Страницы

суббота, 6 сентября 2014 г.

Вывод свойств таблиц из Access в Word

Рассмотрим, как перенести в документ Microsoft Word таблицы с полями и свойствами полей из Microsoft Access. Точнее, мы будем переносить не сами данные, а именно характеристики таблиц.  Иногда бывает нужно сделать несколько работ с отчетами или работу с большой базой данных. В этом случае изложенный метод поможет сэкономить время при написании отчета.
Предлагаю один из вариантов решения поставленной задачи. Его можно отредактировать под свои нужды и стандарты, например, оформление и разные свойства полей.
Как пользоваться (для тех, кто мало использует VBA) – скопируйте выделенный шрифтом текст функции (дальше по тексту поста). Откройте базу данных, перейдите на вкладку «Создание». Найдите крайний справа пункт «Макрос» и нажмите на раскрывающую стрелку вниз, выберите пункт «Модуль»:


Откроется редактор Visual Basic. У вас автоматически создается первый модуль под именем Module1. Вставляйте ранее скопированный текст функции в этот модуль.
Если у вас уже есть там какой-то модуль, можете создать новый или вставить функцию в имеющийся.
Сейчас нужно проверить подключенные библиотеки. В редакторе VB идем в меню Tools->References и смотрим, что там у нас подключено. Вот какие пункты должны быть отмечены галочками:


Если какого-то пункта нет (как правило, нет библиотеки Microsoft Word 12.0 Object Library) то ищем его в списке и ставим галочку. Если у вас офис ранних версий, то версия будет не 12.0, а меньше.

Устанавливаем курсор на текст функции PrintTablesWord() и запускаем ее на выполнение с панели, нажав на значок зеленого треугольника, из меню – Run->Run Sub или нажав F5.
Откроется новый документ Word, заполнится таблицами с данными и останется открытым. Если все устраивает, то закрываем редактор Visual Basic, не сохраняя изменения (для работы новая функция не нужна, только для отчета). Далее работаем с документом Word – копируем таблицы в отчет, исправляем и так далее.

Если что-то не устраивает, то правим текст функции и снова запускаем.
Сейчас подробнее по тексту.
Sub PrintTablesWord()
    Dim db As dao.Database
    Dim tdf As TableDef, fld As Field, prop As Property
    Dim wd As Word.Application
    Dim tableNumber As Integer, fldCount As Integer
    Dim str As String, strDimens As String
   
    On Error Resume Next
    tableNumber = 1
    fldCount = 0
    str = ""
    strDimens = ""
   
    Set db = CurrentDb
    Set wd = CreateObject("Word.Application")
    wd.Visible = True
    'создаем новый документ Word
    wd.Documents.Add
    'выборка всех таблиц из базы данных
    For Each tdf In db.TableDefs
        'исключаем системные таблицы
         If Left(tdf.Name, 4) <> "MSys" Then
            fldCount = tdf.Fields.Count
            'пишем таблицу и ее номер
            wd.Selection.TypeParagraph
            wd.Selection.Font.Italic = False
            wd.Selection.TypeText Text:="Таблица " + CStr(tableNumber)
            wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphRight
            'название таблицы
            wd.Selection.TypeParagraph
            wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
            wd.Selection.TypeText Text:="Характеристики полей таблицы " + tdf.Name
            wd.Selection.MoveLeft Unit:=wdCharacter, Count:=Len(tdf.Name), Extend:=wdExtend
            wd.Selection.Font.Italic = True
            wd.Selection.MoveRight Unit:=wdCharacter, Count:=Len(tdf.Name)
            'вставляем таблицу с нужным количеством строк
            wd.ActiveDocument.Tables.Add Range:=wd.Selection.Range, NumRows:=fldCount + 1, NumColumns:= _
        3, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
        wdAutoFitFixed
            With wd.Selection.Tables(1)
                If .Style <> "Сетка таблицы" Then
                    .Style = "Сетка таблицы"
                End If
                .ApplyStyleHeadingRows = True
                .ApplyStyleLastRow = False
                .ApplyStyleFirstColumn = True
                .ApplyStyleLastColumn = False
                .ApplyStyleRowBands = True
                .ApplyStyleColumnBands = False
            End With
            'первая строка - шапка таблицы
            wd.Selection.TypeText Text:="Имя поля"
            wd.Selection.MoveRight Unit:=wdCell
            wd.Selection.TypeText Text:="Тип данных"
            wd.Selection.MoveRight Unit:=wdCell
            wd.Selection.TypeText Text:="Свойства поля"
           
            'перебор полей
            For Each fld In tdf.Fields
                str = ""
                strDimens = ""
                'название поля
                wd.Selection.MoveRight Unit:=wdCell
                wd.Selection.TypeText Text:=fld.Name
                wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
                wd.Selection.SelectCell
                wd.Selection.Cells.VerticalAlignment = wdCellAlignVerticalCenter
                wd.Selection.MoveRight Unit:=wdCell
                'тип данных (и размер)
                Select Case fld.Type
                Case dbBoolean
                    wd.Selection.TypeText Text:="Логический"
                Case dbByte
                    wd.Selection.TypeText Text:="Байт"
                    strDimens = "Байт"
                Case dbCurrency
                    wd.Selection.TypeText Text:="Денежный"
                Case dbDate
                    wd.Selection.TypeText Text:="Дата/время"
                Case dbDouble
                    wd.Selection.TypeText Text:="Числовой"
                    strDimens = "С плавающей точкой 8 байт"
                Case dbGUID
                    wd.Selection.TypeText Text:="Счетчик"
                    strDimens = "Длинное целое"
                Case dbInteger
                    wd.Selection.TypeText Text:="Числовой"
                    strDimens = "Целое"
                Case dbLong
                    wd.Selection.TypeText Text:="Числовой"
                    strDimens = "Длинное целое"
                Case dbLongBinary
                    wd.Selection.TypeText Text:="Объект OLE"
                Case dbMemo
                    wd.Selection.TypeText Text:="Поле MEMO"
                Case dbSingle
                    wd.Selection.TypeText Text:="Числовой"
                    strDimens = "С плавающей точкой 4 байт"
                Case dbText
                    wd.Selection.TypeText Text:="Текстовый"
                    strDimens = CStr(fld.Size)
                Case Else
                    wd.Selection.TypeText Text:=CStr(fld.Type)
strDimens = CStr(fld.Size)
     End Select
                wd.Selection.SelectCell
                wd.Selection.Cells.VerticalAlignment = wdCellAlignVerticalCenter
                'свойства поля
                wd.Selection.MoveRight Unit:=wdCell
                wd.Selection.Font.Italic = False
                wd.Selection.TypeText Text:="Обязательное поле: " + IIf(fld.Required, "Да", "Нет")
                wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
                wd.Selection.MoveLeft Unit:=wdCharacter, Count:=3, Extend:=wdExtend
                wd.Selection.Font.Italic = True
                wd.Selection.MoveRight Unit:=wdCharacter, Count:=1
                If Len(strDimens) > 0 Then
                    wd.Selection.TypeParagraph
                    wd.Selection.Font.Italic = False
                    wd.Selection.TypeText Text:="Размер поля: " + strDimens
                    wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
                    wd.Selection.MoveLeft Unit:=wdCharacter, Count:=Len(strDimens), Extend:=wdExtend
                    wd.Selection.Font.Italic = True
                    wd.Selection.MoveRight Unit:=wdCharacter, Count:=1
                End If
                'перебор всех свойств и выбор нужного
                For Each prop In fld.Properties
                    str = ""
                    If prop.Name Like "Description" Then
                        str = "Описание: "
                    End If
                    If prop.Name Like "inputmask" Then
                        str = "Маска ввода: "
                    End If
                    If prop.Name Like "Format" Then
                        str = "Формат поля: "
                    End If
                    If prop.Name Like "rowsource" Then
                        str = "Источник строк: "
                    End If
                    'вывод свойства в таблицу
                    If Len(str) > 0 Then
                        wd.Selection.TypeParagraph
                        wd.Selection.Font.Italic = False
                        wd.Selection.TypeText Text:=str + prop.Value
                        wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphLeft
                        wd.Selection.MoveLeft Unit:=wdCharacter, Count:=Len(prop.Value), Extend:=wdExtend
                        wd.Selection.Font.Italic = True
                        wd.Selection.MoveRight Unit:=wdCharacter, Count:=1
                    End If
                Next prop
            Next fld
            tableNumber = tableNumber + 1
            wd.Selection.MoveDown Unit:=wdLine, Count:=1
        End If
    Next tdf
   Set db = Nothing
End Sub
Функция получилась длинная, но разбивать ее на несколько нет смысла, все равно копировать одним куском, а потом удалять.
Сначала объявляем переменные:
db As dao.Database – база данных
tdf As TableDef - таблица
fld As Field – поле таблицы
prop As Property – свойство поля
wd As Word.Application – приложение Word
tableNumber As Integer – номер таблицы (нужен для заголовка)
fldCount As Integer - количество полей в таблице (для создания таблицы)
str As String, strDimens As String – вспомогательные строки

Обязательно пишем - On Error Resume Next
Дело в том, что у разных типов полей разные свойства. Если программа не найдет какого-либо свойства, то выдаст ошибку и остановится. Если же написано «On Error Resume Next», то программа без выдачи предупреждений об ошибках проследует дальше.
Далее инициализируем наши переменные, подключаемся к базе данных программно, создаем и открываем новый документ Word.
For Each tdf In db.TableDefs
Next tdf
В этом цикле выбираем все таблицы. Но не все таблицы нам нужны. В базе содержится куча системных таблицы, которые скрыты. В отчете их не нужно указывать.  Названия системных таблиц начинаются с MSys, поэтому их исключаем:
         If Left(tdf.Name, 4) <> "MSys" Then
Если же есть еще скрытые таблицы, например, начинающиеся с USys, можно добавить новое условие.
Затем считаем количество полей таблицы

fldCount = tdf.Fields.Count

и начинаем оформлять документ. Сначала заголовок таблицы и слово «Таблицы « с номером, затем вставляем таблицу с нужным количеством строк, равным числу полей плюс 1 (для шапки).
Несколько операторов из текста:
wd.Selection.TypeParagraph – новый абзац.
wd.Selection.Font.Italic = False – устанавливаем НЕкурсивный шрифт.
wd.Selection.TypeText Text:="Таблица " текст абзаца.
wd.Selection.ParagraphFormat.Alignment = wdAlignParagraphRight – выравнивание абзаца
Все выполняем через объект Selection.

В заголовке таблицы выделим название таблицы курсивом. Сделаем, например, так (взято из записи макроса):

wd.Selection.TypeText Text:="Характеристики полей таблицы " + tdf.Name – выводим заголовок
wd.Selection.MoveLeft Unit:=wdCharacter, Count:=Len(tdf.Name), Extend:=wdExtend – выделяем название таблицы, то есть двигаемся влево на количество букв (тип единиц – буква wdCharacter) названия.
wd.Selection.Font.Italic = True – устанавливаем курсивный шрифт.
wd.Selection.MoveRight Unit:=wdCharacter, Count:=Len(tdf.Name) – возвращаемся обратно.
Можно передвигаться по-другому, используя Move, end, start. Способы описаны в справке по VBA.
wd.ActiveDocument.Tables.Add Range:=wd.Selection.Range, NumRows:=fldCount + 1, NumColumns:= _3, … - вставляем таблицу из трех столбцов.
Передвигаться по ячейкам таблицы можно также с помощью MoveLeft, MoveRight и т.д., но единица передвижения будет ячейка – wdCell.

 wd.Selection.MoveRight Unit:=wdCell – переходим в ячейку правее. Если она крайняя, то курсор переходит на следующую строку. Если строки нет, то она создается по шаблону верхней строки.
 For Each fld In tdf.Fields – в цикле перебираем все поля таблицы.

В первом и втором столбце нужно установить выравнивание по вертикали по центру. Это делается на в параметрах абзаца (как выравнивание по горизонтали), а в параметрах ячейки. Сначала нужно выделить ячейку, затем установить нужный вариант выравнивания:

wd.Selection.SelectCell
wd.Selection.Cells.VerticalAlignment = wdCellAlignVerticalCenter


Во втором столбце нужно указать тип данных. Каждому типу соответствует своя константа. Поскольку значение константы числовое, а в отчет нужно вывести текстовое значение, то в операторе Select Case выбираем нужное значение, соответствующее константе. Если мы перечислили не все значения, и подходящего соотношения не нашлось, то ищем его значение в справке и добавляем в текст функции или просто выведем числовое значение и исправим вручную в тексте документа.

Кроме типа данных запомним еще размер поля strDimens. Можно вывести и само значение Size, но оно показательно только для текстовых полей.
Case dbText
wd.Selection.TypeText Text:="Текстовый"
strDimens = CStr(fld.Size)
В третьем столбце выводим свойства полей. Значение свойства выделяем курсивом, как уже описано выше. Отличие – возвращаемся вправо на одну единицу, потому что в таблицах движение идет по ячейкам.
Сначала выводим, является ли поле обязательным. Недостаток – у ключевых полей всегда выводится «Нет»., а свойство “Primary” требует ADO.
Затем выведем размер поля, если он записан в strDimens. Иногда размер поля не имеет значения (например, у OLE, MEMO), в таких случаях его не выводим:

 If Len(strDimens) > 0 Then
    ‘… здесь выводим размер поля


Затем в цикле For Each перебираем все поля и выбираем нужные. Из нужных запоминаем в переменную str название. Затем смотрим, если длина str больше нуля, то есть свойство найдено, то выводим его и его значение (prop.value). Значение затем выделяем курсивом.

После каждой таблицы сдвигаемся вниз:

wd.Selection.MoveDown Unit:=wdLine, Count:=1

Вот что примерно получается:


Список свойств в этом примере неполный, можете посмотреть в справке и добавить свои. Вот адрес страницы справки всех свойств: http://msdn.microsoft.com/en-us/library/aa294141%28v=office.10%29.aspx

Кажется, все важное описал. Пример проверен для Microsoft Access 2007.