![]() | ![]() |
Translate to: |
|||||
Обратная связь | Новости САПР | Программы | Документация | Полезные советы | Обзорные статьи | ||
Заказ и разработка | Каталог САПР | САПР-конференция | Библиотека ГОСТов | Наши соавторы | Коммерческое ПО |
Чтобы показать, как создавать многостраничный DWF-файл, я представлю пользовательскую форму со списком всех шаблонов в текущем чертеже (рис. 1). Здесь пользователь может выбрать, какие из шаблонов будут присутствовать в финальном DWF-файле. Таким образом необходима Userform с ListBox и CommandButton. Заключительная версия кода, которая может быть загружена, будет включать больше материала, но показанная ниже достаточно полно демонстрировать функциональные возможности. Я оставил все имена по умолчанию для средств управления, но вместе с тем я установлю чтобы ListBox мог использовать переключатели и разрешу множественный выбор.
Option Explicit Private Sub UserForm_Initialize() '+--- Startup Dim oLO as AcadLayout For Each oLO In ThisDrawing.Layouts ListBox1.AddItem oLO.Name Next 'setup controls CommandButton1.Caption = "Print" ListBox1.ListStyle = fmListStyleOption ListBox1.MultiSelect = fmMultiSelectMulti Me.Caption = "xPage DWF Print Example" End Sub Private Sub CommandButton1_Click() '+--- user is printing Dim cLO As New Collection Dim iIndex As Integer For iIndex = 0 To Listbox1.ListCount - 1 If ListBox1.Selected(iIndex) = True Then cLO.Add ListBox1.List(iIndex) End If Next 'hide form so code can run Me.Hide 'call to printing MultiDWFPrint cLO 'show form again Me.Show End Sub
Замечание: предпоследняя строка - запрос на печать, который будет описан ниже.
Фоновая информация в DWF-файлеФормат DWF-фйла подобен сжатому Zip-архиву. Если вы дадите DWF-файл расширение .zip, а затем попробуете открыть его используя Winzip, вы увидите серию каталогов и файлов, которые будут содержать струтуры XML-данных, графику в формате PNG и информацию мета-данных.
Файл, который представляет интерес для нас, это DSD-файл (Drawing Set Description), расположеный в папке ePlotGlobal. Этот DSD-файл содержит таблицу содержания, которая сообщает DWF-механизму AutoCAD что необходимо для многостраничного DWF-файла. AutoCAD использует этот файл чтобы обработать необходимые панели шаблонов. Ниже представлен пример DSD-файла:
[DWF6Version] Ver = 1 [DWF6Sheet:1st Layout Name] DWG=C: \Wilhome.dwg Layout = 1st Layout Name [DWF6Sheet:Nth Layout Name] DWG=C:\ Wilhome.dwg Layout = Nth layout Name [Target] Type=1 DWF=C:\Wilhome.dwf PWD=
Обратите внимание, что DSD-файл является не чем иным как Windows INI-файлом, где данные разделены по секциям. Первые две строки должны оставаться неизменными - они указывают версию DWF-файла. последняя строка - опциональная и позволяет установить пароль, если это необходимо. Строки в середине содержат описания шаблонов, включенных в многостраничный DWF-файл. Для каждого шаблона необходима секция с указанием имени шаблона. Следующие две строки - чертежный файл и его шаблон для обработки как части DWF-файла.
Обратите внимание на то, что в DSD-файле может быть ключевых значений, чем показано выше (там показана минимальная структура, необходимая для DSD-файла). Это важно, так как следующим нашим шагом будет создание нашего собственного DSD-файла.
Создание DSD-файлаDSD-файл необходим для создания многостраничного DWF-файла. Будет ли использован существующий DSD-файл или будет создан новый как часть этого проекта должны определить вы сами.
Я буду использовать очень простой код для создания файла и добавил цикл, который будет записывать имя каждого шаблона, который выберет пользователь в ListBox нашей формы. Ниже размещен код, который я использовал:
Private Function CreateDSDFile(cLOs As Collection, _ sDWFFile As String) As Boolean Dim iCntr As Integer 'generic counter Dim sTemp As String 'generic temporary string Dim LogNum As Integer 'reference to file object On Error GoTo Exit_Early 'check to see if DSD file exists and delete it if it does If FileLen(sDWFFile) > 0 Then Kill sDWFFile 'create the new dsd file LogNum = FreeFile 'write to the file Open sDWFFile For Append Access Write Lock Write As #LogNum Print #LogNum, "[DWF6Version]" Print #LogNum, "Ver = 1" 'iterate thru the layouts collection For iCntr = 1 To cLOs.Count 'grab the next layout name in the collection sTemp = cLOs.Item(iCntr) Print #LogNum, "[DWF6Sheet:" & sTemp & "]" Print #LogNum, "DWG=" & m_dwgName Print #LogNum, "Layout = " & sTemp Next Print #LogNum, "[Target]" Print #LogNum, "Type=1" Print #LogNum, "DWF=" & sDWFFile Print #LogNum, "PWD=" Close #LogNum 'send back success CreateDSDFile = True Exit Function Exit_Early: Err.Clear 'send back failure CreateDSDFile = False End Function
Здесь я хотел использовать функцию, которая ожидает коллекцию и строку в качестве параметра. Коллекция будет содержать список имен шаблонов, которые пользователь выберет в диалоговом окне, а строка будет содержать имя DSD-файла. В этом примере, DSD-файл будет расположен в том же самом каталоге как и текущий чертеж и будет иметь то же самое имя, как и чертеж. Функция будет возвращать назад Булево значение, которое будет указывать, было ли успешно создание DSD-файла.
Сохранение DWF-файлаК сожалению, существует только один способ создания DWF-файла из AutoCAD, это использование команды Publish, что однако создает ряд проблем, потому что Publish не доступна через AutoCAD API. Первой проблемой является то, что Publish использует диалоговое окно, которое мы не можем вызвать. Если команда Publish действительно запускает свое диалоговое окно, моя программа остановиться, поскольку я не имею никакого способа связаться с помощью интерфейса с ним.
Чтобы пройти этот этап, я использовал версию Publish для командной строки: _PUBLISH. Чтобы сделать это я должен был полавить отображение файловых диалоговых окон, выключая системную переменную FILEDIA:
ThisDrawing.SetVariable "FILEDIA", 0
Следующей проблемой является вызов команды _PUBLISH. Что бы сделать это, я использовал метод SendCommand. Метод SendCommand должен всегда резервироваться как самая последняя опция потому что он создает целую кучу проблем вашим усилиям по программированию. Так как SendCommand по существу явяется методом принудительного набора команд в командной строке AutoCAD, для программы очень легко потерять фокус так как нет способа определить, когда код SendCommand завершит свою работу. VB/VBA код только передает строку в SendCommand, и продолжает свою работу, что обычно приводит к ошибке, так как код VBA выполняется быстрее, чем команда. Так что, если Вы должны использовать SendCommand, всегда делайте ее самой последней командой в программе.
Следующая проблема, которую я мог иметь происходит из-за имени файла, который я собираюсь генерировать. Если DWF-файл имеет пробелы в имени, SendCommand будет видеть, эти пробелы как Возвраты каретки и разобьет название файла на части, оказывая этим отрицательное воздействие на программу. Чтобы обойти это препятствие, я должен передать имя DWF-файла , в кавычках без VB/VBA интерпретатора, перепутывающего кавычки со строковыми индикаторами VB. Я решил передать LISP-команду в SendCommand, чем я смог связать символьные коды [CHR (*)] с моими реальными строковым переменным и обмануть интерпретатор.
Sub MultiDWFPrint (cLayOuts As Collection) Dim dwgName As String Dim dwfName As String Dim dsdName As String Dim sTxt As String 'grab the drawing variables we need dwgName = ThisDrawing.FullName 'check to make sure we have layouts If cLayOuts.Count > 0 Then 'build the DSD file name dsdFile = Replace(dwgName, ".dwg", ".dsd") 'build the DWF file name dwfFile = Replace(dwgName, ".dwg", ".dwf") 'create the DSD file If CreateDSDFile(cLayOuts, dsdFile) = True Then 'publish our multipage DWF file With ThisDrawing sTxt = Replace(dsdFile, "\", "/") 'turn FILEDIA *OFF* to avoid dialog boxes .SetVariable "FILEDIA", 0 .Regen acActiveViewport 'Publish layouts .SendCommand "(command " & Chr(34) & _ "-PUBLISH" & Chr(34) & _ " " & Chr(34) & sTxt & _ Chr(34) & ")" & vbCr End With Else MsgBox "Error creating DSD file: " & dsdFile GoTo Leave_Now End If Else MsgBox "There are no valid layouts within dwg file" End If Leave_Now: 'clean up before leaving If Not cLayOuts Is Nothing Then Set cLayOuts = Nothing ' End Sub
Обратите внимание, что строка Replace(dsdFile, "\", "/") необходима, так как LISP не будет воспринимать слеш как символ, и его необходимо заменить на обратный слеш. Это необходимо для LISP.
Обернемся назадТеперь остается только одна проблема. Если программа успешна, моя сессия AutoCAD теперь имеет заблокированную поддержку файлового диалога! Помните, как я сказал, что, если Вы используете SendCommand, это должно быть самая последняя команда? В примере пока, это - предпоследняя команда, и Вы можете видеть как SendCommand все еще выполняется позади кода VBA, потому что Userform вновь появляется перед тем как команда _PUBLISH закончит свою работу. Я мог забыть, что я думал об этой проблеме и только ждать жалоб конечных пользователей, или я могу добавьте код к форме, чтобы закрыть событие, устанавливая FILEDIA назад в 1:
Private Sub UserForm_Terminate() ThisDrawing.SetVariable "FILEDIA", 1 End Sub
А если я создам приложение, которое не содержит форму? Как будет я возвращать FILEDIA назад если это имеет место? Хорошо, мы имеем множество уникальных способов обработать этот сценарий, и я оставлю Вам исследовать их. Например, можно добавить цикл, который читает переменную USER:
Dim sTest As String Do Until sTest = "DONE" sTest = ThisDrawing.GetVariable("USERS2") Loop
В этом сценарии, значение переменной USERS2 могло быть установлено через код, который добавляют к такому событию как EndCommand или EndPlot. Вы сами можете придумать, что нужно сделать чтобы решить эту проблему.
Copyright © Сайт поддержки пользователей САПР by Victor Tkachenko