
2 семестр / vba_2002
.pdf
Последовательность событий может быть сложнее, чем кажется. Перечисленные выше события происходят на уровне объекта Application. При добавлении нового листа возникают и дополнительные события {на уровне объектов Workbook и Worksheet).
Следует помнить, что события возникают в определенной последовательности. Знание порядка этой последовательности может оказаться очень важным при создании процедур обработки событий. Далее в этой главе будет рассматриваться порядок событий, возникающих при определенных действиях (за дополнительной информацией обратитесь к разделу "Отслеживание событий уровня объекта Application") .
Размещение процедур обработкисобытий
Начинающие разработчики VBA-приложений часто интересуются, почему их процедуры обработки событий не запускаются при возникновении соответствующего события. Ответ чаще всего заключается в том, что процедуры расположены в неправильном месте.
В окне редактора VBE все проекты перечислены в окне Projects. Компоненты проектов расположены в списке, показанном на рис. 19.1.
Все приведённые ниже компоненты имеют собственный модуль кода:
•объект Лист (например, Лист1, Лист2 и т.д.);
•объект Диаграмма (т.е. листы диаграмм);
•объект 3TaKHwra(ThisWorkbook);
•модули VBA общего назначения: процедуру обработки события никогда нельзя размещать в модуле общего назначения (необъектном модуле);
•модули классов.
Даже если процедуры обработки событий располагаются в мо- |
|
|
дулях объектов, они могут вызывать процедуры в модулях общего |
|
|
назначения для выполнения определенных задач. Например, сле- |
|
|
дующая процедура обработки события, расположенная в модуле |
|
|
объекта ЭтаКнига, вызывает процедуру WorkbookSetup, кото- |
риСш jgjt Компоненты ка- |
|
рая может храниться в модуле кода VBA общего назначения. |
|
ждаго проекта VBA пере- |
Private sub Workbook_open () |
числены в окне Projects |
|
Call WorkbookSetup |
|
|
End Sub |
|
|
Отключение событий
По умолчанию все события включены. Для того чтобы предотвратить возникновение всех событий, выполните следующий оператор VBA:
Application.EnableEvencs = False
Для разрешения возникновения событий воспользуйтесь оператором Appli cat ion.EnableEven с s = True
Итак, зачем же отключать события? Основная причина заключается в необходимости предотвратить бесконечный цикл возникающих событий.
Часть V. Совершенные методы программирования

Предотвращение возникновения событий не влияет на события, которые проявляются в процессе использования элементов управления в диалоговом окне UserForm. Примером такого события может спужить событие Click, которое генерируется при щелчке на элементе управления CommandButton вдиалоговом окне UserForm.
Например, ячейка Al на рабочем листе всегда должна содержать значение, которое меньше или равно 12. Можно написать процедуру, которая будет выполняться при каждом изменении данных в ячейке, что позволит проверять действительность содержимого этой ячейки. В данном случае контролируется событие Change объекта Worksheet, для чего используется процедура, которая называется Worksheet_Change. Процедура проверяет введенные пользователем данные, и если значение больше 12, то отображается окно сообщения, а содержимое ячейки очищается. Проблема заключается в том, что очистка содержимого ячейки с помощью кода VBA провоцирует возникновение еще одного события Change, что приводит к повторному вызову процедуры обработки события. Так как подобный результат нежелателен, перед очисткой содержимого ячейки необходимо отключить механизм возникновения событий. После выполнения операции включите механизм поддержки событий, чтобы иметь возможность контролировать следующую попытку пользователя ввести правильное значение в ячейку.
Еще одним способом предотвращения бесконечного цикла возникающих событий является декларирование статической булевой переменной ( S t a t i c Boolean) в начале процедуры обработки события. Воспользуйтесь следующим выражением:
S t a t i c AbortProc As Boolean
Программирование событий в старых версиях Excel
Программы Excel до версии 97 также поддерживают события, но методы программирования процедур обработки отличаются от описанных в этой главе,
Например, если вы соэдали процедуру Auto_open, которая хранится в модуле VBA общего назначения, то эта процедура будет запускаться при каждом открытии рабочей книги. Начиная с Excel 97, процедура Auto_Open дополняется обработчиком события Workbook_open, который хранится в модуле кода для обьекта Этакнига. Такой обработчик выполняется перед вызовом процедуры Auto_open.
До выхода Excel 97 разработчикам приходилось часто явно настраивать события. Например, для запуска процедуры каждый раз, когда в ячейку вводились данные, необходимо было выполнять следующий оператор:
Sheets ("Лист1") .OnEntry = "ValidciteEntry"
Этот оператор сообщает Excel, что следует запускать процедуру ValidateEntry каждый раз, когда данные вводятся в ячейку. В Excel 97 и более поздних версиях достаточно создать процедуру, которая называется Worksheet_change и сохранить ее в модуле кода для объекта Лист1.
По причине совместимости Excel 97 и более поздние версии поддерживают старый механизм обработки событий {хотя он и не документирован в справочном руководстве). Если разрабатываются приложения, которые будут использоваться в Excel 97 и более поздних версиях программы, то можно смело применять методы, описанные в этой главе.
Каждый раз, когда процедура должна внести изменения, необходимо устанавливать значение переменной AbortProc в значение True (в противном случае потребуется убедиться, что переменная установлена в значение False). Вставьте следующий код в начало процедуры.
If |
AbortProc |
Then |
|
AbortProc |
= False |
|
Exit Sub |
|
End |
if |
|
500 |
Глава 19. Концепция событий Excel |

Если происходит повторный вызов процедуры обработки события, то значение T r u e переменной A b o r t P r o c сообщает приложению о необходимости завершения этого вызова. Кроме того, значение переменной A b o r t P r o c устанавливается в значение F a l s e .
В качестве практического примера макроса проверки правильности введенных данных можно рассмотреть процедуру, приведенную в разделе "Проверка правильности введенных данных" далее в этой главе.
Отключение событий в Excel выполняется одновременно по отношению ко всем рабочим книгам. Например, если отключить события в одной процедуре и открыть другую рабочую книгу, в которой существует процедура workbook_Open, то эта процедура также не будет запущена.
Ввод кода процедуры обработки события
Каждая процедура обработки события имеет свое предопределенное имя. Ниже приводятся названия отдельных процедур обработки событий:
Worksheet_SelееtionChange Workbook_Open Chart_Activate
Class_Initialize
Можно объявить процедуру обработки события вручную, но целесообразнее возложить эту задачу на редактор VBE.
На рис. 19.2 показан модуль кода объекта ЭтаКнига. Для того чтобы добавить объявление процедуры, выберите объект Workbook из списка объектов слева. Затем выберите событие из списка процедур справа. После этого будет создана "оболочка" процедуры, которая состоит из строки декларации и оператора End Sub.
Рис. 19.2. Лучшим способом создания процедуры обработки событияявляетсяиспользованиевстроенныхсредствVBE
Haiiptrivfер, если выбрать из списка объектов — Workbook, а из списка процедур — Open, то редактор VBE вставит приведенную ниже (пустую) процедуру;
P r i v a t e Sub VJorkbook_Open {)
End Sub
Создаваемый код должен помещаться между этими двумя строками.
Часть V. Совершенные методы программирования |
501 |

Процедуры обработки событий, которые используют аргументы
Некоторые процедуры обработки событий используют набор аргументов. Например, может возникнуть необходимость в создании процедуры для обработки события S h e e t A c t i v a t e рабочей книги. Если воспользоваться методикой, описанной в предыдущем разделе, то редактор VBE создаст представленную далее процедуру:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
End Sub
Эта процедура использует один аргумент (Sh), который представляет активизированный лист. В данном случае переменная Sh имеет тип O b j e c t , а не просто тип Worksheet. Это связано с тем, что активизированный лист может оказаться листом диаграммы.
Данные, которые переданы в виде аргумента, могут быть применены в коде процедуры. В приведенном ниже примере процедура выполняется при активизации рабочего листа. На экране отображается тип и имя активизированного листа с помощью функции TypeName и свойства Name объекта, который передан в качестве аргумента.
Private Sub Workbook_SheetActivate(ByVal Sh As Object) MsgBox TypeName(Sh) & vbCrLf & Sh.Name
End Sub
Некоторые процедуры обработки событий используют аргумент C a n c e l с типом данных Boolean. Например, объявление процедуры обработки события B e f o r e P r i n t рабочей книги будет выглядеть следующим образом:
Private Sub Workbook_BeforePrint(Cancel As Boolean)
Значение аргумента C a n c e l , которое передается в процедуру, равно F a l s e . Но код может установить это значение равным True, что приведет к отмене печати. Следующий пример демонстрирует такую операцию.
Private Sub Workbook_BeforePrint(Cancel As Boolean) Msg = "Вы загрузили необходимую бумагу?"
Ans = MsgBox{Msg, vbYesNo, "В процессе печати...") If Ans = vbNo Then Cancel = True
End Sub
Процедура W o r k b o o k _ B e f o r e P r i n t выполняется перед тем, как печатается рабочая книга. Эта процедура отображает окно сообщения, которое показано на рис. 19.3. Если пользователь щелкнет на кнопке Нет, то аргумент C a n c e l будет иметь значение True, и ничего напечатано не будет.
Событие BeforePrint возникает и перед предварительным просмотром рабочей книги.
Рис.19.3.Можноотменитьоперацию печати, изменив значение аргумента Cancel
502 |
Глава 19. КонцепциясобытийExcel |
К сожалению, Excel не обрабатывает событие Bef orePrint на уровне листа. Таким образом, код не может определить, какая часть рабочей книги будет распечатана.
События объекта Workbook
События объекта Workbook происходят в пределах определенной рабочей книги. В табл. 19.1 перечислены события рабочей книги, а также приведено краткое описание каждого из них. Процедуры обработки событий объекта Workbook хранятся в модуле кода объекта ThisWorkbook (ЭтаКнига).
Таблица 19.1. СобытияобъектаWorkbook
Событие |
Действие, которое приводит к возникновению этого события |
Activate |
Актиаизация рабочей книги |
Addinlnstall |
Установка рабочей книги в качестве надстройки |
AddinUninstall |
Удаление рабочей книги, используемой в качестве надстройки |
BeforeClose |
Начало закрытия рабочей книги |
BeforePrint |
Начало процесса печати или предварительного просмотра рабочей |
|
книги или любого из ее элементов |
BeforeSave |
Начало сохранения рабочей книги |
Deactivate |
Деактивизация рабочей книги |
NewSheet |
Создание нового листа в рабочей книге |
Open |
Открытие рабочей книги |
PivotTableCloseConnection* Соединение с внешним источником данных сводной таблицы
|
закрыто |
|
PivotTableOpenConnection* Соединение с внешним источником данных сводной таблицы |
||
|
открыто |
|
SheetActivate |
Активизация любого листа |
|
SheetBeforeDoubleClick |
Двойной щелчок на любом из листов. Это событие происходит до |
|
|
принятого по умолчанию события двойного щелчка |
|
SheetBeforeEightClick |
Щелчок правой кнопкой мыши на любом листе. Это событие про- |
|
|
исходит до принятого по умолчанию события щелчка правой кноп- |
|
|
кой мыши |
|
SheetCalculate |
Расчет (или перерасчет) значений в любом листе |
|
SheetChange |
Изменение любого листа пользователем или внешней ссылкой |
|
SheetDeactivate |
Деактивизация любого листа |
|
SheetFollowHyperlink |
Щелчок на гиперссылке в листе |
|
SheetPivotTableUpdate |
Пополнение сводной таблицы новыми данными |
|
SheetSelectionChange |
Изменение выделения на любом листе |
|
WindowActivate |
Активизация окна любой рабочей книги |
|
WindowDeactivate |
Деактивация окна любой рабочей книги |
, |
WindowResize |
Изменение размера окна любой рабочей книги |
|
" Это событие происходит только в Excel 2002 и не поддерживается в предыдущих версиях.
ЧастьV.Совершенныеметодыпрограммирования |
503 |

Если необходимо следить за событиями, возникающими для всех рабочих книг, то следует работать на уровне объекта Application (см. раздел "События объекта Application" далее в этой главе). Ниже приведены примеры использования событий объекта workbook. Все примеры процедур, представленные ниже,, должны располагаются в модуле кода объекта ЭтаКнига. Если разместить их в модуле кода другого типа, то они не будут работать.
Событие Open
Одним из наиболее часто используемых является событие Open объекта рабочей книги. Это событие возникает при открытии рабочей книги (или надстройки). При этом выполняется процедура Workbook_Open. Процедура Workbook_Open может выполнять любые действия, но чаще всего она используется для решения следующих задач:
•отображении приветственных сообщений;
•открытия других рабочих книг;
•настройки пользовательских меню или панелей инструментов;
•активизации определенного листа или ячейки;
•проверки определенных условий (например, рабочая книга может требовать наличия определенной надстройки);
•установки определенных автоматических средств (например, можно определять комбинации клавиш — см. раздел "Событие ОпКеу" далее в этой главе);
•настройки свойства S c r o l l A r e a рабочего листа (которое не хранится в рабочей книге);
•настройки защиты User I n t e r faceOnly для рабочего листа, что позволяет управлять
защищенными листами в коде. Этот параметр является аргументом метода P r o t e c t и не хранится в пределах рабочей книги
Если пользователь будет удерживать клавишу <Shift> в момент открытия рабочей книги, то процедура Workbook_ppen не сможет быть запущена.
Ниже приводится простой пример процедуры Workbook_Open. Эта процедура использует функцию Weekday для определения дня недели. Если текущий день недели пятница, то отображается окно сообщения, которое напоминает пользователю о необходимости проведения еженедельного резервного копирования файлов. Если текущий день недели не пятница, то ничего не происходит.
P r i v a t e Sub Workbook_Open{)
If Weekday(Now) = vbFriday Then
Msg = "Сегодня пятница. Ты уже создал" Msg = Msg & "новую резервную копию?" MsgBox Msg, vblnformation
End If End Sub
Событие Activate
Следующая процедура выполняется при каждой активизации рабочей книги, Эта проце-
дура разворачивает активное окно: |
|
504 |
Глава 19. Концепция событий Excel |
Private Sub Workbook_Activate()
ActiveWindow.WindowState = xlMaximized
End Sub
Событие SheetActivate
Представленная далее процедура выполняется каждый раз, когда пользователь активизирует один из листов рабочей книги. Если этот лист является рабочим листом, то выделяется ячейка А1. Если он не является рабочим листом, то ничего не происходит. Данная процедура использует функцию VBA TypeName для того, чтобы удостовериться, что активный лист является рабочим листом (не представлен листом диаграммы).
Private Sub Workbook_SheetActivate(ByVal Sh As Object) If TypeName(Sh) = "Worksheet" Then _
Range("Al").Select
End Sub
Существует и другой метод избежать ошибки при выделении ячейки на листе диаграммы — просто игнорируйте такую ошибку.
P r i v a t e Sub Workbook_SheetActivate{ByVal Sh As Object)
On Error Resume Next Range("Al").Select
End Sub
Событие NewSheet
Рассматриваемая процедура выполняется каждый раз, когда к рабочей книге добавляется лист. Лист передается в процедуру в качестве аргумента. Так как новый лист может выступать как рабочим листом, так и листом диаграммы, то эта процедура в обязательном порядке определяет тип листа. Если вставляется рабочий лист, то код создает запись о дате и времени добавления листа в ячейку А1.
Private Sub Workbook_NewSheet(ByVal Sh As Object) If TypeName(Sh) = "Worksheet" Then _
Range("Al") = "Лист добавлен " & Now () End Sub
Событие BeforeSave
Событие B e f o r e S a v e возникает перед фактическим сохранением рабочей книги. Как известно, использование команды Файл^Сохранить приводит к появлению диалогового окна Сохранение документа. Это происходит в том случае, если рабочая книга еще ни разу
не сохранялась и не открывалась в режиме "только чтения". |
|
||
При |
выполнении процедуры |
Workbook_Bef o r e S a v e ей передается |
аргумент |
(SaveAsUI), который позволяет предвосхитить появление диалогового окна Сохранение |
|||
документа. Следующий пример демонстрирует использование этого события. |
|
||
Private Sub Workbook_BeforeSave __ |
|
||
{ByVal SaveAsUI As Boolean, |
Cancel As Boolean) |
|
|
If SaveAsUI Then |
|
|
|
|
MsgBox "Щелкните на кнопке OK для сохранения." |
|
|
End |
If |
|
|
End Sub |
|
|
|
Часть V. Совершенные методы программирования |
505 |

Когда пользователь сохраняет рабочую книгу, выполнится процедура Workbook_ BeforeSave . Если операция сохранения приводит к появлению диалогового окна Сохранение документа, то переменной SaveAsUl присваивается значение True . Процедура проверяет переменную SaveAsUl, в результате отображается сообщение лишь в том случае, если на экране появляется окно сохранения документа. При установлении процедурой аргумента C a n c e l в значение True файл сохранен не будет.
Событие Deactivate
Предлагаемый пример демонстрирует использование события D e a c t i v a t e . Эта процедура выполняется каждый раз при деактивизашш рабочей книги. Она не позволяет пользователю деактивизиронать рабочую книгу. При возникновении события D e a c t i v a t e код производит повторную активизацию рабочей книги и выводит на экран соответствующее сообщение.
Private Sub Workbook_Deactivate() Me.Windows(1).Activate
MsgBox "Мне жаль, ко вы не покинете эту книгу!" End Sub
Использовать такие процедуры не рекомендуется. Если процедура пытается "взвалить" на себя задачи Excel, то ее действия могут привести пользователя в замешательство. Мы настоятельно рекомендуем обучать пользователей правильной работе с приложением.
Приводимый пример иллюстрирует важность обработки событий в необходимой последовательности. Запустив эту процедуру, вы убедитесь, что она работает правильно только в тех случаях, когда пользователь активизирует другую рабочую книгу. Событие D e a c t i v a t e для рабочей книги возникает и в ряде других случаев:
•при закрытии рабочей книги;
•при открытии новой рабочей книги;
•при сворачивании окна рабочей книги..
Таким образом, данная процедура не будет работать точно так, как это задумывалось изначально. Она будет предотвращать попытки пользователя непосредственно активизировать другую рабочую книгу, но не сможет воспрепятствовать закрытию рабочей книги, открытию новой рабочей книги шш сворачиванию окяя рабочей книги. Окно сообщения будет отображаться, но действия все же будут возможны.
Событие BeforePrint
Событие B e f o r e P r i n t происходит, когда пользователь отправляет документ на печать или отображает его (или фрагмент рабочей книги) в режиме предварительного просмотра. Данное событие происходит перед началом фактической печати или предварительного просмотра рабочей книги. Процедура обработки этого события принимает аргумент C a n c e l , чтобы в коде можно было отменить печать пли выполнить предварительный просмотр в результате установки этого аргумента и значение True . К сожалению, не существует способа определить, чем было спровоцировано событие B e £ o r e P r i n t : отправкой задания печати или запросом предварительного просмотра.
В Excel до версии 2002 нельзя было в верхнем или нижнем колонтитуле страницы напечатать полный путь к файлу, в котором хранилась рабочая книга. Excel 2002 решает эту проблему. Теперь на вкладке Колонтитулы (доступ к ней открыт в диалоговом окне Параметры страницы) можно определить все необходимые данные колонтитулов.
506 Глава 19. Концепция событий Excel

Если вы используете старую версию Excel, то единственным решением будет создание кода, который добавляет путь к рабочей книге в верхний или нижний колонтитул. Процедура обработки события BeforePrint является идеальным способом размещения такого кода. Процедура Workbook_BeforePrint, содержащая подобный код, приводится ниже.
Private Sub Workbook_BeforePrint(Cancel As Boolean) For Each sht In ThisWorkbaok.Sheets
sht.PageSetup.LeftFooter = „ "&8" & ThisWorkbook.FullName
Next sht End Sub
Эта процедура просматривает все листы рабочей книги и присваивает свойству LeftFooter объекта PageSetup значение свойства FileName объекта рабочей книги (которое содержит путь и имя файла, где хранится рабочая книга). Кроме того, размер шрифта устанавливается в значение 8 пунктов.
Приводимый пример демонстрирует неоднородность объектной модели Excel. Для того чтобы изменить размер шрифта нижнего и верхнего колонтитулов, необходимо применить специальный код форматирования. В примере, показанном выше, используется строка "&8" для назначения шрифта размером 8 пунктов. В идеале в объектах колонтитулов должен использоваться объект Font. Чтобы определить доступность других способов форматирования, необходимо обратиться к справочному руководству (или записать макрос в момент доступа к диалоговому окну Параметры страницы, а затем проанализировать полученный код).
При тестировании процедуры обработки события BeforePrint вы сможете сэкономить время {и бумагу), выполнив предварительный просмотр документа вместо отправки его на печать.
Событие BeforeClose
Событие B e f o r e C l o s e происходит перед закрытием рабочей книги. Это событие часто используется совместно с процедурой Workbook_Open. Например, можно использовать процедуру Workbook_open для создания дополнительной опции меню, специфичной для конкретной рабочей книги, а процедуру W o r k b o o k _ B e f o r e C l o s e — для удаления этого дополнительного элемента из меню. Таким образом вы обеспечите доступность опции меню только в открытой рабочей книге.
Как известно, при попытке закрыть несохраненную рабочую книгу Excel выдает сообщение с запросом на сохранение рабочей книги перед ее закрытием (рис. 19.4).
Рис. 19.4- Если отображается это сообщение, значит, процедура Workhook_Be£oreClose уже завершиласвоюработу
Обратим ваше внимание на потенциальную проблему, которая заключается в следующем: к моменту отображения этого сообщения событие BeforeClose уже возникло, что указывает на завершение работы процедуры workbook_BeforeCios(j.
Часть V. Совершенные методы программирования |
507 |
Рассмотрим иной сценарий развития событий: в момент открытия определенной рабочей книги отображается пользовательское меню. В данном случае рабочая книга использует процедуру Workbook_Open для создания меню при открытии рабочей книги, а процедура Workbook_Bef o r e C l o s e — для удаления этого меню при закрытии рабочей книги. Процедуры обработки событий приведены ниже. Обе процедуры вызывают другие процедуры, которые нами не рассматриваются.
Private Sub Workbook_Open()
Call CreateMenu
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Call DeleteMenu
End Sub
Как отмечалось выше, сообщение Excel Сохранить и з м е н е н и я . . . отображается после того, как процедура Workbook_Bef o r e C l o s e завершит свою работу. Поэтому, если пользователь щелкнет на кнопке Отмена, то работай книга останется открытой, но дополнительный элемент меню будет уже удален!
Одним из решений подобной проблемы является создание кода запроса на сохранение в процедуре Workbook _ BeforeClose . Ниже приведен пример, выполняющий подобную задачу.
Private Sub Workbook_BeforeClose(Cancel As Boolean) Dim Msg As String
If Me.Saved Then Call DeleteMenu Exit Sub
Else
Msg = "Сохранить изменения в документе?" Msg = Msg & Me.Name & "?"
Ans = MsgBox{Msg, vbQuestion + vbVesNoCancel) Select Case Ans
Case vbYes Me.Save
Call DeleteMenu Case vbNo
Me.Saved = True
Call DeleteMenu Case vbCancel
Cancel = True End Select
End If End Sub
Данная процедура проверяет значение свойства Saved объекта Workbook, с целью определить наличие в рабочей книге несохраненных данных. Если они существуют, то выполняется процедура DeleteMenu, и рабочая книга закрывается. Однако в рабочей книге могут оставаться несохраненные данные, тогда процедура отображает окно сообщения, которое дублирует исходное окно сообщения Excel. Если пользователь щелкнет на кнопке Да, то рабочая книга будет сохранена, элемент меню удален, а рабочая книга — закрыта. Если пользователь щелкнет на кнопке Нет, то код установит свойство Saved объекта Workbook в значение True {но не будет сохранять файл) и удалит опцию меню. Если пользователь щелкнет на кнопке Отмена, то событие Bef o r e C l o a e будет отменено и процедура завершится без удаления элемента меню.
508 |
Глава 19. Концепция событий Excel |