Программирование на VBA в Microsoft Office. Создаем свои объекты
Программирование на VBA в Microsoft Office.
Создаем свои объекты (не для чайников:-(
Здесь мы рассмотрим технологию объектно-ориентированного программирования (ООП) на Visual Basic for Applications. Описывать преимущества данной технологии нет смысла — тот, кто не пробовал ее применять на практике, этого все равно не поймет. Поэтому сразу к делу.
Запустите Word или Excel, откройте документ со своим приложением и запустите редактор Visual Basic (для начинающих — комбинация Alt+F11).
В окне проекта кликните правой кнопкой мыши и во всплывающем меню выберите пункт "Вставить-> " и далее "Модуль класса" — объекты по аналогии с C/C++ называются классами, и каждый класс хранится в отдельном модуле класса.
В дереве объектов выделите свой класс и в окне свойств наберите желаемое имя для него, например, MyClass. Это имя Вы будете использовать в дальнейшем в своих программах для создания экземпляров класса — переменных типа MyClass.
Теперь дважды кликните по имени модуля класса в окне проекта — откроется пустое окно для ввода исходного текста.
Все процедуры и функции, описанные в модуле класса, будут являться методами этого класса, соответственно, все переменные, описанные на уровне модуля, будут являться свойствами класса.
Инкапсуляция осуществляется применением ключевых слов Public и Private перед описанием свойств и методов, а в остальном — все то же самое, например:
Public hFile As Long '- свойство — ссылка на открытый файл
Private ownFile As String '- свойство — имя файла
Public Function getDataRecord(NumRec As Long) As String '- метод — чтение записи из файла, параметр — номер записи.
Все свойства и методы, описанные как Public, будут доступны для изменения и вызова из программ, в которых они будут использоваться. В нашем примере метод getDataRecord может быть вызван из основной программы.
Свойство hFile также может быть использовано основной программой без ведома самого класса.
Соответственно, все описанное как Private будет скрыто от основной программы.
В примере свойство ownFile доступно для изменения только внутри самого объекта его методами, основная программа ни прямо, ни косвенно (объявлением одноименной переменной) не может изменять значение этого свойства.
Рассмотрим более необычные варианты объявлений. В большинстве случаев требуется, чтобы доступ к свойствам класса был разрешен исключительно с помощью методов, а в некоторых случаях свойств вообще фактически не существует, а значения должны вычисляться непосредственно в момент обращения.
Для этого в языке Visual Basic существует механизм описания таких свойств с помощью ключевого слова Property.
Свойства, при чтении значения которого должен вызываться метод вычисления или передачи этого значения, описываются следующим образом:
Property Get FileName() As String
'код программы
'поиска, вычисления
'или передачи значения
FileName= ownFile ' — возврат значения
End Property
Свойства, при присваивании значения которым должен вызываться метод обработки этого значения, описываются аналогично, только с применением ключевых слов Property Let либо Property Set. Разница между ними состоит в том, что Property Let применяется для передачи значений стандартных и предопределенных программистом типов, а Property Let применяется для объектов Office и объектных переменных программы.
Property Let FileName (ByVal strFileName As String)
ownFileName = strFileName ' — присваивание строкового значения
End Property
Property Set SelectedSheet (ByVal CurrSheet As Object)
Set Area = CurrSheet ' — присваивание объекта
End Property
Для использования класса необходимо объявить переменную типа MyClass и затем создать экземпляр класса с помощью оператора new. Присваивание значений объектной переменной всегда предваряется оператором Set. Например:
Dim ObjVar As MyClass
Set ObjVar = New MyClass
Инициализация объекта при его создании и деинициализация при удалении осуществляются двумя предопределенными методами, которые можно переопределить, чтобы добавить свой код.
Private Sub Class_Initialize()
'Код инициализации
End Sub
Private Sub Class_Terminate()
'Код деинициализации
End Sub
К сожалению, в VBA не реализованы наследование и полиморфизм, но даже в таком "обрезанном" варианте применение ООП представляется более предпочтительным, нежели создание обычных процедур и функций.
При создании объемного приложения внутри документа Microsoft Office нередко наступает момент, когда стандартных средств языка Visual Basic не хватает для полноценных и более простых решений. Один из вариантов реализации программных задач заключается в вызове соответствующих функций Windows API.
Определение импортируемых функций ядра Windows, а также .DLL-библиотек в языке Visual Basic осуществляется оператором Declare, например:
Public Declare Function OemToCharBuffA Lib "User32" (ByVal src As String, ByVal Dest As String, ByVal cnt As Long) As Long
При этом перед каждым параметром необходимо ставить ключевое слово ByVal — передача параметра по значению. Проблемой иногда бывает необходимость передачи указателей на различные структуры.
Именно в таком варианте удобно применять объекты, скрывая от основной программы код вызова WinAPI и обработку громоздких структур данных, передаваемых через параметры, чтобы не "засорять" основные алгоритмы.
Рассмотрим реализацию варианта вызова диалогового окна Windows для выбора файла нужного типа. Вставьте в проект модуль класса и назовите его dlgFileOpen.
В окне исходного текста введите следующий код:
'Определение типа необходимой структуры
Private Type OPENFILENAME
lngStructSize As Long — 'Размер структуры
hwndOwner As Long — 'Дескриптор окна владельца
hInstance As Long — 'Дескриптор приложения
strFilter As String — 'Строка фильтра
strCustomFilter As String — 'Строка с выбранным фильтром
intMaxCustFilter As Long — 'Длина буфера для строки выбранного фильтра 'Всегда должна быть равна Len(strCustomFilter)
intFilterIndex As Long — 'Индекс строки фильтра
strFile As String — 'Полное имя выбранного файла (путь и файл)
intMaxFile As Long — 'Длина буфера для полного имени файла 'Всегда должна быть равна Len(strFile)
strFileTitle As String — 'Имя выбранного файла
intMaxFileTitle As Long — 'Длина буфера для имени выбранного файла 'Всегда должна быть равна Len(strFileTitle)
strInitialDir As String — 'Имя начального каталога (при открытии окна)
strTitle As String — 'Заголовок диалогового окна
lngFlags As Long — 'Флаги диалогового окна
intFileOffset As Integer — 'Смещение имени файла
intFileException As Integer — 'Смещение расширения файла
strDefExt As String — 'Расширение файла по умолчанию
lngCustData As Long — 'Данные для обработки
lngfnHook As Long — 'Указатель функции обработки
strTemplateName As String — 'Имя шаблона диалогового окна
End Type
'Описание функций Win32 API как скрытых методов класса
Private Declare Function GetOpenFileName Lib "comdlg32" _
Alias "GetOpenFileNameA" (ofn As OPENFILENAME) As Boolean
Private Declare Function GetActiveWindow Lib "user32" () As Boolean
'Переменная типа структуры — скрытое свойство класса
Private ownFileDlg As OPENFILENAME
'Метод вызова диалогового окна.
'Принимает параметры — строка фильтра, строка расширений,
'начальный каталог, строка заголовка окна.
'Возвращает полное имя файла.
Public Function OpenFile(szFilter As String, _
Optional szDefExt As String, _
Optional szInitDir As String, _
Optional szCaption As String) As String
'Задание начальных значений полей структуры
With ownFileDlg
.hInstance = 0
.hwndOwner = GetActiveWindow()
.strFile = String(255, 0)
.intMaxFile = 255
.strFilter = szFilter
.intMaxCustFilter = Len(szFilter)
.strFileTitle = String(255, 0)
.intMaxFileTitle = 255
.strDefExt = szDefExt
.strInitialDir = szInitDir
.strTitle = szCaption
.lngFlags = OFN_FILEMUSTEXIST Or OFN_EXTENTIONDIFFERENT
.lngStructSize = Len(ownFileDlg)
End With
If GetOpenFileName(ownFileDlg) Then
OpenFile = ownFileDlg.strFile
End If
End Function
Для использования этого класса создайте форму — в окне проекта кликнуть правой кнопкой мыши и выбрать "Вставить-> / UserForm".
В окне свойств формы в свойстве (Name) укажите имя своего творения, пусть это будет ownMediaPlayer. Теперь в форме создайте строку ввода ("Поле") и кнопку.
Дважды щелкните по кнопке и в окне исходного текста введите следующий код.
'Описание экземпляра класса
Dim dlgFiler As dlgFileOpen
'Инициализация класса
Private Sub UserForm_Initialize()
'Создание экземпляра класса
Set dlgFiler = New dlgFileOpen
End Sub
'Обработка события кнопки — нажатие
Private Sub CommandButton1_Click()
'Присваивание значения полю ввода — полное имя файла
TextBox1.Value = dlgFiler.OpenFile("WAV-Файлы" & _
vbNullChar & "*.WAV",,, "Выбирайте звуковой файл")
End Sub
Использование такого объекта уже гораздо проще и, в отличие от предыдущего исходника, сохраняет читабельность основной программы.
При желании Вы можете дополнить объект своими методами, возвращающими более подробную информацию о последнем выбранном файле из структуры ownFileDlg. В этом случае наиболее удобно будет использовать объявления методов-свойств Property Get.
Чтобы увидеть форму с объектом в деле, прямо на листе Excel создайте кнопку, щелкните по ней правой кнопкой мыши и выберите "Исходный текст".
Внутри метода обработки события — нажатия кнопки введите строку запуска формы:
ownMediaPlayer.Show
Описанный класс dlgFileOpen используется в примерах следующих статей. Там мы уже не будем заострять на нем внимание, а познакомимся с использованием мультимедиа в приложениях VBA — проигрыванием звуковых файлов различных форматов и видеороликов.
Пример таблицы Excel с описанными программами на VBA Вы сможете найти на http://brestmedia.f2s.com/ в разделе "Скачать".
to be continued...
Виктор Маковчик makovchik@tut.by
Создаем свои объекты (не для чайников:-(
Здесь мы рассмотрим технологию объектно-ориентированного программирования (ООП) на Visual Basic for Applications. Описывать преимущества данной технологии нет смысла — тот, кто не пробовал ее применять на практике, этого все равно не поймет. Поэтому сразу к делу.
Запустите Word или Excel, откройте документ со своим приложением и запустите редактор Visual Basic (для начинающих — комбинация Alt+F11).
В окне проекта кликните правой кнопкой мыши и во всплывающем меню выберите пункт "Вставить-> " и далее "Модуль класса" — объекты по аналогии с C/C++ называются классами, и каждый класс хранится в отдельном модуле класса.
В дереве объектов выделите свой класс и в окне свойств наберите желаемое имя для него, например, MyClass. Это имя Вы будете использовать в дальнейшем в своих программах для создания экземпляров класса — переменных типа MyClass.
Теперь дважды кликните по имени модуля класса в окне проекта — откроется пустое окно для ввода исходного текста.
Все процедуры и функции, описанные в модуле класса, будут являться методами этого класса, соответственно, все переменные, описанные на уровне модуля, будут являться свойствами класса.
Инкапсуляция осуществляется применением ключевых слов Public и Private перед описанием свойств и методов, а в остальном — все то же самое, например:
Public hFile As Long '- свойство — ссылка на открытый файл
Private ownFile As String '- свойство — имя файла
Public Function getDataRecord(NumRec As Long) As String '- метод — чтение записи из файла, параметр — номер записи.
Все свойства и методы, описанные как Public, будут доступны для изменения и вызова из программ, в которых они будут использоваться. В нашем примере метод getDataRecord может быть вызван из основной программы.
Свойство hFile также может быть использовано основной программой без ведома самого класса.
Соответственно, все описанное как Private будет скрыто от основной программы.
В примере свойство ownFile доступно для изменения только внутри самого объекта его методами, основная программа ни прямо, ни косвенно (объявлением одноименной переменной) не может изменять значение этого свойства.
Рассмотрим более необычные варианты объявлений. В большинстве случаев требуется, чтобы доступ к свойствам класса был разрешен исключительно с помощью методов, а в некоторых случаях свойств вообще фактически не существует, а значения должны вычисляться непосредственно в момент обращения.
Для этого в языке Visual Basic существует механизм описания таких свойств с помощью ключевого слова Property.
Свойства, при чтении значения которого должен вызываться метод вычисления или передачи этого значения, описываются следующим образом:
Property Get FileName() As String
'код программы
'поиска, вычисления
'или передачи значения
FileName= ownFile ' — возврат значения
End Property
Свойства, при присваивании значения которым должен вызываться метод обработки этого значения, описываются аналогично, только с применением ключевых слов Property Let либо Property Set. Разница между ними состоит в том, что Property Let применяется для передачи значений стандартных и предопределенных программистом типов, а Property Let применяется для объектов Office и объектных переменных программы.
Property Let FileName (ByVal strFileName As String)
ownFileName = strFileName ' — присваивание строкового значения
End Property
Property Set SelectedSheet (ByVal CurrSheet As Object)
Set Area = CurrSheet ' — присваивание объекта
End Property
Для использования класса необходимо объявить переменную типа MyClass и затем создать экземпляр класса с помощью оператора new. Присваивание значений объектной переменной всегда предваряется оператором Set. Например:
Dim ObjVar As MyClass
Set ObjVar = New MyClass
Инициализация объекта при его создании и деинициализация при удалении осуществляются двумя предопределенными методами, которые можно переопределить, чтобы добавить свой код.
Private Sub Class_Initialize()
'Код инициализации
End Sub
Private Sub Class_Terminate()
'Код деинициализации
End Sub
К сожалению, в VBA не реализованы наследование и полиморфизм, но даже в таком "обрезанном" варианте применение ООП представляется более предпочтительным, нежели создание обычных процедур и функций.
При создании объемного приложения внутри документа Microsoft Office нередко наступает момент, когда стандартных средств языка Visual Basic не хватает для полноценных и более простых решений. Один из вариантов реализации программных задач заключается в вызове соответствующих функций Windows API.
Определение импортируемых функций ядра Windows, а также .DLL-библиотек в языке Visual Basic осуществляется оператором Declare, например:
Public Declare Function OemToCharBuffA Lib "User32" (ByVal src As String, ByVal Dest As String, ByVal cnt As Long) As Long
При этом перед каждым параметром необходимо ставить ключевое слово ByVal — передача параметра по значению. Проблемой иногда бывает необходимость передачи указателей на различные структуры.
Именно в таком варианте удобно применять объекты, скрывая от основной программы код вызова WinAPI и обработку громоздких структур данных, передаваемых через параметры, чтобы не "засорять" основные алгоритмы.
Рассмотрим реализацию варианта вызова диалогового окна Windows для выбора файла нужного типа. Вставьте в проект модуль класса и назовите его dlgFileOpen.
В окне исходного текста введите следующий код:
'Определение типа необходимой структуры
Private Type OPENFILENAME
lngStructSize As Long — 'Размер структуры
hwndOwner As Long — 'Дескриптор окна владельца
hInstance As Long — 'Дескриптор приложения
strFilter As String — 'Строка фильтра
strCustomFilter As String — 'Строка с выбранным фильтром
intMaxCustFilter As Long — 'Длина буфера для строки выбранного фильтра 'Всегда должна быть равна Len(strCustomFilter)
intFilterIndex As Long — 'Индекс строки фильтра
strFile As String — 'Полное имя выбранного файла (путь и файл)
intMaxFile As Long — 'Длина буфера для полного имени файла 'Всегда должна быть равна Len(strFile)
strFileTitle As String — 'Имя выбранного файла
intMaxFileTitle As Long — 'Длина буфера для имени выбранного файла 'Всегда должна быть равна Len(strFileTitle)
strInitialDir As String — 'Имя начального каталога (при открытии окна)
strTitle As String — 'Заголовок диалогового окна
lngFlags As Long — 'Флаги диалогового окна
intFileOffset As Integer — 'Смещение имени файла
intFileException As Integer — 'Смещение расширения файла
strDefExt As String — 'Расширение файла по умолчанию
lngCustData As Long — 'Данные для обработки
lngfnHook As Long — 'Указатель функции обработки
strTemplateName As String — 'Имя шаблона диалогового окна
End Type
'Описание функций Win32 API как скрытых методов класса
Private Declare Function GetOpenFileName Lib "comdlg32" _
Alias "GetOpenFileNameA" (ofn As OPENFILENAME) As Boolean
Private Declare Function GetActiveWindow Lib "user32" () As Boolean
'Переменная типа структуры — скрытое свойство класса
Private ownFileDlg As OPENFILENAME
'Метод вызова диалогового окна.
'Принимает параметры — строка фильтра, строка расширений,
'начальный каталог, строка заголовка окна.
'Возвращает полное имя файла.
Public Function OpenFile(szFilter As String, _
Optional szDefExt As String, _
Optional szInitDir As String, _
Optional szCaption As String) As String
'Задание начальных значений полей структуры
With ownFileDlg
.hInstance = 0
.hwndOwner = GetActiveWindow()
.strFile = String(255, 0)
.intMaxFile = 255
.strFilter = szFilter
.intMaxCustFilter = Len(szFilter)
.strFileTitle = String(255, 0)
.intMaxFileTitle = 255
.strDefExt = szDefExt
.strInitialDir = szInitDir
.strTitle = szCaption
.lngFlags = OFN_FILEMUSTEXIST Or OFN_EXTENTIONDIFFERENT
.lngStructSize = Len(ownFileDlg)
End With
If GetOpenFileName(ownFileDlg) Then
OpenFile = ownFileDlg.strFile
End If
End Function
Для использования этого класса создайте форму — в окне проекта кликнуть правой кнопкой мыши и выбрать "Вставить-> / UserForm".
В окне свойств формы в свойстве (Name) укажите имя своего творения, пусть это будет ownMediaPlayer. Теперь в форме создайте строку ввода ("Поле") и кнопку.
Дважды щелкните по кнопке и в окне исходного текста введите следующий код.
'Описание экземпляра класса
Dim dlgFiler As dlgFileOpen
'Инициализация класса
Private Sub UserForm_Initialize()
'Создание экземпляра класса
Set dlgFiler = New dlgFileOpen
End Sub
'Обработка события кнопки — нажатие
Private Sub CommandButton1_Click()
'Присваивание значения полю ввода — полное имя файла
TextBox1.Value = dlgFiler.OpenFile("WAV-Файлы" & _
vbNullChar & "*.WAV",,, "Выбирайте звуковой файл")
End Sub
Использование такого объекта уже гораздо проще и, в отличие от предыдущего исходника, сохраняет читабельность основной программы.
При желании Вы можете дополнить объект своими методами, возвращающими более подробную информацию о последнем выбранном файле из структуры ownFileDlg. В этом случае наиболее удобно будет использовать объявления методов-свойств Property Get.
Чтобы увидеть форму с объектом в деле, прямо на листе Excel создайте кнопку, щелкните по ней правой кнопкой мыши и выберите "Исходный текст".
Внутри метода обработки события — нажатия кнопки введите строку запуска формы:
ownMediaPlayer.Show
Описанный класс dlgFileOpen используется в примерах следующих статей. Там мы уже не будем заострять на нем внимание, а познакомимся с использованием мультимедиа в приложениях VBA — проигрыванием звуковых файлов различных форматов и видеороликов.
Пример таблицы Excel с описанными программами на VBA Вы сможете найти на http://brestmedia.f2s.com/ в разделе "Скачать".
to be continued...
Виктор Маковчик makovchik@tut.by
Компьютерная газета. Статья была опубликована в номере 02 за 2002 год в рубрике программирование :: разное