Как часто в горестной разлуке,
В моей блуждающей судьбе,
Комплект КД, я думал о тебе!
Итак, в предыдущей статье я остановился на автоматизации отдельного документа и пообещал рассказать о том, как удалось организовать работу с комплектом разнородных документов при помощи вспомогательной базы Excel и как оказалось возможным делать комплекты документов вообще не открывая Word.
Под комплектом я здесь понимаю набор файлов форматов Word, Visio и AutoCAD, относящихся к одному общему проекту или изделию. То есть те файлы, которые представляют документы с одинаковыми, взаимно синхронизируемыми текстовыми полями. Далее, я буду называть этот комплект - автоматизированным комплектом документов или АКД.
Давайте посмотрим, как выглядит АКД в проводнике Windows.
Обратите внимание на файл variables.xls. Именно здесь располагаются все переменные, которые мы хотим централизованно распределять по нашему комплекту. В этом файле, при работе макросов VBA Word, Visio, AutoCad - автоматически создаются страницы, соответствующие этим файлам и содержащим все специфические переменные этих файлов.
Есть два нюанса. Первый - страница "All". Она понадобилась для того, чтобы сохранять переменные, которые одинаковы для ВСЕХ без исключения документов АКД. Например, для переменной vObj - Объект проектирования = Зал славы. :)) Второй нюанс - для документов Visio вкладка создается для каждой страницы документа, так как обычно достаточно удобно держать все схемы проекта в одном файле. В принципе, никто не мешает разнести эти схемы и по разным файлам, но в Excel попадут все равно названия страниц этих документов. Ну и дополнительно, чисто для эстетики, цвета вкладок-листов Excel соответствуют типам файлов. Например, синие - это Word.
Так как в предыдущей статье я уже рассказал о принципе формирования и обработки полей-переменных, то сейчас расскажу только о дополнительных вещах, относящихся к работе с файлом переменных. На следующем рисунке показана связь переменных, которые мы создаем с файлом variables.xls. Имя файла может быть любым и оно задается в основном окне макроса - в нижнем белом поле.
Методом проб и ошибок я пришел к такой организации работы со своим "детищем":
Создается новый файл. Как правило, уже на основе имеющегося шаблона.
В окне макроса нажимается кнопка "Сохранить". При этом в фале переменных автоматически создается новая вкладка для этого файла и на нее заносятся имеющиеся в документе переменные. Если эти переменные уже есть на вкладке "All" - то они не вносятся на персональную вкладку документа.
После сохранения, все "персональные" переменные документа отображаются и редактируются на вкладке окна макроса "Локальные". Общие переменные АКД - отображаются на вкладке "Общие". (Кстати, там они не редактируются, а только отображаются, во избежание ошибочных изменений, которые затронут весь комплект)
Если я хочу сделать какие-то из переменных документа - общими, то я просто потом перехожу в файл Excel и перетаскиваю их строки с листа документа на лист "All". А если я хочу переопределить общую переменную персонально для конкретного файла, например, если везде разработчик один и тот же, но в единственном документе он другой то я копирую строку с листа "All" на персональную вкладку этого самого "особенного" документа.
Такое повторяется для каждого документа комплекта (если комплект создается "с нуля". Если комплект типовой - то вообще ничего делать не надо, только в Excel или в окне макроса переменные менять.)
Ниже приведу, для примера, код функции, которая обеспечивает занесение переменных документа в файл.
Код функции записи переменных и дисклаймер
На всякий случай, сообщаю - я не профессиональный программист. Поэтому представленный код не является образцом для подражания и периодически балует меня окнами ошибок. Однако, моя идеология программирования заключается в том, чтобы не делать код таким, чтобы он вносил непоправимые ошибки в документы. Соответственно, по мере возникновения ошибок, я просто вношу соответствующие правки в код и работаю дальше.
Sub xlAddVars(ExcelFile As String)
Dim xlWSh, xlWShAll As Object
Dim xlWbk As Object
Dim xlApp As Object
Dim Checked As Boolean
Dim FileEx As Boolean
Dim AllLastRow, LastRow
Dim SheetName As String
SheetName = ""
On Error Resume Next
SheetName = ActiveDocument.Name
On Error GoTo openexcel
Set xlApp = GetObject(, "excel.application")
Checked = False
For a = 1 To xlApp.Workbooks.Count
If xlApp.Workbooks(a).Name = ExcelFile Then Checked = True: Set xlWbk = xlApp.Workbooks(ExcelFile): Exit For
Next
If Not Checked Then
On Error GoTo CreateFile
FileEx = FileDateTime(ActiveDocument.Path + "" + ExcelFile)
On Error GoTo 0
If FileEx Then Set xlWbk = xlApp.Workbooks.Open(ActiveDocument.Path + "\" + ExcelFile)
End If
Found = False
For a = 1 To xlWbk.sheets.Count
If xlWbk.sheets(a).Name = SheetName Then Found = True
Next
If Not Found Then
Set xlWbs = xlWbk.sheets.Add(After:=xlApp.Worksheets(xlApp.Worksheets.Count))
xlWbs.Name = SheetName
xlWbs.Tab.ColorIndex = 37
End If
Set xlWSh = xlApp.ActiveWorkbook.Worksheets(SheetName)
Set xlWShAll = xlApp.ActiveWorkbook.Worksheets("All")
'Calculate last used rows in sheets
AllLastRow = xlWShAll.Cells(1, 1).End(-4121).Row
If AllLastRow >= 65536 Then
If xlWShAll.Cells(1, 1).Value = Empty Then AllLastRow = 0 Else AllLastRow = 1
End If
LastRow = xlWSh.Cells(1, 1).End(-4121).Row
If LastRow >= 65536 Then
If xlWSh.Cells(1, 1).Value = Empty Then LastRow = 0 Else LastRow = 1
End If
'Запись кол-ва листов
ActiveDocument.Variables("vPages").Value = ActiveDocument.BuiltInDocumentProperties(wdPropertyPages)
For b = 1 To ActiveDocument.Variables.Count
Checked = False
'Search in All sheet
For a = 1 To AllLastRow
If xlWShAll.Cells(a, 1).Value = ActiveDocument.Variables(b).Name Then
Checked = True
Exit For
End If
Next
'Search in self sheet
If Not Checked Then
For a = 1 To LastRow
sL = ActiveDocument.Variables(b).Name
sR = ""
sL = Left(sL, InStr(1, sL, "_"))
If sL = "" Then sL = ActiveDocument.Variables(b).Name Else sR = Right(ActiveDocument.Variables(b).Name, Len(ActiveDocument.Variables(b).Name) - InStr(1, ActiveDocument.Variables(b).Name, "_"))
If xlWSh.Cells(a, 1).Value = sL Then
If sR = "" Then
xlWSh.Cells(a, 2).Value = "'" + CStr(ActiveDocument.Variables(b).Value)
Checked = True
Exit For
Else
For bb = 2 To 100
If xlWSh.Cells(1, bb).Value = sR Then
xlWSh.Cells(a, bb).Value = "'" + CStr(ActiveDocument.Variables(b).Value)
Checked = True
Exit For
End If
Next
End If
End If
Next
End If
'If not found - add personal row in self sheet
If Not Checked Then
xlWSh.Cells(LastRow + 1, 1).Value = "'" + CStr(ActiveDocument.Variables(b).Name)
xlWSh.Cells(LastRow + 1, 2).Value = "'" + CStr(ActiveDocument.Variables(b).Value)
LastRow = LastRow + 1
End If
Next
Set xlApp = Nothing ' the application, then release the reference.
Exit Sub
CreateFile:
Set xlWbk = xlApp.Workbooks.Add
xlWbk.ActiveSheet.Name = "All"
xlApp.DisplayAlerts = False
For a = xlWbk.sheets.Count To 2 Step -1
xlWbk.sheets(a).Delete
Next
xlApp.DisplayAlerts = True
Set xlWbs = xlWbk.sheets.Add(After:=xlApp.Worksheets(xlApp.Worksheets.Count))
xlWbs.Name = SheetName
xlApp.Workbooks(xlWbk.Name).SaveAs (ActiveDocument.Path + "\" + ExcelFile)
Resume
openexcel:
Set xlApp = CreateObject("excel.application")
xlApp.Visible = True
Resume
End Sub
Как и в случае немодального окна макроса, я делаю Excel доступным для редактирования во время работы. Произвольным образом, при этом, могу редактировать значения переменных там, где мне удобно.
Итого, проработав все документы комплекта, мы получаем каталог файлов и один управляющий Excel-файл для централизованного внесения изменений. В некоторых случаях, комплекты получаются таковы, что отредактировав файл переменных можно избежать работы в Word полностью. Разве что придется открыть эти файлы, нажать кнопку макроса "Обновить" и убедиться в корректной подстановке значений в поля перед печатью этого документа.
Теперь давайте посмотрим, что можно сделать, если какой-либо документ комплекта требует специфической проработки. Например, это, в моем случае, будет таблица соединений и подключений.
Заполнять строки таблицы в Word мне неудобно, я лучше это сделаю в Excel. Тем более там можно произвести расчет значений, например, длин кабелей по формулам, автоматом пронумеровать по возрастанию порты, и т.п.
Для переноса этой информации в Word - я сделаю макрос импорта таблицы. При этом, так-как операция эта специфическая именно для "таблицы соединений", то этот макрос я буду создавать именно в этом файле, в файле шаблона таблицы, а не глобально в normal.dotm.
Он из себя представляет следующее: (см внутри)
'Формирование списка
Sub BuildSpec2()
Dim sTab As Table
Dim xlWSh As Object
Dim xlApp As Object
Dim of As Boolean
Dim nf As Boolean
Dim cf As Boolean
Dim oCol, nCol, cCol As Integer
i = Selection.Rows.Count
If i = 0 Then
MsgBox ("Необходимо выделить строки спецификации, куда будет помещены строки раздела (Оборудование)!")
Exit Sub
End If
Response = MsgBox("Экспортировать из Эксел?", _
vbYesNo, _
"Заполнение таблицы")
If Response = vbNo Then Exit Sub
On Error Resume Next
Set xlApp = GetObject(, "Excel.Application")
If Err.Number <> 0 Then
Err.Clear ' Clear Err object in case error occurred.
MsgBox ("Сначала необходимо открыть в Excel соответствующую спецификацию")
Exit Sub
End If
On Error GoTo 0
Set xlRange = xlApp.Selection
If xlRange.Rows.Count < 2 Then
MsgBox ("Необходимо выделить диапазон строк в Экселе.")
Exit Sub
End If
UserForm1.Show
Application.ScreenUpdating = False
Set sTab = Tables(1)
i = Selection.Rows(1).Index - 1
For a = 1 To xlRange.Rows.Count - 1
sTab.Rows.Add
For b = 1 To 9
sTab.Rows(a + i).Cells(b).Range.Text = xlRange.Rows(a).Cells(b).Text
Next
UserForm1.Label2.Caption = sTab.Rows(a + i).Cells(1).Range.Text
UserForm1.Repaint
Next
UserForm1.Hide
Application.ScreenUpdating = True
Set xlApp = Nothing ' the application, then release the reference.
End Sub
Принцип работы этого макроса заключается единственно в том, чтобы взять диапазон выделенных предварительно в Excel строк и перенести в заготовку таблицы, имеющуюся в шаблоне документа.
При этом, если шаблон сделан правильно (а он сделан правильно), то при заполнении таблицы на первом листе, новые строки таблицы появятся на вновь созданном втором (третьем, четвертом, ...) листе (причем этот лист будт сделан уже с другими форматными рамками, соотвтетсвующими последующим листам ЕСКД, с маленькой нижней рамкой основной надписи).
Еще один специфичный документ - спецификация. Часть его заполняется на основе шаблона тем же макросом что и таблица кабелей (именно поэтому, если вы обратили внимание, там в названии макроса стоит Buildspec)
Здесь можно дополнительно сделать формирование списка документации, который... правильно! Соответствует набору вкладок в файле variables.xls. Поэтому очередной специфический макрос для документа "спецификация" будет осуществлять просмотр листов-вкладок "Excel" и в порядке следования занесет их в таблицу "Документация". Названия, коды, примечания - будут взяты из соответствующих переменных, введенных ранее для этих документов.
В комплекте документов есть еще ряд файлов Visio и AutoCAD. Работа с ними отличается от работы с Excel и Word, что само собой разумеется. И эти отличия заслуживают отдельного рассмотрения.
В следующей статье, я опишу принципы и некоторые детали реализации автоматизации Visio - документов. В том числе работу с шаблонами и Stencils-ами.