Логотип сайта поддержки пользователей САПРО сайте поддержки пользователей САПР Translate to:

Глава из книги "AutoCAD 2002"
Н.Н. Полещука.
На домашнюю страницу автора

Visual LISP и COM

Фирма Microsoft разработала модель COM (Component Object Model - модель компонентных объектов), позволяющую связывать самые разнородные приложения. Построенный по спецификации этой модели программный комплекс предоставляет описание своих компонент и средств доступа к ним другим программам. Это дает возможность проектировать такие системы, в которых одни приложения (приложения-клиенты) обращаются к другим приложениям (приложениям-серверам) для вы-полнения некоторых операций, специфичных для приложений-серверов. При этом приложение-сервер может запускаться в видимом режиме (когда для него открывается свое окно) и в невидимом (приложение работает в оперативной памяти, не открывая своего окна).

Приложения, поддерживающие технологию COM, при установке заносят в реестр Windows информацию о себе, о своих компонентах, объектах. Так, например, имя приложения (ProgID), под которым оно может быть вызвано как приложение-сервер, заносится в реестр в раздел HKEY_CLASSES_ROOT. На рис. 1 в окне редактора реестра видно, что последняя версия AutoCAD зарегистрирована, как "AutoCAD.Application.15". Под таким именем нужно вызывать (создавать) объект приложения AutoCAD, если обращаться к нему из другой программы.



Рис. 1. Окно редактора реестра Windows (строка, связанная с AutoCAD)

В реестре также находится информация о том, как можно обратиться к нужному объекту (для этого есть специальные интерфейсы), какие методы к нему применимы.

В данном разделе рассматриваются два примера использования COM. В первом из них система AutoCAD читает таблицу, созданную в СУБД FoxPro, во втором - таблицу Microsoft Excel. Эти два примера также являются демонстрацией одного из способов работы с базами данных из сеанса AutoCAD.

Чтение базы Visual FoxPro 6

Перед тем, как рассмотреть программу, работающую с базой, созданной с помощью FoxPro, проверим, под каким именем нужно обратиться к FoxPro, как к приложению-серверу. Запустим программу редактора реестра (как правило, она имеет имя regedit.exe и находится в папке Windows). Открыв окно редактора реестра (см. рис. 2), выполнив операцию поиска по признаку (например, "visual.foxpro") и повторив ее некоторое количество раз, узнаем, что к Visual FoxPro как к приложению нужно обращаться с помощью строки "Visual.FoxPro.Application.6" (верхний регистр с этой строке в дальнейшем необязателен).



Рис. 2. Окно редактора реестра Windows (строка, связанная с Visual FoxPro)
Замечание

Можно обращаться к Visual FoxPro и с помощью строки "Visual.FoxPro.Application", поскольку в разделе HKEY_CLASSES_ROOT\Visual.FoxPro\CurVer указано, какая версия FoxPro на данном компьютере является текущей.

Нужную нам информацию можно найти также в разделе HKEY_CLASSES_ROOT\CLSID.

Выясним теперь, какие методы применимы к приложению Visual FoxPro как к объек-ту, а также какими он обладает свойствами. Среди функций Visual LISP, реализую-щих технологию ActiveX, есть две, которые нам в этом помогут: vlax-get-or-create-object и vlax-dump-object. Первая создаст указатель объекта приложения Visual FoxPro, а вторая - выведет в тестовый экран перечень его свойств и методов. Выполним в командной строке AutoCAD следующее LISP-выражение:

(vlax-dump-object (vlax-get-or-create-object "Visual.FoxPro.Application.6") T)

В результате этой операции получим список методов: DataToClip (3), DoCmd (1), Eval (1), Help (3), Quit () , RequestData (2), SetVar (2), а также список свойств приложения. В скобках дано максимальное количество аргументов, которое можно задать при обращении к методу.

Теперь рассмотрим пример, который приведен в листинге 1. В этом примере работа выполнялась над базой sample.dbf, которая открыта в режиме просмотра на рис. 3, и ее копией.



Рис. 3. Окно просмотра базы sample.dbf

Листинг 1. Чтение базы FoxPro с применением COM

; Программы для обеспечения COM-связи AutoCAD - Microsoft Visual FoxPro
; А.А.Кузнецов, 2002
;
; Тестовый пример
(defun fox_com1 ( / dbname dbtemp db_dbf db_alias
                    ofp one_sql table_list sql_list)
; Имена баз (с внешними кавычками, т.к. пути могут содержать пробелы)
  (setq dbname "\"d:\\r 15\\sample\""
        dbtemp "\"d:\\r 15\\tmp\\acad_test\"")
  (setq db_dbf (strcat (vl-string-trim "\"" dbtemp) ".dbf"))
  (setq db_alias (vl-filename-base db_dbf))
; --- 1 ---
; Установление связи c FoxPro
  (setq ofp (fp_set_connect))
; --- 2 ---
; Удаление временной базы (с расширением dbf), если она уже существует,
; чтобы не выводился лишний запрос FoxPro на перезапись файла
  (if (findfile db_dbf) (vl-file-delete db_dbf))
; Выполним команду SELECT
; --- 3 ---
  (setq table_list (list dbname))
  (setq one_sql (strcat "SELECT * FROM " dbname " INTO TABLE " dbtemp))
; --- 4 ---
  (setq kol_rec (fp_exec_sеlect ofp table_list one_sql nil))
  (alert (strcat "Всего выбрано записей - " (rtos kol_rec 2 0)))
; --- 5 ---
; Закроем базу
  (fp_close_one_dbf ofp db_alias)
; Откроем базу и выполним команду UPDATE
  (setq table_list (list dbtemp))
  (setq sql_list
    (list (strcat "UPDATE " dbtemp " SET Dbf_name = 'bb' ")))
; --- 6 ---
  (fp_exec_sql_list ofp table_list sql_list nil)
; --- 7 ---
; Установим в качестве текущей запись с номером 5
  (fp_set_record ofp db_alias 5)
; Прочитаем поле "Field_desc";   ПУТЬ К КАТАЛОГУ ПРОЕКТА
  (alert (fp_field_value ofp db_alias "Field_desc"))
; Разорвём связь c FoxPro
; --- 8 ---
  (fp_break_connect ofp )
  (princ)
)

;---------------------------------------------
; Установить связь с FoxPro 6.0
; Возвращаемое значение - VLA-объект приложения
(defun fp_set_connect ( / o)
  (vl-load-com) 
  (setq o (vlax-get-or-create-object "VisualFoxPro.Application.6"))
; Если связь не установлена, то аварийно завершить работу
  (if (null o)
    (progn
      (alert "Нельзя запустить FoxPro")
      (exit)
    )
  );if
; Можно сделать FoxPro видимым:
;;;  (vlax-put-property o "Visible" :vlax-true)
;
; Возвращаемое значение
  o
)
;---------------------------------------------
; Разорвать связь с FoxPro 6.0
(defun fp_break_connect (o / )
  (vlax-invoke-method o "Quit")(vlax-release-object o)
)
;---------------------------------------------
; Открытие dbf-файла в среде FoxPro
; one_dbf - имя dbf-файла с путём
(defun fp_open_one_dbf (o one_dbf / command_fox)
  (setq command_fox (strcat "USE " one_dbf " IN 0 SHARED"))
  (vlax-invoke-method o "DoCmd" command_fox)
)

;---------------------------------------------
; Закрытие dbf-файла в среде FoxPro
(defun fp_close_one_dbf (o alias / command_fox)
  (setq command_fox (strcat "USE IN " alias))
  (vlax-invoke-method o "DoCmd" command_fox)
)

;---------------------------------------------
; Исполнение списка SQL-команд (DELETE, UPDATE, ...) в среде FoxPro
; с закрытием таблиц (close_table=T) или без закрытия (close_table=nil)
(defun fp_exec_sql_list (o tablist slist close_table / )
; Откроем таблицы
  (foreach one_dbf tablist (fp_open_one_dbf o one_dbf))
; Выполним команды в списке
  (foreach 1sql slist (vlax-invoke-method o "DoCmd" 1sql))
  (if close_table
     (foreach one_dbf tablist (fp_close_one_dbf o one_dbf))
  )
)
;---------------------------------------------
; Исполнение одной команды SELECT в среде FoxPro
; возврат - число записей результата, с закрытием
; таблиц или без (по close_table)
(defun fp_exec_sеlect (o tablist 1sql close_table / kol_rec)
  (foreach one_dbf tablist (fp_open_one_dbf o one_dbf))
  (vlax-invoke-method o "DoCmd" 1sql)
; Читаем значение системной переменной _TALLY,
; содержащей количество записей в базе
  (setq kol_rec
    (vlax-variant-value (vlax-invoke-method o "Eval" "_TALLY")))
  (if close_table
    (foreach one_dbf tablist (fp_close_one_dbf o one_dbf))
  )
   kol_rec
)
;-------------------------------------------
; Установить текущую запись открытой таблицы
(defun fp_set_record (o alias nrecord / command_fox)
  (setq command_fox (strcat "GO " (itoa nrecord) " IN " alias))
  (vlax-invoke-method o "DoCmd" command_fox)
)
;-------------------------------------------
; Получить значение поля текущей записи открытой таблицы
(defun fp_field_value (o alias field_name / command_fox)
  (setq command_fox (strcat alias "." field_name))
  (vlax-variant-value (vlax-invoke-method o "Eval" command_fox))
)

Данная программа демонстрирует различные операции, выполняемые с привлечением FoxPro. Файл, приведенный в листинге, содержит тексты программ, выполняющих следующие действия:

Опишем схему работы приложения fox_com1. В качестве базы, с которой выполняется работа, выбран файл sample.dbf (см. рис. 3), расположенный в папке d:\r 15 (имя папки содержит пробел). В качестве копии базы, в которую будет переписано содержимое базы sample.dbf, выбран образующийся в папке d:\r 15\tmp файл acad_test.dbf. Обращаю внимание, что подпапка tmp должна быть заранее создана, иначе наше приложение аварийно завершится.

  1. С помощью программы fp_set_connect устанавливается связь с Visual FoxPro (в случае невозможности такой связи - например, если на компьютере не инсталлирован пакет Microsoft Visual FoxPro 6 - приложение принудительно завершается с помощью функции exit) и в переменную ofp заносится указатель связи (он является VLA-объектом). FoxPro запускается в невидимом режиме (иначе надо раскомментировать строку с изменением свойства Visible в программе fp_set_connect).
  2. Из папки d:\r 15\tmp удаляется экземпляр файла acad_test.dbf (иначе из FoxPro будет дополнительный вопрос о перезаписи, который нужно специально обрабатывать).
  3. В переменную table_list заносится список баз (у нас в списке одна база), а в переменную one_sql - строку с командой SELECT и ее параметрами.
  4. С помощью программы fp_exec_select выполняется копирование основной базы в файл acad_test.dbf (работает строка one_sql с командой SELECT) и в переменную kol_rec заносится количество записей (при этом использовано то обстоятельство, что в FoxPro системная переменная _TALLY в текущий момент содержит как раз количество записей всей базы). Результат отображается в окне с помощью функции alert (см. рис. 4).
  5. С помощью функции fp_close_one_dbf основная база закрывается. В переменной table_list формируется список с именами новых баз (у нас - это одна база acad_test.dbf), а в переменной sql_list - список строк с командами FoxPro (у нас - одна строка с командой UPDATE и ее параметрами).
  6. С помощью функции fp_exec_sql_list открывается вспомогательная база acad_test и выполняется список с командами (у нас - это одна строка с командой UPDATE, которая изменяет значение поля Dbf_name всех записей на bb).
  7. С помощью функции fp_set_record текущей устанавливается запись с номером 5, а с помощью функции fp_field_value - читается значение поля Field_desc этой записи. Результат (строка с текстом "ПУТЬ К КАТАЛОГУ ПРОЕКТА") отображается в окне с сообщением, выводимом функцией alert (см. рис. 5).
  8. С помощью функции fp_break_connection связь с FoxPro разрывается.


Рис. 4. Окно с сообщением о количестве записей




Рис. 5. Окно с сообщением, содержащим значение поля Field_desc

Для выполнения команд FoxPro приложение fox_com1 применяло функцию vlax-invoke-method, у которой первым аргументом был VLA-объект FoxPro, вторым была строка "DoCmd", а третьим - строка с командой и параметрами. Это соответствовало применению метода DoCmd к объекту приложения FoxPro.

Для надежности работы аналогичной программы автор должен тщательно анализи-ровать результаты, возвращаемые выражениями, применяющими методы, поскольку непредусмотренные сбойные ситуации могут вызывать зависание системы AutoCAD.

Построение таблицы спецификации с импортом данных из файла Excel 2000

Довольно часто проходится в рисунке AutoCAD создавать таблицу (например, спецификации), данные для которой находятся в файле Excel. Пример решения этой задачи приводится в настоящем разделе. Можно было бы такую таблицу получить вставкой OLE-объекта, но это не всегда удобно.

Как и в предыдущем разделе, узнаем с помощью реестра, под каким именем нужно в COM-технологии обращаться к приложению Microsoft Excel 2000. В результате получим строку "Excel.Application.9" (можно пользоваться и укороченной строкой "Excel.Application" - в этом случае операционная система сама определяет, какая версия Excel является последней на данном компьютере, а программист должен учитывать возможность вызова не той версии, на которую он рассчитывал).

С помощью функции vlax-dump-object прочитаем список методов, которые можно применять к объекту приложения Excel, и максимально допустимое количество аргументов этих методов: ActivateMicrosoftApp (1), AddChartAutoFormat (3), AddCustomList (2), Calculate (), CalculateFull (), CentimetersToPoints (1), CheckSpelling (3), ConvertFormula (5), DDEExecute (2), DDEInitiate (2), DDEPoke (3), DDERe-quest (2), DDETerminate (1), DeleteChartAutoFormat (1), DeleteCustomList (1), Dou-bleClick (), Evaluate (1), ExecuteExcel4Macro (1), FindFile (), GetCustomListContents (1), GetCustomListNum (1), GetOpenFilename (5), GetPhonetic (1), GetSaveAsFilename (5), Goto (2), Help (2), InchesToPoints (1), InputBox (8), Intersect (30), MacroOptions (10), MailLogoff (), MailLogon (3), NextLetter (), OnKey (2), OnRepeat (2), OnTime (4), OnUndo (2), Quit (), RecordMacro (2), RegisterXLL (1), Repeat (), Run (31), SaveWorkspace (1), SendKeys (2), SetDefaultChart (2), Undo (), Union (30), Vola-tile (1), Wait (1), _Evaluate (1), _Run2 (31). Одновременно получим и названия свойств (в этот список включены и дочерние семейства), которые нам будут нужны в первую очередь: ActiveCell, ActiveChart, ActivePrinter, ActiveSheet, ActiveWindow, ActiveWorkbook, AddIns, AlertBeforeOverwriting, AltStartupPath, AnswerWizard, Application, AskToUpdateLinks, Assistant, AutoCorrect, AutoPercentEntry, Build, CalculateBeforeSave, Calculation, Cal-culationVersion, Caller, CanPlaySounds, CanRecordSounds, Caption, CellDragAndDrop, Cells, Charts, ClipboardFormats, Columns, COMAddIns, CommandBars, CommandUnderlines, ConstrainNumeric, ControlCharacters, CopyObjectsWithCells, Creator, Cursor, CursorMovement, CustomListCount, CutCopyMode, DataEntryMode, DDEAppReturnCode, DefaultFilePath, DefaultSaveFormat, DefaultSheetDirection, DefaultWebOptions, Dialogs, DisplayAlerts, DisplayClipboardWindow, DisplayCommentIndicator, DisplayExcel4Menus, DisplayFormulaBar, DisplayFullScreen, DisplayNoteIndicator, DisplayRecentFiles, DisplayScrollBars, DisplayStatusBar, EditDirectlyInCell, EnableAnimations, EnableAutoComplete, EnableCancelKey, EnableEvents, EnableSound, Excel4IntlMacroSheets, Excel4MacroSheets, ExtendList, FeatureInstall, FileConverters, FileFind, FileSearch, FixedDecimal, FixedDecimalPlaces, Height, IgnoreRemoteRequests, Interactive, International, Itera-tion, LanguageSettings, Left, LibraryPath, MailSession, MailSystem, MathCoprocessorAvailable, MaxChange, MaxIterations, MemoryFree, MemoryTotal, MemoryUsed, MouseAvailable, MoveAfterReturn, MoveAfterReturnDirection, Name, Names, NetworkTemplatesPath, ODBCErrors, ODBCTimeout, OLEDBErrors, OnWindow, OperatingSystem, OrganizationName, Parent, Path, PathSeparator, PivotTableSelection, PreviousSelections, ProductCode, PromptForSummaryInfo, Range, RecentFiles, RecordRelative, ReferenceStyle, RegisteredFunctions, RollZoom, Rows, ScreenUpdating, Selection, Sheets, SheetsInNewWorkbook, ShowChartTipNames, ShowChartTipValues, ShowToolTips, ShowWindowsInTaskbar, StandardFont, StandardFontSize, StartupPath, StatusBar, TemplatesPath, ThisWorkbook, Top, TransitionMenuKey, TransitionMenuKeyAction, TransitionNavigKeys, UsableHeight, UsableWidth, UserControl, UserLibraryPath, UserName, Value, VBE, Version, Visible, Width, Windows, Win-dowsForPens, WindowState, Workbooks, WorksheetFunction, Worksheets, _Default.

Предположим, что данные для таблицы спецификации, которую нам нужно начертить в рисунке AutoCAD, раполагаются в листе Спецификация книги (файла) d:\r 15\sampex.xls (см. рис. 6).



Рис. 6. Окно просмотра листа книги sampex.xls

На рисунке видно, что в нашем файле четыре листа (помимо листа Спецификация есть еще листы Примитивы, Расходы, Материалы), поэтому программа должна не только открыть книгу Excel, но еще и обратиться к нужному листу.

В листе Спецификация для облегчения программирования введены дополнительные данные, которые уточняют характеристики будущей таблицы деталей, создаваемой в AutoCAD.

В первой строке в ячейке A1 дано количество деталей (т. е. строк таблицы без учета заголовка - 6), а в ячейке B1 - количество столбцов таблицы (5). Вторая строка листа Спецификация - это размеры столбцов по ширине в мм (10, 70, 25, 35 и 25). Третья строка уточняет тип данных, которые располагаются в соответствующем столбце (int - целое, real - вещественное, str - текст). При выводе вещественных чисел будем давать по одной цифре после десятичной точки.

Четвертая строка - это названия колонок таблицы (Позиция, Наименование, Толщина, Материал, Количество).

Будем придерживаться следующих параметров таблицы: высота строк должна равняться 8 мм, а высота букв в стиле текста - 5 мм. В каждой ячейке текст должен быть выровнен влево и должен располагаться с отступом 1 мм от левой, нижней и правой границ, а если текст будет длинным, то тогда его нужно вписывать в соответствующую ячейку с помощью опции Fit (По ширине) команды TEXT (ТЕКСТ).

В листинге 2 приведен текст программы exc_com1 и ее подпрограмм.

Листинг 2. Чтение файла Excel с применением COM и построение таблицы в AutoCAD
; Программы COM-связи AutoCAD - Microsoft Excel 2000
; Н.Н.Полещук, 2002
;
; Пример вычерчивания таблицы по данным из листа книги Excel
; Используются текущий слой, текущий цвет и текущий текстовый стиль
; В текущем текстовом стиле высота букв должна быть задана нулем
; (тогда команда TEXT запрашивает высоту букв надписи)
(defun exc_com1 ( / tb_xls hcell hlet oex wkbs awb shs mainsh cell
  nlines ncolumns table_items i j row pt0 widths types headers xx1 xx2 
  yy1 ww val)
; Имя файла Excel и нужного листа
(setq tb_xls "d:\\r 15\\sampex.xls" sheetname "Спецификация")
; Высота ячеек рисуемой таблицы и высота букв
(setq hcell 8.0 hlet 5.0)
;
; Установить связь c Excel
(vl-load-com) 
(setq oex (ex_set_connect))
; Получить указатель семейства Workbooks
(setq wkbs (vlax-get-property oex "Workbooks"))
; Открыть файл (книгу) и получить указатель книги
(setq awb (vlax-invoke-method wkbs "Open" tb_xls))
(if (not awb)
  (progn (alert (strcat "Не обнаружен файл " tb_xls))(exit)))
; Прочитать список листов 
(setq shs (vlax-get-property awb "Worksheets"))
; Получить указатель на лист с нужным именем  
(vlax-for s shs
  (if (= sheetname (vlax-get-property s "Name"))(setq mainsh s)))
; Если нужный лист не обнаружен, то завершить работу
(if (not mainsh)
  (progn (alert (strcat "Не обнаружен лист " sheetname))(exit)))
;
; Читаем из ячейки A1 файла Excel количество строк в будущей таблице
;  спецификации, без учета строки заголовков
(setq cell
  (vlax-variant-value (vlax-invoke-method mainsh "Evaluate" "A1")))
(setq nlines
  (fix (vlax-variant-value (vlax-get-property cell "Value"))))
; Читаем количество столбцов в будущей таблице спецификации
;  (из ячейки B1 файла Excel)
(setq cell
  (vlax-variant-value (vlax-invoke-method mainsh "Evaluate" "B1")))
(setq ncolumns
  (fix (vlax-variant-value (vlax-get-property cell "Value"))))
;
; Получить список элементов таблицы (строки 2,3,4, ... Excel)
; Строка 2 - ширины столбцов в мм
; Строка 3 - заголовки столбцов
(setq table_items nil j 1)
(repeat (+ nlines 3)
  (setq row nil j (1+ j) i -1)
  (repeat ncolumns
    (setq i (1+ i))
    (setq cell
      (vlax-variant-value
        (vlax-invoke-method
          mainsh
          "Evaluate"
          (strcat (chr (+ i (ascii "A"))) (itoa j))
        )
      )
    )
    (setq row
      (append
        row
        (list
          (vlax-variant-value
            (vlax-get-property cell "Value")
          )
        )
      )
    )
  );repeat ncolumns
  (setq table_items (append table_items (list row)))
);repeat nlines
;
; Закрыть книгу Excel
(ex_break_connect oex)
;
; Запрос точки левого верхнего угла таблицы
(setq pt0 nil)
(while (null pt0)
  (setq pt0 (getpoint "\nТочка левого верхнего угла таблицы: "))
);while
;
(setq widths (nth 0 table_items) types (nth 1 table_items))
;
; Нарисовать сетку (высота ячеек 8 мм)
(tab_lines pt0 ncolumns nlines widths hcell)
;
; Заголовки столбцов таблицы
(setq headers (nth 2 table_items) i -1
  xx1 (car pt0) yy1 (- (cadr pt0) hcell))
(repeat ncolumns
  (setq i (1+ i) ww (nth i widths) xx2 (+ xx1 ww))
  (setq val (nth i headers))
  (write_item val "str" xx1 xx2 yy1 hlet)
  (setq xx1 xx2)
);
;
; Заполнить таблицу
(setq j 2)
(repeat nlines
  (setq j (1+ j) i -1
    xx1 (car pt0) yy1 (- (cadr pt0) (* (1- j) hcell)))
  (repeat ncolumns
    (setq i (1+ i) ww (nth i widths) xx2 (+ xx1 ww))
    (setq val (nth i (nth j table_items)))
    (setq itype (nth i types))
    (write_item val itype xx1 xx2 yy1 hlet)
    (setq xx1 xx2)
  );repeat ncolumns
);repeat nlines
;
(redraw)
(princ)
)
;-------------- Подпрограммы -----------------
; Установить связь с Excel 2000
; Возвращаемое значение - VLA-объект приложения
(defun ex_set_connect ( / e)
  (setq e (vlax-get-or-create-object "Excel.Application.9"))
; Если связь не установлена, то аварийно завершить работу
  (if (null e)
    (progn
      (alert "Нельзя запустить Microsoft Excel")
      (exit)
    )
  );if
; Можно сделать Excel видимым:
;;; (vlax-put-property e "Visible" :vlax-true)
;
; Возвращаемое значение
  e
)
;---------------------------------------------
; Разорвать связь с Excel
(defun ex_break_connect (e / )
  (vlax-invoke-method e "Quit")(vlax-release-object e)
)
;-----------------------------------------------------------
; Вычерчивание элемента таблицы, с отступом от границ ячейки
(defun write_item (item typ x1 x2 yi hl / gapx gapy wi yig st size sizex)
; Аргументы:
; item  - элемент
; typ   - тип ("int", "str", ...)
; x1,x2 - граничные абсциссы ячейки таблицы, в которую нужно внести текст
; yi    - ордината нижней границы ячейки
; hl    - высота букв надписи
; Рабочие переменные:
; wi    - ширина ячейки
; gapx - отступ по X от левой и правой границ ячейки
; gapy - отступ по Y от нижней границы ячейки
  (setq gapx 1.0 gapy 1.0 wi (- x2 x1) yig (+ yi gapy))
  (if item
    (progn
;
; Преобразование значения item в текст, в зависимости от формата
; Значения типа "int" нужно обрабатывать без дробной части
      (setq st
        (if (= typ "int")
          (itoa (fix item))
          (vl-princ-to-string item)
        )
      )
;
; Вычислить размер текста (sizex - размер по горизонтали)
      (setq size (textbox (list (cons 1 st) (cons 40 hl))))
      (setq sizex (- (caadr size) (caar size)))
; Если текст помещается в ячейке, то вписываем его
;  с выравниванием по левой нижней точке
; Если текст не помещается, то вписываем его с опцией Fit (По ширине)
      (if (<= sizex (- wi (+ gapx gapx)))
        (command "_.TEXT" (list (+ x1 gapx) yig) hl 0.0 st)
        (command "_.TEXT" "_F"
          (list (+ x1 gapx) yig) (list (- xx2 gapx) yig)
          hl st
        )
      );if
    );progn
  );if item
);
;--------------------------------------
; Вычерчивание линий таблицы
(defun tab_lines (p0 nc nl wids h / w k xx yy htab)
; p0  - точка верхнего левого угла таблицы
; nc   - количество столбцов
; nl   - количество строк
; wids - список ширин столбцов
; h    - высота строк
;
; Вычисление w - полной ширины таблицы
  (setq w 0.0 k -1)
  (repeat nc (setq k (1+ k) w (+ w (nth k wids))))
;
; Горизонтальные отрезки
  (setq xx (car p0) yy (cadr p0))
  (repeat (+ nl 2)
    (command "_.LINE" (list xx yy) (list (+ xx w) yy) "")
    (setq yy (- yy h))
  );repeat
;
; Вертикальные отрезки
  (setq xx (car p0) yy (cadr p0) htab (* h (1+ nl)) k -1)
  (command "_.LINE" (list xx yy) (list xx (- yy htab)) "")
  (repeat nc
    (setq k (1+ k) xx (+ xx (nth k wids)))
    (command "_.LINE" (list xx yy) (list xx (- yy htab)) "")
  );repeat
);defun

Результат работы программы exc_com1 приведен на рис. 7.



Рис. 7. Таблица, построенная по листу Спецификация книги sampex.xls

Дадим некоторые пояснения к работе программы.

После установки связи с Microsoft Excel 9 программа получает последовательно объекты: oex (указатель объекта самого приложения Excel), wkbs (указатель семейства Workbooks), awb (указатель активной книги после открытия в Excel файла sampex.xls), shs (указатель семейства листов), mainsh (указатель листа Спецификация).

Затем с помощью метода Evaluate читаются значения, записанные в листе Спецификация в ячейках A1 (nlines - количество строк или деталей) и B1 (ncolumns - количество столбцов в будущей таблице). Поскольку метод Evaluate возвращает значение типа VARIANT, то для сохранения его в виде обычного целого числа применяется преобразование типа с помощью функции vlax-variant-value.

Далее, применяя тот же метод Evaluate, сканируем строки 2-10 листа Спецификация и получаем список table_items, в котором девять элементов, каждый из которых является списком, состоящим из пяти значений: ((10.0 70.0 25.0 35.0 25.0) ("int" "str" "real" "str" "int") ("Позиция" "Наименование" "Толщина" "Материал" "Количество") (1.0 "Планка" 4.5 "A" 2.0) (3.0 "Бракета" 10.0 "C" 1.0) (4.0 "Кница" 8.0 "A" 3.0) (8.0 "Планка" 6.0 "B" 2.0) (14.0 "Лист" 18.0 "A" 4.0) (16.0 "Кница" 6.0 "B" 1.0)).

Первый элемент списка table_items (ширины столбцов) сохраняется для удобства в переменной widths, второй (типы значений по столбцам) - в переменной types, а третий (заголовки столбцов) - в переменной headers.

Из списка видно, что все значения, являющиеся как вещественными, так и целыми числами, представлены в вещественном виде. Поэтому при вписывании их в таблицу нужно будет пользоваться типами ("int" или "real").

После формирования table_items программа закрывает соединение с Excel и интерактивно запрашивает точку p0, которая будет точкой верхнего левого угла таблицы спецификации деталей. Цикл, организованный с помощью функции while, исключает возможностью пустого ввода нажатием на клавишу <Enter> (это можно было сделать и применением функции initget).

Подпрограмма tab_lines рисует отрезки, формирующие строки и столбцы с ячейками таблицы. В качестве четвертого и пятого аргументов этой функции передаются ширины столбцов и высота строк.

Подпрограмма write_item осуществляет заполнение разлинованной таблицы значениями из списка table_items. Для построения надписи используется команда TEXT (ТЕКСТ), которая при вызове ее внутри функции command не работает в цикле (т. е. после первой надписи не требует текст второй надписи и т. д., как это было бы при вызове команды через командную строку).

Перед обращением к команде TEXT (ТЕКСТ) программа с помощью функции textbox выясняет размеры будущей текстовой надписи, если использовать в качестве способа выравнивания привязку к левому нижнему углу надписи. Если ширина надписи (sizex) оказывается больше допустимого (т. е. надпись не поместится в ячейке, с учетом отступов gapx и gapy), то текст надписи выводится командой TEXT (ТЕКСТ) с опцией Fit (По ширине).

Все элементы таблицы перед выводом преобразуются подпрограммой write_item к текстовому виду, при этом используется тип значения, который передается через аргумент typ. Именно здесь числа, которые должны быть целыми, преобразуются к целому типу, а в вещественных сохраняется только один знак после десятичной точки.

Приведенная в листинге 2 программа удобна тем, что в самом файле Excel можно задать такие настройки таблицы, как количество и тип элементов, ширины столбцов. Ряд других настроек хранятся в таких переменных, как tb_xls, hcell, hlet, gapx и т. п. Читатель может на основе этого текста создать для себя более удобный вариант. Опытный программист может добавить к этой программе более тщательный разбор значений, занесенных предварительно в книгу Excel, поскольку при больших объемах данных обязательно возникают ошибки, которые надо обрабатывать.



Copyright © Сайт поддержки пользователей САПР by Victor Tkachenko