? Применение vba и макросов в microsoft® excel

621
решения изнес- ? Применение VBA и макросов в Microsoft® Excel

Upload: vudung

Post on 13-Feb-2017

526 views

Category:

Documents


15 download

TRANSCRIPT

Page 1: ? Применение VBA и макросов в Microsoft® Excel

решения изнес- ?

Применение VBA и макросов в

Microsoft® Excel

Page 2: ? Применение VBA и макросов в Microsoft® Excel

Bill Jelen, Mr. ExcelTracy Syrstad

800 East 96th StreetIndianapolis, Indiana 46240

solutionsusiness ?

VBA and Macros for

Microsoft® Excel

Page 3: ? Применение VBA и макросов в Microsoft® Excel

Билл Джелен, “Мистер Excel”Трейси Сирстад

Москва • Санкт-Петербург • Киев 2006

решения изнес- ?

Применение VBA и макросов в

Microsoft® Excel

Page 4: ? Применение VBA и макросов в Microsoft® Excel

ББК 32.973.26�018.2.75

Д40

УДК 681.3.07

Издательский дом ‘‘Вильямс”

Главный редактор С.Н. Тригуб

Зав. редакцией В.Р. Гинзбург

Перевод с английского и редакция А.В. Журавлева

По общим вопросам обращайтесь в Издательский дом ‘‘Вильямс’’ по адресу:

[email protected], http://www.williamspublishing.com

115419, Москва, а/я 783; 03150, Киев, а/я 152

Джелен, Билл, Сирстад, Трейси.

Д40 Применение VBA и макросов в Microsoft Excel. : Пер. с англ. ���� М. : Из�

дательский дом ‘‘Вильямс’’, 2006. ���� 624 с. : ил. ���� Парал. тит. англ.

ISBN 5�8459�0882�5 (рус.)

В этой книге рассматривается автоматизация выполнения всевозможных задач

с помощью Excel VBA ���� от создания простого отчета до разработки полноценного

приложения Excel ‘‘с нуля’’. Авторы книги полагаются на достаточно высокий уро�

вень подготовки читателя, однако допускают, что материал каждой главы не зна�

ком ему в полном объеме. Особое внимание при изложении материала уделяется

таким высокоэффективным средствам Excel, как диаграмма, расширенный фильтр

и сводная таблица. Прежде чем продемонстрировать решение той или иной задачи

с помощью VBA, авторы кратко останавливаются на ее выполнении с помощью

пользовательского интерфейса Excel. Прочитав книгу, читатель получит знания,

необходимые для автоматизации выполнения повседневных задач и создания соб�

ственных решений в Excel с помощью VBA.

Книга предназначена для опытных пользователей Excel.

ББК 32.973.26�018.2.75

Все названия программных продуктов являются зарегистрированными торговыми марками

соответствующих фирм.

Никакая часть настоящего издания ни в каких целях не может быть воспроизведена в какой

бы то ни было форме и какими бы то ни было средствами, будь то электронные или механиче�

ские, включая фотокопирование и запись на магнитный носитель, если на это нет письменного

разрешения издательства Que Corporation.

Authorized translation from the English language edition published by Sams Publishing, Copyright © 2004.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by any

means, electronic or mechanical, including photocopying, recording or by any information storage re�

trieval system, without permission from the publisher.

Russian language edition is published by Williams Publishing House according to the Agreement with

R&I Enterprises International, Copyright © 2006.

ISBN 5�8459�0882�5 (рус.) © Издательский дом ‘‘Вильямс’’, 2006

ISBN 0�7897�3129�0 (англ.) © Sams Publishing, 2004

Page 5: ? Применение VBA и макросов в Microsoft® Excel

Îãëàâëåíèå

Об авторах 23

Посвящения 23

Благодарности 23

Введение 25

Часть I. Первые шаги 35

Глава 1. Excel и VBA — гремучая смесь 37

Глава 2. Знакомство с Visual Basic for Applications 59

Глава 3. Работа с диапазоном ячеек 95

Глава 4. Функции, определенные пользователем 111

Глава 5. Циклы и управление выполнением кода 141

Глава 6. Стиль записи ссылок R1C1 161

Глава 7. Имена 177

Глава 8. События 189

Глава 9. Введение в пользовательские формы 215

Часть II. Автоматизация Excel 227

Глава 10. Диаграммы 229

Глава 11. Анализ данных с помощью расширенного фильтра 267

Глава 12. Сводные таблицы 299

Глава 13. Excel всемогущий 363

Глава 14. Взаимодействие с Internet 407

Глава 15. Поддержка XML в профессиональном выпуске Excel 2003 427

Глава 16. Автоматизация Word 439

Часть III. Удивительные возможности Visual Basicfor Applications 461

Глава 17. Массивы 463

Глава 18. Работа с текстовыми файлами 473

Глава 19. Использование Microsoft Access 489

Глава 20. Создание пользовательских объектов, типов и коллекций 505

Глава 21. Пользовательские формы — профессиональный подход 525

Глава 22. Интерфейс прикладного программирования (API) Windows 547

Page 6: ? Применение VBA и макросов в Microsoft® Excel

6 Оглавление

Глава 23. Обработка ошибок 561

Глава 24. Создание пользовательских меню и панелей инструментов 575

Глава 25. Надстройки 593

Глава 26. Практикум: создание приложения Excel “с нуля” 603

Предметный указатель 615

Page 7: ? Применение VBA и макросов в Microsoft® Excel

Ñîäåðæàíèå

Об авторах 23

Посвящения 23

Благодарности 23

Введение 25

VBA — работа на результат 25

Как организована эта книга 27

Часть I, “Первые шаги” 27

Часть II, “Автоматизация Excel” 27

Часть III, “Удивительные возможности Visual Basic for Applications” 27

Для кого предназначена эта книга 28

История развития электронных таблиц и макросов 29

Будущее Excel и VBA 30

Соглашения, принятые в этой книге 31

Рассматриваемые версии Excel 32

Программный код 32

Следующий шаг 32

Ждем ваших отзывов! 33

Часть I. Первые шаги 35

Глава 1. Excel и VBA — гремучая смесь 37

Excel всемогущий 37

Камни преткновения 37

Средство записи макросов не работает! 37

Visual Basic — это не BASIC 38

Хорошие новости 38

Отличные новости 38

Панель инструментов “Visual Basic” 39

Безопасность макросов 40

Уровень безопасности “Очень высокая” 40

Уровень безопасности “Высокая” 40

Уровень безопасности “Средняя” 41

Уровень безопасности “Низкая” 41

Запись, хранение и выполнение макросов 42

Диалоговое окно “Запись макроса” 42

Выполнение макроса 43

Создание кнопки выполнения макроса 43

Назначение макроса элементу управления формы 44

Редактор Visual Basic 45

Параметры редактора Visual Basic 45

Page 8: ? Применение VBA и макросов в Microsoft® Excel

8 Содержание

Диспетчер проектов 46

Окно свойств 47

Изучение кода макроса 50

Непредвиденные результаты 52

Возможное решение: использование относительных ссылок 52

Отчаяние 57

Следующий шаг 57

Глава 2. Знакомство с Visual Basic for Applications 59

Загадочный код 59

Учимся понимать “речь” VBA 60

Справочная система VBA 63

Спасительная клавиша <F1> 63

Просмотр разделов справочной системы 65

Изучение кода записанного макроса 66

Необязательные параметры 68

Предопределенные константы 68

Возврат объектов свойством 73

Использование отладчика кода 74

Пошаговое выполнение кода 74

Точки прерывания 77

Перемещение по коду 78

Выполнение фрагмента кода 79

Вычисление значения переменной или выражения 79

Установка точки прерывания с помощью окна Watches 83

Отслеживание состояния объекта с помощью окна Watches 83

Диспетчер объектов 85

5 советов по исправлению и оптимизации автоматически

сгенерированного кода 87

Совет 1: ничего не выделяйте 87

Совет 2: перемещайтесь на последнюю строку данных с конца рабочего

листа 88

Совет 3: используйте переменные 89

Совет 4: используйте одно выражение для копирования и вставки

данных 89

Совет 5: используйте конструкцию With...End With 90

Исправление и оптимизация автоматически сгенерированного

кода 90

Следующий шаг 93

Глава 3. Работа с диапазоном ячеек 95

Объект Range 95

Обращение к диапазону ячеек с помощью указания адреса его

верхнего левого и нижнего правого угла 96

Сокращенная форма обращения к диапазону ячеек 96

Именованные диапазоны ячеек 96

Page 9: ? Применение VBA и макросов в Microsoft® Excel

Содержание 9

Обращение к диапазону ячеек, расположенному на другом

рабочем листе 97

Обращение к диапазону ячеек с помощью указания его

относительного адреса 98

Обращение к диапазону ячеек с помощью свойства Cells 99

Использование свойства Cells в качестве параметра свойства Range 100

Обращение к диапазону ячеек с помощью свойства Offset 100

Изменение размера диапазона ячеек с помощью свойства Resize 101

Обращение к диапазону ячеек с помощью свойств Columns и Rows 102

Объединение диапазонов ячеек с помощью метода Union 103

Создание нового диапазона ячеек из пересекающихся диапазонов с

помощью метода Intersect 103

Проверка пустых ячеек с помощью функции IsEmpty 104

Обращение к диапазону ячеек с помощью свойства CurrentRegion 105

Обращение к диапазону несмежных ячеек с помощью коллекции

Areas 108

Следующий шаг 109

Глава 4. Функции, определенные пользователем 111

Создание функций, определенных пользователем 111

Наиболее распространенные задачи программирования в Excel 113

Вывод имени файла текущей рабочей книги в ячейке 113

Вывод полного имени файла текущей рабочей книги в ячейке 113

Как проверить, открыта ли рабочая книга 114

Проверка существования рабочего листа в открытой книге 114

Подсчет количества файлов рабочих книг в папке 115

Получение имени пользователя, зарегистрировавшегося в системе 116

Получение даты и времени последнего сохранения рабочей книги 117

Получение постоянного значения даты и времени 118

Проверка адреса электронной почты 118

Суммирование значений ячеек на основе цвета заливки 120

Получение имени и номера цвета заливки ячейки 121

Получение номера цвета текста в ячейке 124

Подсчет количества уникальных значений 125

Удаление повторяющихся значений из диапазона ячеек 125

Поиск первой непустой ячейки в диапазоне 128

Замена нескольких символов в строке 128

Извлечение чисел из смешанного текста 130

Преобразование номера недели в дату 130

Разбор строки с символамиYразделителями 131

Сортировка и конкатенация значений ячеек из заданного диапазона 132

Сортировка числовых и строковых значений 134

Поиск строки в диапазоне ячеек 135

Запись содержимого ячейки в обратном порядке 136

Поиск наибольших значений в диапазоне ячеек 137

Получение адреса гиперссылки 138

Page 10: ? Применение VBA и макросов в Microsoft® Excel

10 Содержание

Получение адреса столбца ячейки 138

Генерация постоянных случайных чисел 138

Использование структуры Select...Case 139

Следующий шаг 140

Глава 5. Циклы и управление выполнением кода 141

Цикл For...Next 141

Использование переменных в выражении For 144

Изменение шага в цикле For...Next 144

Досрочное завершение выполнения цикла 145

Вложение циклов 146

Циклы Do...Loop 147

Использование операторов While и Until 150

Цикл While...Wend 152

Цикл For Each...Next 152

Объектные переменные 152

Управление выполнением кода: использование конструкций

If...Then...Else и Select Case 155

Знакомство с конструкцией If...Then...Else 155

Условие 156

Конструкция If...Then...End If 156

Конструкция If...Then...Else...End If 156

Конструкция If...ElseIf...End If 157

Конструкция Select Case...End Select 157

Использование сложных выражений Case 158

Вложение выражений If 158

Следующий шаг 160

Глава 6. Стиль записи ссылок R1C1 161

Сравнение стилей записи ссылок A1 и R1C1 161

R1C1 — дела давно минувших дней? 162

R1C1 — сильные стороны 162

Использование стиля ссылок R1C1 в Excel 162

Чудесный мир формул Excel 163

Как “размножаются” формулы 163

Разоблачение 164

Ссылки в стиле R1C1 166

Относительные ссылки в стиле R1C1 166

Абсолютные ссылки в стиле R1C1 167

Смешанные ссылки в стиле R1C1 167

Обращение к строке или столбцу с помощью ссылок в стиле R1C1 168

Замена нескольких A1Yформул одной R1C1Yформулой 169

Тренируем память 170

Использование ссылок в стиле R1C1 при условном

форматировании ячеек 171

Задание условного форматирования с помощью пользовательского

интерфейса 171

Page 11: ? Применение VBA и макросов в Microsoft® Excel

Содержание 11

Задание условного форматирования с помощью VBA 172

Использование ссылок в стиле R1C1 при создании формулы

массива 174

Следующий шаг 175

Глава 7. Имена 177

Глобальные и локальные имена 177

Создание имен 179

Удаление имен 180

Типы имен 180

Имена формул 181

Имена строк 181

Имена чисел 182

Имена массивов 183

Зарезервированные имена 183

Скрытие имен 185

Проверка существования имени 185

Следующий шаг 187

Глава 8. События 189

Использование событий 190

Параметры событий 190

Запрет обработки событий 191

События рабочей книги 191

Событие Workbook_Activate() 192

Событие Workbook_Deactivate() 192

Событие Workbook_Open() 192

Событие Workbook_BeforeSave(ByVal SaveAsUI As Boolean,

Cancel As Boolean) 193

Событие Workbook_BeforePrint(Cancel As Boolean) 193

Событие Workbook_BeforeClose(Cancel As Boolean) 194

Событие Workbook_NewSheet(ByVal Sh As Object) 195

Событие Workbook_WindowResize(ByVal Wn As Window) 195

Событие Workbook_WindowActivate(ByVal Wn As Window) 196

Событие Workbook_WindowDeactivate(ByVal Wn As Window) 196

Событие Workbook_AddinInstall() 196

Событие Workbook_AddinUninstall() 196

Событие Workbook_SheetActivate(ByVal Sh As Object) 197

Событие Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal

Target As Range, Cancel As Boolean) 197

Событие Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal

Target As Range, Cancel As Boolean) 197

Событие Workbook_SheetCalculate(ByVal Sh As Object) 197

Событие Workbook_SheetChange(ByVal Sh As Object, ByVal Target As

Range) 198

Событие Workbook_SheetDeactivate(ByVal Sh As Object) 198

Page 12: ? Применение VBA и макросов в Microsoft® Excel

12 Содержание

Событие Workbook_SheetFollowHyperlink(ByVal Sh As Object, ByVal

Target As Hyperlink) 198

Событие Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal

Target As Range) 198

События рабочего листа 199

Событие Worksheet_Activate() 199

Событие Worksheet_Deactivate() 199

Событие Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As

Boolean) 199

Событие Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As

Boolean) 200

Событие Worksheet_Calculate() 200

Событие Worksheet_Change(ByVal Target As Range) 202

Событие Worksheet_SelectionChange(ByVal Target As Range) 203

Событие Worksheet_FollowHyperlink(ByVal Target As Hyperlink) 203

События листа диаграммы 204

Встроенные диаграммы 204

Событие Chart_Activate() 205

Событие Chart_BeforeDoubleClick(ByVal ElementID As Long, ByVal Arg1

As Long, ByVal Arg2 As Long, Cancel As Boolean) 205

Событие Chart_BeforeRightClick(Cancel As Boolean) 206

Событие Chart_Calculate() 206

Событие Chart_Deactivate() 206

Событие Chart_DragOver() 206

Событие Chart_DragPlot() 206

Событие Chart_MouseDown(ByVal Button As Long, ByVal Shift As Long,

ByVal x As Long, ByVal y As Long) 206

Событие Chart_MouseMove(ByVal Button As Long, ByVal Shift As Long,

ByVal x As Long, ByVal y As Long) 207

Событие Chart_MouseUp(ByVal Button As Long, ByVal Shift As Long,

ByVal x As Long, ByVal y As Long) 207

Событие Chart_Resize() 207

Событие Chart_Select(ByVal ElementID As Long, ByVal Arg1 As Long,

ByVal Arg2 As Long) 207

Событие Chart_SeriesChange(ByVal SeriesIndex As Long, ByVal PointIndex

As Long) 208

События приложения 208

Событие AppEvent_NewWorkbook(ByVal Wb As Workbook) 210

Событие AppEvent_SheetActivate(ByVal Sh As Object) 210

Событие AppEvent_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal

Target As Range, Cancel As Boolean) 210

Событие AppEvent_SheetBeforeRightClick(ByVal Sh As Object, ByVal

Target As Range, Cancel As Boolean) 210

Событие AppEvent_SheetCalculate(ByVal Sh As Object) 211

Событие AppEvent_SheetChange(ByVal Sh As Object, ByVal Target As

Range) 211

Событие AppEvent_SheetDeactivate(ByVal Sh As Object) 211

Page 13: ? Применение VBA и макросов в Microsoft® Excel

Содержание 13

Событие AppEvent_SheetFollowHyperlink(ByVal Sh As Object, ByVal

Target As Hyperlink) 211

Событие AppEvent_SheetSelectionChange(ByVal Sh As Object, ByVal Target

As Range) 211

Событие AppEvent_WindowActivate(ByVal Wb As Workbook, ByVal Wn As

Window) 211

Событие AppEvent_WindowDeactivate(ByVal Wb As Workbook, ByVal Wn

As Window) 211

Событие AppEvent_WindowResize(ByVal Wb As Workbook, ByVal Wn As

Window) 212

Событие AppEvent_WorkbookActivate(ByVal Wb As Workbook) 212

Событие AppEvent_WorkbookAddinInstall(ByVal Wb As Workbook) 212

Событие AppEvent_WorkbookAddinUninstall(ByVal Wb As Workbook) 212

Событие AppEvent_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel

As Boolean) 213

Событие AppEvent_WorkbookBeforePrint(ByVal Wb As Workbook, Cancel

As Boolean) 213

Событие AppEvent_WorkbookBeforeSave(ByVal Wb As Workbook, ByVal

SaveAsUI As Boolean, Cancel As Boolean) 213

Событие AppEvent_WorkbookDeactivate(ByVal Wb As Workbook) 213

Событие AppEvent_WorkbookNewSheet(ByVal Wb As Workbook, By Val Sh

As Object) 213

Событие AppEvent_WorkbookOpen(ByVal Wb As Workbook) 214

Следующий шаг 214

Глава 9. Введение в пользовательские формы 215

Способы взаимодействия с пользователем 215

Окно ввода 215

Окно сообщения 216

Создание пользовательской формы 216

Вызов и скрытие пользовательской формы 218

Программирование пользовательской формы 218

Основные элементы управления формы 220

Использование списков и комбинированных списков 221

Использование переключателей 222

Использование изображений 223

Использование счетчиков 224

Использование вкладок для объединения форм 225

Проверка ввода обязательных данных 225

Закрытие формы 225

Следующий шаг 226

Часть II. Автоматизация Excel 227

Глава 10. Диаграммы 229

Встроенные диаграммы и диаграммы, расположенные

на отдельном листе 229

Page 14: ? Применение VBA и макросов в Microsoft® Excel

14 Содержание

Встроенные диаграммы и контейнер ChartObject 230

Диаграммы, расположенные на отдельном листе 232

Создание диаграмм с помощью VBA 232

Изменение размещения диаграммы 235

Стандартный тип диаграмм 235

Использование объектных переменных для упрощения кода 236

“Анатомия” диаграммы 237

Область диаграммы (ChartArea) 237

Область построения диаграммы (PlotArea) 240

Ряды данных (Series) 242

Оси диаграммы (Axis) 243

Линии сетки (HasMajorGridlines и HasMinorGridlines) 245

Подписи данных (DataLabels и DataLabel) 246

Название диаграммы, легенда и таблица данных (ChartTitle, HasLegend

и HasDataTable) 247

Линии тренда и полосы погрешности (Trendlines и ErrorBar) 248

Типы диаграмм 251

Параметры трехмерных и круговых диаграмм 256

Параметры трехмерных диаграмм 256

Параметры круговых диаграмм 258

Интерактивные диаграммы 260

События диаграмм 260

Экспорт диаграммы в файл изображения 261

Удивительные возможности точечных диаграмм 262

Создание нестандартных диаграмм 262

Круговая пузырьковая диаграмма 262

Диаграмма с точками данных в виде спидометров 264

Диаграмма кривой предложения 264

Иерархическая кольцевая диаграмма 265

Следующий шаг 266

Глава 11. Анализ данных с помощью расширенного фильтра 267

Преимущества VBA перед пользовательским интерфейсом Excel 267

Использование расширенного фильтра для отбора уникальных

значений из заданного диапазона 268

Отбор уникальных значений из заданного столбца с помощью

пользовательского интерфейса 268

Отбор уникальных значений из заданного столбца с помощью VBA 271

Отбор уникальных значений из комбинации нескольких столбцов с

помощью VBA 275

Использование расширенного фильтра с указанием условия отбора

данных 276

Объединение нескольких условий с помощью

логической операции “ИЛИ” 278

Объединение нескольких условий с помощью логической операции “И” 278

Дополнительные аспекты объединения условий с помощью

логической операции “ИЛИ” 279

Page 15: ? Применение VBA и макросов в Microsoft® Excel

Содержание 15

Задание условия отбора с помощью формулы 279

Отбор пустого множества записей 286

Фильтрация диапазона исходных данных “на месте” 287

Отбор пустого множества записей 288

Отображение записей, скрытых в результате фильтрации “на месте” 288

Отбор только уникальных записей при фильтрации “на месте” 288

Использование расширенного фильтра для копирования всех

записей, удовлетворяющих заданному условию 289

Копирование всех столбцов исходного диапазона данных 289

Копирование и переупорядочивание подмножества столбцов исходного

диапазона данных 290

Автофильтр 297

Следующий шаг 298

Глава 12. Сводные таблицы 299

Сводные таблицы в различных версиях Excel 299

Создание сводных таблиц с помощью пользовательского

интерфейса Excel 300

Создание сводных таблиц с помощью VBA 303

Подсчет суммы чисел вместо количества значений 305

Перемещение или изменение части сводной таблицы 306

Определение размера сводной таблицы 307

Создание отчета о структуре спроса на товары 309

Заполнение значениями пустых ячеек в области данных 312

Изменение порядка сортировки списка заказчиков 313

Изменение порядка следования столбцов сводной таблицы вручную 314

Изменение формата отображения числовых значений 315

Запрет автоматического добавления промежуточных итогов 315

Запрет подсчета общей суммы по столбцам 316

Создание отчета о структуре спроса на товары:

завершающая стадия 317

Создание новой рабочей книги 318

Копирование содержимого сводной таблицы 318

Улучшение внешнего вида отчета 319

Стилевое форматирование отчета 321

Добавление промежуточных итогов 321

Результирующий код 323

Создание отчета о прибыльности товаров 326

Определение вычисляемых полей области данных 328

“Подводные камни” вычисляемых элементов 331

Суммирование значений полей области данных сводной таблицы

путем группирования 332

Группирование дат по неделям 336

Определение сроков выполнения заказов 338

Дополнительные возможности сводных таблиц 340

Отображение лучшей десятки заказчиков 340

Использование сводной таблицы для фильтрации исходных данных 344

Page 16: ? Применение VBA и макросов в Microsoft® Excel

16 Содержание

Использование полей области страницы сводной таблицы 346

Фильтрация элементов полей сводной таблицы вручную 351

Сумма, среднее, количество, минимум, максимум и др. 355

Дополнительные вычисления в полях области данных сводной

таблицы 356

Доля от общей суммы 358

Приведенное отличие от значения предыдущего элемента поля 358

Приведенное отличие от значения заданного элемента поля 359

Нарастающий итог 359

Следующий шаг 361

Глава 13. Excel всемогущий 363

Расширение возможностей Excel с помощью VBA 363

Условное форматирование с более чем тремя условиями 364

Расширенный фильтр с более чем двумя условиями 364

Файловые операции 365

Поиск файлов 366

Удаление рабочей книги после определенной даты 367

Создание команды меню “Закрыть и удалить” 368

Импорт CSVYфайлов 370

Считывание текстового файла в память и его последующий анализ 370

Объединение и разделение рабочих книг 372

Сохранение листов рабочей книги в виде отдельных рабочих книг 372

Объединение нескольких рабочих книг в одну 372

Фильтрация данных с последующим копированием полученного

результата в отдельные рабочие листы 373

Экспорт данных в Word 375

Работа с примечаниями 376

Вывод примечаний 376

Изменение размера области примечания 377

Изменение размера области примечания с помощью центрирования 378

Размещение диаграммы в примечании 379

Замечательные возможности Excel VBA 381

Выделение ячейки с помощью условного форматирования 381

Выделение ячейки без применения условного форматирования 382

Транспонирование данных 383

Выделение и отмена выделения несмежных ячеек 384

VBA для профессионалов 386

Установка параметров страницы 386

Вычисление времени выполнения кода макроса 389

Запрет/разрешение выполнения операций вырезания,

копирования и вставки 390

Определение порядка сортировки 392

Создание индикатора хода процесса 394

Создание защищенного поля для ввода пароля 395

Изменение регистра текста 397

Обработка события удаления строки или столбца 398

Поиск заданного текста с помощью свойства SpecialCells 399

Page 17: ? Применение VBA и макросов в Microsoft® Excel

Содержание 17

Условное удаление строк 400

Сокрытие строки формул 401

На закуску 402

Извлечение информации о курсах акций из Internet 402

Вставка программного кода во вновь созданную рабочую книгу 404

Следующий шаг 405

Глава 14. Взаимодействие с Internet 407

Извлечение данных из Internet 407

Создание WebYзапроса с помощью пользовательского интерфейса Excel 407

Обновление существующего WebYзапроса с помощью VBA 409

Создание WebYзапроса с помощью VBA 410

Извлечение данных из Internet в режиме реального времени 413

Анализ данных, извлеченных из Internet 414

Условия выполнения метода OnTime 414

Определение временного окна для выполнения макроса 415

Отмена назначенного задания 415

Отмена всех назначенных заданий 416

Выполнение макроса по прошествии заданного периода времени 416

Периодическое выполнение макроса через определенные

промежутки времени 416

Размещение данных на WebYстранице 418

Создание WebYстраниц с помощью VBA 420

Применение Excel в качестве системы управления содержимым 421

Загрузка WebYстраницы на FTPYсервер 425

Следующий шаг 425

Глава 15. Поддержка XML в профессиональном выпуске Excel 2003 427

Введение в XML 427

Правила XML 428

Универсальный формат файлов 429

XML набирает обороты 429

Схемы и сопоставления XML 429

Сохранение и считывание содержимого рабочей книги Excel в

формате XML 431

Следующий шаг 438

Глава 16. Автоматизация Word 439

Раннее связывание 439

Ошибка компиляции: отсутствие библиотеки 442

Позднее связывание 442

Работа с объектами 443

Ключевое слово New 443

Функция CreateObject 444

Функция GetObject 444

Объекты Word 445

Объект Document 446

Page 18: ? Применение VBA и макросов в Microsoft® Excel

18 Содержание

Объект Selection 448

Объект Range 449

Закладки 453

Следующий шаг 460

Часть III. Удивительные возможности Visual Basicfor Applications 461

Глава 17. Массивы 463

Объявление массива 463

Многомерные массивы 464

Заполнение массива 464

Манипулирование элементами массива 466

Еще одно преимущество массивов 467

Динамические массивы 469

Передача массива в качестве параметра 470

Следующий шаг 471

Глава 18. Работа с текстовыми файлами 473

Импорт данных из текстового файла 473

Импорт текстовых файлов, содержащих менее 65 536 записей 474

Импорт текстовых файлов, содержащих более 65 536 записей 482

Экспорт данных в текстовый файл 486

Следующий шаг 487

Глава 19. Использование Microsoft Access 489

ADO и DAO 490

Объекты ADO 492

Добавление записи в таблицу Access 493

Извлечение записей из таблицы Access 494

Обновление записей таблицы Access 496

Удаление записей таблицы Access 499

Создание итоговых запросов 499

Несколько полезных макросов 500

Проверка существования таблицы в базе данных Access 500

Проверка существования поля в таблице базы данных Access 501

Добавление таблицы в базу данных Access 502

Добавление поля в таблицу базы данных Access 503

Следующий шаг 503

Глава 20. Создание пользовательских объектов, типов и коллекций 505

Создание модуля класса 506

Обработка событий уровня приложения и встроенной диаграммы 506

События уровня приложения 507

События встроенной диаграммы 509

Page 19: ? Применение VBA и макросов в Microsoft® Excel

Содержание 19

Создание пользовательского объекта 510

Применение пользовательского объекта на практике 511

Использование выражений Property Let и Property Get 513

Коллекции 515

Создание коллекции в стандартном модуле 515

Создание коллекции в модуле класса 516

Создание пользовательских типов 520

Следующий шаг 524

Глава 21. Пользовательские формы //// профессиональный подход 525

Панель инструментов UserForm 525

Создание коллекций элементов управления формы 526

Дополнительные элементы управления формы 528

Переключатели 528

Набор вкладок 529

Поле ввода адреса диапазона ячеек 530

Немодальные формы 531

Гиперссылки в формах 531

Добавление элементов управления на форму во время выполнения

программного кода 532

Изменение размеров формы во время выполнения программного кода 534

Добавление элемента управления на форму во время выполнения

программного кода 534

Определение размера и положения элемента управления на форме во

время выполнения программного кода 535

Ограничения, связанные с добавлением элементов управления на форму

во время выполнения программного кода 535

Типы элементов управления 535

Добавление изображения на форму во время выполнения программного

кода 536

Результирующий код 537

Использование полосы прокрутки для выбора значений 539

Добавление подсказки к элементу управления 541

Использование сочетаний клавиш 541

Подсказка элемента управления 541

Порядок переноса фокуса 541

Изменение цвета фона активного элемента управления 542

Использование эффекта прозрачности формы 545

Следующий шаг 546

Глава 22. Интерфейс прикладного программирования (API) Windows 547

Знакомство с Windows API 547

Объявления Windows API 548

Использование объявлений Windows API 548

Примеры полезных объявлений Windows API 549

Определение имени компьютера 549

Page 20: ? Применение VBA и макросов в Microsoft® Excel

20 Содержание

Проверка возможности доступа к файлу 550

Определение разрешения экрана 550

Блокирование кнопки закрытия окна приложения 552

Блокирование кнопки закрытия окна формы 552

Часы 553

Создание гиперссылок 554

Воспроизведение звуковых файлов 555

Создание диалогового окна выбора файла 555

Дополнительные источники объявлений Windows API 559

Следующий шаг 559

Глава 23. Обработка ошибок 561

Отладка кода с помощью редактора VBA 561

Отладка кода пользовательской формы 562

Обработка ошибок с помощью выражения On Error GoTo 564

Использование нескольких обработчиков ошибок 565

Универсальные обработчики ошибок 566

Игнорирование ошибок 566

Игнорирование сообщений Excel 568

Извлечение пользы из ошибок 568

Общение с заказчиками 569

“Отложенные” ошибки 569

Ошибка времени выполнения 9: “Subscript out of range” 570

Ошибка времени выполнения 1004: “Method 'Range' of object '_Global'

failed” 571

Несовершенство защиты проекта VBA 572

Защита проекта VBA в различных версиях Excel 573

Совместимость различных версий Excel 573

Следующий шаг 574

Глава 24. Создание пользовательских меню и панелей инструментов 575

Создание пользовательского меню 575

Создание и удаление пользовательского меню 575

Добавление команд меню 577

Группирование команд меню 578

Создание подменю 579

Создание пользовательской панели инструментов 581

Создание и удаление пользовательской панели инструментов 582

Добавление кнопок на панель инструментов 582

Выбор значка кнопки панели инструментов 584

Добавление раскрывающегося списка на панель инструментов 584

Сохранение и восстановление координат панели инструментов 585

Другие способы запуска макросов 587

Запуск макроса с помощью сочетания клавиш 587

Запуск макроса с помощью кнопки 587

Запуск макроса с помощью элемента управления ActiveX 590

Следующий шаг 592

Page 21: ? Применение VBA и макросов в Microsoft® Excel

Содержание 21

Глава 25. Надстройки 593

Стандартные надстройки Excel 593

Преобразование рабочей книги Excel в надстройку 594

Преобразование рабочей книги Excel в надстройку с помощью

диалогового окна “Сохранение документа” (Save As) 594

Преобразование рабочей книги Excel в надстройку с помощью

редактора VBA 596

Использование надстроек 597

Безопасность стандартных надстроек Excel 598

Выгрузка надстроек 599

Удаление надстроек 599

Альтернативное решение: использование скрытой рабочей книги 599

Следующий шаг 601

Глава 26. Практикум: создание приложения Excel ‘‘с нуля’’ 603

О Тушаре Мехта 603

Постановка задачи 604

Решение 605

Реализация решения с помощью Excel и VBA 606

Этап 1а: нисходящее программирование 606

Этап 1б: создание ключевых компонентов 607

Этап 2а: нисходящее программирование 608

Этап 2б: создание ключевых компонентов 610

Этап 3а: нисходящее программирование 611

Этап 3б: создание ключевых компонентов 613

Резюме 614

Предметный указатель 615

Page 22: ? Применение VBA и макросов в Microsoft® Excel
Page 23: ? Применение VBA и макросов в Microsoft® Excel

Об авторахБилл Джелен, более известный под псевдонимом ‘‘Мистер Excel’’, YYYY рукоY

водитель популярнейшего WebYсайта MrExcel.com (свыше 10 млн. посещений

в год), а также автор многочисленных книг, посвященных Excel. Билл создает

решения, основанные на использовании Excel VBA, для сотен клиентов по

всему миру. До основания MrExcel.com Билл на протяжении 12 лет занимал

должность финансового аналитика в отделах финансов, маркетинга, бухгалY

терского учета и операций крупной корпорации. Билл проживает в окрестноY

стях города Акрон, штат Огайо, США, вместе со своей женой Мэри Эллен и

детьми Джошем и Зиком.

Трейси Сирстад работает программистом и консультантом в компании

Билла Джелена MrExcel Consulting. Трейси проживает в живописной местноY

сти Южной Дакоты вместе со своим мужем Джоном и собакой Генералом.

ПосвященияПосвящается Мэри Эллен Джелен.

Билл

Посвящается Джону Сирстаду, вера которого в меня помогает преодолеватьвсе трудности, встречающиеся на жизненном пути.

Трейси

БлагодарностиСпасибо Мале Сингху (Mala Singh) из XLSoft Consulting за помощь в написаY

нии главы 10; Тому Уртису (Tom Urtis) за техническое редактирование; Джерри

Колю (Jerry Kohl) за его великолепные идеи; Джанет Гарсиа (Jeanette Garcia),

Барбе Джелен (Barb Jelen), Дагу и Стейси Джеффериз за техническую помощь;

Зику, Джошу и Мэри Эллен Джелен за их терпение; Тому Мацешеку (Tom MaY

cioszek) за ‘‘дружескую’’ проверку; Чеду Ротшиллеру (Chad Rothschiller) из MiY

crosoft за неоценимую помощь в изучении Excel XML; Дейву Гейнеру (Dave

Gainer), Стиву Заске (Steve Zaske), Эрику Паттерсону (Eric Patterson) и Джо ЧиY

рилову (Joe Chirilov) из Microsoft; Лоретте Йейтс (Loretta Yates), Шону Диксону

(Sean Dixon), Марго Кэттс (Margo Catts), Энди Бистеру (Andy Beaster), Грегу

Виганду (Greg Wiegand), Эми Сорокас (Amy Sorokas), Ким Спилкер (Kim

Spilker), Эрике Миллен (Erika Millen), Кэти Бидуэл (Kathy Bidwell), Синди ТиY

терс (Cindy Teeters), Мишель Митчелл (Michelle Mitchell) и Гэри Адэру (Gary

Adair) из Pearson; Иване Тейлор (Ivana Taylor) за блестящий маркетинг; читатеY

лям MrExcel.com, нашим клиентам и всем MVP; Дэну Бриклину (Dan Bricklin),

Бобу Фрэнкстону (Bob Frankston) и Митчу Кейпору (Mitch Kapor) за создание

электронных таблиц; Уильяму Брауну (William Brown) из Waterside; Пэм Гензель

Page 24: ? Применение VBA и макросов в Microsoft® Excel

24 Благодарности

(Pam Gensel) за 1Yй урок по созданию макросов; Роберту Ф. Джелену (Robert

F. Jelen) за то, что он был первым поклонником моего таланта программиста;

Роберту К. Джелену (Robert K. Jelen) за вдохновение; Бонни Хильярд (Bonnie

Hilliard) за связь с общественностью; Лаурель Рииппу (Laurelle Riippa) из PW;

Лео Лапорте (Leo LaPorte) и Фон Луу (Fawn Luu) из TechTV; Дэну Пойнтеру

(Dan Poynter); Крейгу Кросмэну (Craig Crossman) из Computer America и УолтеY

ру Моссбергу (Walter Mossberg) из Wall Street Journal.

Билл

Спасибо Корту ЧиллдонуYХоффу (Cort ChilldonYHoff) за поддержку в трудY

ные минуты; Хуану Пабло Гонсалесу Руизу (Juan Pablo Gonzales Ruiz) за его

советы (в частности, касающиеся функций из главы 4); Даниелю Клэнну

(Daniel Klann), Деннису Валентайну (Dennis Wallentin), Ивану Ф. Моале (Ivan

F. Moala), Хуану Пабло Гонсалесу (Juan Pablo Gonzales), Масаре Каджи

(Masaru Kaji), Натану П. Оливеру (Nathan P. Oliver), Ричи Силлсу (Richie

Sills), Расселу Гауфу (Russell Hauf), Суату Мехмету Озгуру (Suat Mehmet

Ozgur), Тому Уртису (Tom Urtis), Томми Майлзу (Tommy Miles) и Вэю Цзянгу

(Wei Jiang) за их вклад в написание главы 13; Крису Лемэру (Chris Lemair) за

то, что он открыл для меня удивительный мир Excel и макросов, а также Энн

Трой (Anne Troy) за то, что она познакомила меня с Биллом.

Трейси

Page 25: ? Применение VBA и макросов в Microsoft® Excel

Ââåäåíèå

VBA — работана результат

Язык программирования Visual

Basic for Applications (VBA) позвоY

ляет существенно повысить произY

водительность труда пользователей

Microsoft Excel.

Не дожидаясь помощи от отдела

информационных технологий, польY

зователи Excel могут самостоятельно

создавать отчеты, необходимые для

выполнения своих повседневных

обязанностей. Это сулит как преY

имущества, так и недостатки. С одY

ной стороны, пользователи Excel

смогут повысить эффективность своеY

го труда. С другой, им придется раY

зобраться со всеми тонкостями исY

кусства создания макросов с помоY

щью Excel VBA.

Уверен, что в этот самый момент

вы или ктоYлибо из ваших коллег

все еще выполняете в Excel рутинY

ные операции, которые могут быть

автоматизированы с помощью VBA.

Случай, произошедший с Валери, —

весьма типичен для компаний, наY

считывающих 20 и более пользоватеY

лей Excel.

VBA — работа на результат ......... 25Как организована эта книга ........27Для кого предназначена этакнига................................................. 28История развитияэлектронных таблиц и макросов ...................................... 29Будущее Excel и VBA ..................... 30Соглашения, принятыев этой книге...................................... 31Рассматриваемыеверсии Excel .................................... 32Программный код......................... 32Следующий шаг............................. 32

 ÝÒÎÌ ÂÂÅÄÅÍÈÈ...

Page 26: ? Применение VBA и макросов в Microsoft® Excel

26 Введение

Практикум

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

Прежде всего, Валери экспортировала главную бухгалтерскую книгу из ERP&системы в текстовый файл с разделителями&запятыми (CSV). Затем полученныйCSV&файл был импортирован в Excel.

Создание отчета оказалось делом не из легких. Некоторые счета необходимо былоклассифицировать как расходы, некоторые — полностью исключить из отчета.Шаг за шагом, Валери внесла все требуемые корректировки. Для получения пер&вой части отчета она создала сводную таблицу и скопировала итоговые значенияна новый рабочий лист. Аналогичным образом были получены остальные частиотчета. После трех часов кропотливого труда финансовый отчет был готов.

Звездный часВалери передала отчет своему начальнику, который уже отчаялся получить егов срок. Она тут же стала “героем дня” и пребывала на седьмом небе от счастья.

Неожиданный поворот событийНа следующий день состоялось ежемесячное собрание руководства корпорации, пол&ноценно подготовиться к которому смог лишь начальник финансового отдела. Он эф&фектно положил на стол отчет, чем привел в замешательство всех присутствующих. По&сле того как начальник Валери рассказал о происхождении отчета, президент корпора&ции попросил его помочь подготовить отчеты для всех остальных отделов.

Тяжкое бремя славыКорпорация, в которой работает Валери, насчитывает 46 отделов. Подготовка фи&нансового отчета для каждого отдела подразумевает импортирование данных изERP&системы, удаление определенных счетов, создание нескольких сводных таб&лиц и комбинацию полученных итоговых результатов. На подготовку первого от&чета Валери потратила 3 часа. Она подсчитала, что с учетом полученного опытасможет создать 46 отчетов не менее чем за 40 часов. Валери пришла в отчаяние.

VBA спешит на помощьК счастью, Валери решила поделиться своими заботами с возглавляемой мноюкомпанией MrExcel Consulting. Менее чем за неделю я создал набор VBA&макросов, реализующих действия, необходимые для подготовки отчета, — импортданных, удаление счетов, создание сводных таблиц, объединение полученныхитоговых сведений и стилевое форматирование отчета. Благодаря VBA 40&часовой процесс создания отчетов вручную был сведен к двум щелчкам мыши ичетырем минутам ожидания.

Page 27: ? Применение VBA и макросов в Microsoft® Excel

Введение 27

Как организована эта книгаЭта книга состоит из трех частей. Ее цель — научить читателя создавать

макросы VBA для автоматизации выполнения рутинных задач в Excel.

Часть I, “Первые шаги”Глава 1, ‘‘Excel и VBA YYYY гремучая смесь’’, акцентирует внимание на фундаменY

тальной проблеме средства записи макросов Excel — средство записи макросов не

работает. В главе 2, ‘‘Знакомство с Visual Basic for Applications’’, рассматриваются

основы синтаксиса языка программирования Visual Basic for Applications. Глава 3,

‘‘Работа с диапазоном ячеек’’, посвящена работе с диапазонами ячеек.

В главе 4, ‘‘Функции, определенные пользователем’’, рассматривается созY

дание функций, определенных пользователем, а также приводятся примеры

решения 25 наиболее распространенных задач, встречающихся при повсеY

дневном программировании в Excel.

Глава 5, ‘‘Циклы и управление выполнением кода’’, посвящена циклам —

фундаментальному компоненту любого языка программирования. РазрабатыY

вая решение для Валери, мы создали код, подготавливающий отчет для одного

отдела, а затем поместили его в цикл с 46 итерациями.

В главе 6, ‘‘Стиль записи ссылок R1C1’’, описывается стиль записи ссылок

R1C1, а в главе 7, ‘‘Имена’’, — использование имен. Глава 8, ‘‘События’’, поY

священа событиям, а глава 9, ‘‘Введение в пользовательские формы’’, — польY

зовательским формам.

Часть II, “Автоматизация Excel”В главе 10, ‘‘Диаграммы’’, рассматривается использование VBA при работе

с диаграммами. Глава 11, ‘‘Анализ данных с помощью расширенного фильтY

ра’’, посвящена анализу данных с помощью расширенного фильтра, а глаY

ва 12, ‘‘Сводные таблицы’’, — работе со сводными таблицами. В комбинации

с VBA диаграммы, расширенный фильтр и сводные таблицы образуют мощY

ную основу для создания всевозможных отчетов.

В главе 13, ‘‘Excel всемогущий’’, рассматриваются распространенные задаY

чи, встречающиеся при работе с Excel, и их решения с помощью VBA, предY

лагаемые опытными программистами со всех уголков мира.

Глава 14, ‘‘Взаимодействие с Internet’’, посвящена автоматизации WebYзаY

просов, глава 15, ‘‘Поддержка XML в профессиональном выпуске Excel 2003’’, —

работе с данными в формате XML, глава 16, ‘‘Автоматизация Word’’, — автоматиY

зации Microsoft Word.

Часть III, “Удивительные возможности Visual Basicfor Applications”

В главе 17, ‘‘Массивы’’, рассматриваются массивы. Основное предназнаY

чение массива заключается в упрощении обработки данных и повышении

Page 28: ? Применение VBA и макросов в Microsoft® Excel

28 Введение

скорости выполнения программного кода. Глава 18, ‘‘Работа с текстовыми файY

лами’’, посвящена работе с текстовыми файлами, а глава 19, ‘‘Использование

Microsoft Access’’, — использованию баз данных Microsoft Access. Применение

Excel в качестве пользовательского интерфейса, а MDBYфайла — в качестве

базы данных позволяет добиться оптимального использования возможностей

обеих программ.

В главе 20, ‘‘Создание пользовательских объектов, типов и коллекций’’, расY

сматривается создание модулей классов, предназначенных для размещения польY

зовательских объектов VBA. Глава 21, ‘‘Пользовательские формы YYYY профессиоY

нальный подход’’, посвящена сложным элементам управления, а также различY

ным приемам программирования пользовательских форм. В главе 22, ‘‘Интерфейс

прикладного программирования (API) Windows’’, рассматриваются основы исY

пользования функций интерфейса прикладного программирования (API) WinY

dows. Глава 23, ‘‘Обработка ошибок’’, посвящена обработке ошибок, глава 24,

‘‘Создание пользовательских меню и панелей инструментов’’, — созданию польY

зовательских меню и панелей инструментов, глава 25, ‘‘Надстройки’’, — применеY

нию надстроек. Наконец, глава 26, ‘‘Практикум: создание приложения Excel

‘‘с нуля’’, представляет собой практикум, демонстрирующий процесс создания

приложения Excel ‘‘с нуля’’.

Для кого предназначена эта книгаНа мероприятии, посвященном выходу на рынок пакета приложений MiY

crosoft Office 2003, корпорация Microsoft огласила результаты исследования,

согласно которым среднестатистический пользователь применяет только 10%

заложенных в Office возможностей. Эта книга предназначена для опытных

пользователей Excel. Опрос, проведенный среди 2000 посетителей WebYсайта

MrExcel.com, показал, что 42% опытных пользователей Excel применяют в поY

вседневной работе все наиболее эффективные средства этого приложения.

Компания MrExcel Consulting часто устраивает семинары для бухгалтеров. Как

правило, все они работают с Excel по 30YY40 часов в неделю. Практически на

каждом семинаре я демонстрирую слушателям возможности Excel, о которых

они ранее и не подозревали, и тем не менее практически на каждом семинаре

находится слушатель, который превосходит меня в знании того или иного

средства Excel. Что я хочу этим сказать? Вероятно, читатель этой книги велиY

колепно разбирается в Excel. Несмотря на это, я предполагаю, что материал

каждой главы незнаком в полном объеме для 58% опытных пользователей ExY

cel. Прежде чем продемонстрировать решение той или иной задачи с помоY

щью VBA, я кратко остановлюсь на ее выполнении с помощью пользовательY

ского интерфейса Excel.

Page 29: ? Применение VBA и макросов в Microsoft® Excel

Введение 29

История развития электронныхтаблиц и макросов

Вплоть до 1978 года каждый бухгалтер применял для создания отчета буY

магу формата ‘‘гроссбух’’, механический карандаш и ластик. Сведения о дневY

ном обороте записывались от руки, а промежуточный итог подсчитывался

с помощью счетной машины. Ошибка в расчетах или исходных данных стоила

многих часов работы с ластиком, счетной машиной и карандашом.

В 1979 году Дэн Бриклин (Dan Bricklin) и Боб Фрэнкстон (Bob Frankston)

(рис. 1) в буквальном смысле изменили мир. Они создали первую электронY

ную таблицу, предназначенную для выполнения на компьютерах Apple II, и

назвали ее VisiCalc (сокращение от англ. ‘‘visual calculator’’ — визуальный

калькулятор). Вскоре программа VisiCalc была перенесена на несколько разY

личных платформ, включая IBM PC. В 1981 году была выпущена расширенная

версия VisiCalc, предназначенная для выполнения на компьютерах Apple III и

поддерживающая макросы командной строки. Проект VisiCalc прекратил свое

существование в 1985 году в результате судебной тяжбы.

Рис. 1. Дэн Бриклин и Боб Фрэнкстон

В 1983 году Митч Кейпор (Mitch Kapor) создал программу Lotus 1Y2Y3.

По своим функциональным возможностям Lotus 1Y2Y3, изначально разработанY

ная для выполнения под управлением операционной системы DOS, намного

превзошла VisiCalc. В первый год объем продаж Lotus 1Y2Y3 достиг впечатляюY

щей цифры в 53 млн долларов. Вплоть до середины 90Yх годов Lotus 1Y2Y3 заниY

мала лидирующее положение на рынке программ для работы с электронными

Page 30: ? Применение VBA и макросов в Microsoft® Excel

30 Введение

таблицами. Несмотря на наличие конкурентов (Quattro, Multiplan и др.), Lotus

1Y2Y3 ‘‘деYфакто’’ оставалась стандартным инструментом бухгалтерского учета.

1985 год был ознаменован появлением на свет второго выпуска Lotus 1Y2Y3,

поддерживающего 8192 строки и 256 столбцов — более 2 млн ячеек! Кроме того,

пользователю была предоставлена возможность записывать простые макросы.

В 1990 году я был на 100% уверен в незыблемости позиций Lotus 1Y2Y3 на рынке

программного обеспечения для работы с электронными таблицами.

В начале 90Yх годов была выпущена версия Lotus 1Y2Y3 для операционной

системы CP/M. В то же самое время Microsoft направила усилия на улучшение

собственного продукта для работы с электронными таблицами — Excel. ПроY

грамма Excel 3.0, выпущенная в 1990 году, существенно проигрывала Lotus

1Y2Y3. Тем не менее, Microsoft продолжала упорствовать, выпуская новую,

улучшенную версию Excel каждые 1YY2 года. Excel 4, выпущенная в 1992 году,

уже пользовалась популярностью и предлагала возможность создавать макроY

сы с помощью языка XLM. Excel 5, выпущенная в 1993 году, поддерживала

создание нескольких рабочих листов в пределах одной рабочей книги,

а также запись макросов с помощью нового языка программирования —

VBA. Благодаря наличию обратной совместимости с Lotus 1Y2Y3 продажи

Excel стали стремительно возрастать. Середину 90Yх годов прошлого столеY

тия можно без преувеличения назвать ‘‘золотой эрой’’ в развитии Excel.

В Excel 95 и Excel 97 были представлены новые функциональные средства,

такие как сводные таблицы, автофильтр и автоматическое вычисление проY

межуточных итогов. Кроме того, в Excel 97 появилась новая среда разработY

ки VBA. Доминированию Lotus 1Y2Y3 на рынке программ для работы с элекY

тронными таблицами был положен конец. На момент написания этой книги

гремучая смесь в виде Excel и VBA прочно завоевала сердца более чем

400 млн пользователей по всему миру.

Будущее Excel и VBAС каждым новым выпуском программа для работы с электронными таблиY

цами StarOffice Calc приближается по предлагаемым возможностям к Excel.

Один из наиболее существенных недостатков пакета StarOffice заключается

в отсутствии поддержки VBA, равно как и любого другого языка создания

макросов. Этот факт позволяет не рассматривать StarOffice Calc в качестве

серьезного конкурента Excel.

Наверняка многие слышали о том, что Microsoft собирается отказаться от

VBA. На самом деле это маловероятно. По прошествии более чем 10 лет с моY

мента появления VBA Microsoft все еще поддерживает макросы XLM (язык

макросов, появившийся в Excel 4). К тому же Microsoft официально заявила о

поддержке VBA в следующей версии Excel. Учитывая, что большинство польY

зователей приобретают каждую вторую версию Office, VBA будет актуален по

меньшей мере до 2009 года.

Page 31: ? Применение VBA и макросов в Microsoft® Excel

Введение 31

Наконец, с точки зрения маркетинга было бы нелепо отказываться от VBA

как от ключевого компонента, обеспечивающего Excel тотальное преимущестY

во над StarOffice Calc.

В октябре 2003 года корпорация Microsoft официально объявила о новой

инициативе, направленной на повышение безопасности предлагаемых MiY

crosoft решений. Это заявление имеет весьма серьезное значение, поскольку

печально известный вирус Melissa использовал для своего распространения

макросы VBA текстового редактора Word. Пресса и власть имущие отреагироY

вали мгновенно, поместив VBA в список ‘‘вымирающих’’ технологий. Если

безопасность приложений пакета Office будет оставаться под угрозой, MicroY

soft может быть вынуждена отказаться от VBA.

Одной из отличительных особенностей пакета Office 2003 является подY

держка языка программирования Visual Basic .NET. Язык Visual Basic 6 позвоY

лял автоматизировать любую задачу в Excel XP с помощью VBA. В Excel 2003

некоторые задачи, такие как создание смартYдокумента или размещение соY

держимого на панели Справочные материалы (Research Pane), можно автоY

матизировать только из среды .NET.

Учитывая вопросы безопасности, возникающие при использовании VBA,

Microsoft может заменить его набором инструментов .NET Tools for Office. Это

было бы роковой ошибкой. На текущий момент свыше 400 млн пользователей

Office могут приобрести книгу, подобную этой, в течении недели изучить осноY

вы создания макросов и начать разрабатывать собственные решения с помощью

VBA. Производительность труда ‘‘белых воротничков’’ может существенно возY

расти, а их зависимость от отдела информационных технологий — уменьшитьY

ся. Если Microsoft заменит VBA набором инструментов .NET Tools for Office, коY

нечный пользователь будет лишен возможности создавать макросы с помощью

Excel. Кроме того, это нивелирует преимущество Excel перед конкурирующим

продуктом StarOffice Calc, поддержка языка создания макросов в котором должY

на появиться к 2007 году. Таким образом, инициатива по повышению безопасY

ности приложений пакета Office может обернуться для Microsoft утратой лидиY

рующих позиций на рынке программ для работы с электронными таблицами.

Тем не менее, я уверен, что VBA останется с нами по крайней мере до конY

ца этого десятилетия. К тому же навыки создания макросов с помощью Excel

VBA не утратят своей актуальности в результате перехода на среду .NET,

а синтаксис VBA не так уж сильно отличается от синтаксиса Visual Basic .NET.

Соглашения, принятые в этой книгеВ этой книге приняты следующие обозначения.

Курсив используется для выделения терминов, названий WebYсайтов,

а также акцентирования внимания читателя.

Моноширинным шрифтом выделяется код VBA, заголовки столбцов,

ссылки, формулы, имена макросов, модулей, функций, процедур,

Page 32: ? Применение VBA и макросов в Microsoft® Excel

32 Введение

переменных, констант, объектов, методов, свойств, файлов, адреY

сов URL и пр.

Для выделения названий элементов пользовательского интерфейса

применяется следующий шрифт: Меню.

Вдобавок к указанным обозначениям, каждая глава книги содержит специY

альные фрагменты текста: ‘‘Практикум’’, ‘‘На заметку’’, ‘‘Совет’’ и ‘‘Внимание’’.

‘‘Практикум’’ содержит примеры решений реальных задач с использованием

средств, описываемых в текущей главе.

На заметку Так помечается информация, которая не относится к основной теме главы, однакоявляется весьма интересной и полезной.

Совет В этом фрагменте содержатся методы и приемы, позволяющие сэкономить времяи усилия, которые потребуются для решения той или иной задачи.

Внимание Будьте осторожны, если встретите такой фрагмент. Приводящиеся в нем сведенияпомогут вам избежать ошибок, а также сберечь время и нервы.

Рассматриваемые версии ExcelНа момент написания этой книги текущей версией Excel была версия ExY

cel 2003. За исключением главы 15, ‘‘Поддержка XML в профессиональном

выпуске Excel 2003’’, большая часть приведенного в книге программного кода

совместима с Excel 2002 и Excel 2000. Более подробно о совместимости разY

личных версий Excel рассказывается в главе 23, ‘‘Обработка ошибок’’.

Программный кодПрилагаемый к книге программный код включает все рассматриваемые в

ней примеры. Его можно загрузить по адресу:

http://www.williamspublishing.com/Books/5-8459-0882-5.html.

(Чтобы загрузить код, прилагающийся к англоязычному изданию этой книги, поY

сетите WebYстраницу по адресу: http://www.mrexcel.com/getcode.html.)

Следующий шагВ главе 1, ‘‘Excel и VBA YYYY гремучая смесь’’, рассматривается редактор ViY

sual Basic и средство записи макросов Excel.

Page 33: ? Применение VBA и макросов в Microsoft® Excel

Введение 33

Ждем ваших отзывов!Вы, читатель этой книги, и есть главный ее критик и комментатор. Мы цеY

ним ваше мнение и хотим знать, что было сделано нами правильно, что можY

но было сделать лучше и что еще вы хотели бы увидеть изданным нами. Нам

интересно услышать и любые другие замечания, которые вам хотелось бы выY

сказать в наш адрес.

Мы ждем ваших комментариев и надеемся на них. Вы можете прислать нам

бумажное или электронное письмо, либо просто посетить наш WebYсервер и

оставить свои замечания там. Одним словом, любым удобным для вас спосоY

бом дайте нам знать, нравится или нет вам эта книга, а также выскажите свое

мнение о том, как сделать наши книги более интересными для вас.

Посылая письмо или сообщение, не забудьте указать название книги и ее

авторов, а также ваш обратный адрес. Мы внимательно ознакомимся с вашим

мнением и обязательно учтем его при отборе и подготовке к изданию послеY

дующих книг. Наши координаты:

EYmail: [email protected]

WWW: http://www.williamspublishing.com

Адреса для писем:

из России: 115419, Москва, а/я 783

из Украины: 03150, Киев, а/я 152

Page 34: ? Применение VBA и макросов в Microsoft® Excel
Page 35: ? Применение VBA и макросов в Microsoft® Excel

IЧасть I

Первые шаги

1. Excel и VBA — гремучая смесь...............................................37

2. Знакомство с Visual Basic for Applications......................... 59

3. Работа с диапазоном ячеек ................................................. 95

4. Функции, определенные пользователем........................111

5. Циклы и управление выполнением кода........................ 141

6. Стиль записи ссылок R1C1.................................................... 161

7. Имена ....................................................................................... 177

8. События ...................................................................................189

9. Введение в пользовательские формы .............................215

Page 36: ? Применение VBA и макросов в Microsoft® Excel
Page 37: ? Применение VBA и макросов в Microsoft® Excel

1Excel всемогущий ...........................37Камни преткновения.....................37Панель инструментов“Visual Basic” ...................................39Безопасность макросов ............... 40Запись, хранение ивыполнение макросов ..................42Выполнение макроса ....................43Редактор Visual Basic .....................45Изучение кода макроса................50Непредвиденные результаты .....52Отчаяние ..........................................57Следующий шаг..............................57

Глава 1

Excel è VBA —ãðåìó÷àÿ ñìåñü

Excel всемогущий Сочетание языка программироваY

ния Visual Basic for Applications (VBA)

и Microsoft Excel таит в себе огромY

ные возможности. Удивительно, но об

этом задумывались лишь немногие из

почти что 400 миллионов пользоватеY

лей Microsoft Office. С помощью VBA

можно существенно упростить выY

полнение практически любой задачи в

Excel. К примеру, создание целого воY

роха квартальных диаграмм может

быть сведено всего лишь к нескольY

ким щелчкам мыши.

Камни преткновения Чтобы научиться программировать

с помощью VBA, вам придется преY

одолеть два барьера — несовершенное

средство записи макросов Excel и

чрезвычайно запутанный синтаксис

языка программирования VBA.

Средство записи макросовне работает!

С середины 90Yх годов прошлого

столетия корпорация Microsoft начаY

ла доминировать на рынке программ

для создания электронных таблиц.

Несмотря на то что в части работы с

электронными таблицами продукт

Microsoft оказался действительно

очень удачным (приверженцы Lotus

Page 38: ? Применение VBA и макросов в Microsoft® Excel

38 Часть I Первые шаги

1Y2Y3 быстро научились с ним работать), записать корректно работающий

макрос в Excel не удавалось практически никому. Неоспоримое преимущество

языка программирования Microsoft VBA перед языком макросов Lotus 1Y2Y3

нивелировалось низким качеством средства записи макросов.

Макрос, созданный накануне с помощью Lotus 1Y2Y3, прекрасно выполняY

ется и сегодня. Аналогичный макрос, созданный с помощью Microsoft Excel,

мог преподнести неприятный сюрприз. Многие из тех, кто пытался создать

свой первый макрос в Excel, приходили в отчаяние.

Visual Basic — это не BASIC

Код, сгенерированный в результате создания моего первого макроса, не

был похож ни на что, виденное мною ранее. Несмотря на то что я знал с полY

дюжины различных языков программирования, так называемый ‘‘Visual

Basic’’ оказался абсолютно неинтуитивным и даже приблизительно не напоY

минал тот BASIC, который я изучал в школе.

В 1995 году я уже в совершенстве освоил создание электронных таблиц.

И вот компания, в которой я работал, приняла решение о переходе с Lotus

1Y2Y3 на Excel. Без преувеличения, я оказался в сложном положении: с одной

стороны — средство записи макросов, которое не работает так, как надо,

с другой — язык программирования, в котором я ничего не понимал.

Эта книга задумывалась как пособие для тех, кто разбирается в создании

электронных таблиц больше, чем остальные 90% его сотрудников. Знание каY

когоYлибо языка программирования необязательно. Практика показывает, что

знание таких языков, как BASIC, может скорее навредить, чем принести пользу.

Нас должно объединять следующее: мы все пытались создать макрос в Excel и

остались недовольны полученным результатом.

Хорошие новости

Многочисленные недостатки средства записи макросов не являются неY

преодолимым препятствием на пути к постижению искусства программироY

вания в Excel. Далее в книге будет рассказано, как исправить ошибки автомаY

тически сгенерированного кода, а также как прочитать загадочный мануY

скрипт, написанный на языке Visual Basic.

Отличные новости

Microsoft Visual Basic for Applications (VBA) — чрезвычайно мощный язык

программирования. С его помощью можно продублировать абсолютно все

действия, выполняемые посредством пользовательского интерфейса Excel,

например, создание отчетов, построение диаграмм и т.п.

Авторы книги работают в компании MrExcel Consulting, предлагающей усY

луги по автоматизации процесса создания отчетов в Excel для огромного числа

клиентов. В ходе своей работы мы часто сталкиваемся с очень похожими задаY

Page 39: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 39

чами: успешно импортировав данные в Excel, наши клиенты хотели бы упроY

стить долгий и утомительный процесс создания одних и тех же еженедельных,

ежемесячных или ежеквартальных отчетов.

Именно это и предлагает VBA. Часы, потраченные на программирование

макросов, сводят создание отчетов к нескольким щелчкам мыши. Поистине

царская награда!

В этой главе будут рассмотрены причины некорректной работы средства заY

писи макросов. В частности, будет рассмотрен макрос, который начинает сбоY

ить на следующий день после своего создания. Не обращайте внимания на неY

понятный вам код. Цель этой главы — показать фундаментальную проблему

средства создания макросов Excel и познакомить вас со средой разработки VBA.

Панель инструментов “Visual Basic” Панель инструментов Visual Basic — одно из основных средств, необходиY

мых при написании макросов с помощью VBA. Чтобы отобразить ее на экраY

не, выберите в меню Excel команду Вид Панели инструментов Visual Basic(View Toolbars Visual Basic) (рис. 1.1).

Выполнить макрос Редактор сценариев

Записать макрос Режим конструктора

Редактор Visual Basic

Параметрыбезопасности

Элементы управления

Рис. 1.1. Панель инструментов Visual Basic предоставляет интерфейс для выполне&ния и записи макросов

Панель инструментов Visual Basic содержит несколько кнопок.

Выполнить макрос (Run Macro). Отображает список доступных макросов.

Записать макрос (Record Macro). Начинает процесс записи макроса и

отображает панель инструментов Остановить запись (Stop Recording)

(рис. 1.2).

Рис. 1.2. Одна из самых маленьких панелей инструментов в Excel содержит однуиз самых важных для записи работоспособного макроса кнопок (Относительнаяссылка)

Безопасность (Security). Отображает диалоговое окно Безопасность(Security) (см. раздел ‘‘Безопасность макросов’’, далее в этой главе).

Редактор Visual Basic (Visual Basic Editor). Открывает редактор Visual

Basic.

Page 40: ? Применение VBA и макросов в Microsoft® Excel

40 Часть I Первые шаги

Элементы управления (Control Toolbox). Отображает панель инструменY

тов с элементами управления, которые можно добавить на рабочий лист.

Режим конструктора (Design Mode). Режим конструктора позволяет

редактировать элементы управления, размещенные на рабочем листе.

Редактор сценариев (Microsoft Script Editor). Открывает редактор WebY

сценариев. Поскольку эта тема не имеет прямого отношения к VBA,

она не будет рассматриваться в этой книге.

Панель инструментов Остановить запись (см. рис. 1.2), которая отображаY

ется на экране в результате щелчка на кнопке Записать макрос, содержит

всего лишь 2 кнопки.

Остановить запись (Stop Recording). Останавливает текущий процесс

записи макроса.

Относительная ссылка (Relative Reference). Указывает Excel на необY

ходимость использования относительных ссылок вместо абсолютных.

Безопасность макросовПосле того как макросы VBA стали использоваться злоумышленниками

для распространения вирусов, Microsoft разработала новую политику безопасY

ности, по умолчанию запрещающую выполнение макросов. Чтобы продолY

жить изучение материала, нам потребуется изменить стандартную политику.

Откройте диалоговое окно Безопасность (Security) (рис. 1.3), выбрав коY

манду главного меню Excel Сервис Макрос Безопасность (Tools Macro

Security). Microsoft различает 4 уровня безопасности: Очень высокая (Very

High), Высокая (High) (используется по умолчанию), Средняя (Medium) и

Низкая (Low). При выборе уровня безопасности Высокая запрещается выполY

нение или редактирование всех неподписанных макросов. Чтобы начать создаY

ние собственных макросов, выберите уровень безопасности Средняя.

Уровень безопасности “Очень высокая”

В соответствии с парадигмой безопасности Microsoft системный админиY

стратор создает высокозащищенный сетевой каталог (так называемую

песочницу (sandbox)) и определяет его как доверенное размещение. Все макроY

сы, находящиеся в песочнице, считаются безопасными (их разрешается выY

полнять), остальные макросы таят в себе потенциальную угрозу. Ключевым

моментом этой парадигмы является предположение о невозможности комY

прометации доверенного размещения.

Уровень безопасности “Высокая”

На этом уровне безопасности разрешается выполнение только доверенных

макросов, т.е. макросов, имеющих цифровую подпись и происходящих из наY

Page 41: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 41

дежного источника. Поскольку подписывание макроса подразумевает необхоY

димость приобретения цифрового сертификата у уполномоченной на это орY

ганизации (такой как VeriSign), уровень безопасности Высокая (High) являетY

ся далеко не самым лучшим выбором при разработке собственных макросов.

При открытии рабочей книги все находящиеся в ней неподписанные макросы

будут попросту отключены.

Рис. 1.3. Уровень безопасности Высокая выбран поумолчанию

Уровень безопасности “Средняя”

На уровне безопасности Средняя (Medium) решение об отключении

потенциально опасных макросов принимается пользователем. Именно

этот уровень безопасности рекомендуется применять при разработке собY

ственных макросов. Конечно же, необходимость включать макросы при

каждом открытии рабочей книги может несколько раздражать. С другой

стороны, это последняя возможность защититься от разрушительного виY

руса, который таится в ничем не приметной рабочей книге, присланной

вам по электронной почте.

Уровень безопасности “Низкая”

На этом уровне безопасности защита от потенциально опасных макроY

сов отсутствует. Теперь уже ничто не защитит вас от вируса, хранящегося в

рабочей книге. Применение уровня безопасности Низкая (Low) крайне не

рекомендуется.

Page 42: ? Применение VBA и макросов в Microsoft® Excel

42 Часть I Первые шаги

Если необходимость включения собственных макросов при каждом открыY

тии рабочей книги начала приводить вас в бешенство, подумайте о приобреY

тении цифрового сертификата (см. выше).

Запись, хранение и выполнение макросовЗапись макросов весьма полезна на начальном этапе изучения языка макY

росов. По мере накопления знаний и опыта потребность в записи макросов

будет неуклонно уменьшаться.

Чтобы начать запись макроса, выберите команду главного меню Excel

Сервис Макрос Начать запись (Tools Macro Record New Macro) или

щелкните на кнопке Записать макрос (Record Macro) панели инструментов

Visual Basic. Перед тем как начать запись макроса, Excel отобразит диалоговое

окно Запись макроса (Record Macro), показанное на рис. 1.4.

Рис. 1.4. Задайте имя и сочетаниеклавиш для будущего макроса

Диалоговое окно “Запись макроса”

Введите имя макроса в поле Имя макроса (Macro name). В имени макроса

не допускается использование пробела (таким образом, имя Макрос1 являетY

ся допустимым, а имя Макрос 1 — нет). Старайтесь давать макросам значиY

мые имена, например, КвартальныйОтчет. Имена наподобие Макрос1 явY

ляются не слишком информативными.

Задайте сочетание клавиш с помощью одноименного поля. К примеру, если

ввести в поле Сочетание клавиш (Shortcut key) букву ‘‘п’’, записанный макрос

можно будет выполнить путем нажатия комбинации клавиш <Ctrl+п>.

С помощью раскрывающегося списка Сохранить в (Store macro in) выберите

место хранения записываемого макроса: Личная книга макросов (Personal

Macro Workbook), Новая книга (New Workbook) или Эта книга (This Workbook).

Макросы, имеющие непосредственное отношение к текущей рабочей книге,

рекомендуется сохранять в размещении Эта книга.

Личная книга макросов (PERSONAL.XLS) создается при первом сохранении

макроса в одноименном размещении. Это скрытая рабочая книга, которая

загружается автоматически при каждом запуске Excel. Чтобы отобразить личY

Page 43: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 43

ную книгу макросов на экране, выберите команду главного меню Excel

Окно Отобразить (Window Unhide).

Личная книга макросов подходит для хранения далеко не каждого макроса.

В ней рекомендуется хранить макросы общего назначения, не имеющие непоY

средственного отношения к конкретному рабочему листу или книге.

После выбора места хранения макроса щелкните на кнопке OK. Чтобы заY

кончить запись макроса, щелкните на кнопке Остановить запись (Stop ReY

cording) одноименной панели инструментов.

Выполнение макросаДля выполнения макроса достаточно нажать соответствующую комбинаY

цию клавиш (если она определена) на клавиатуре. Макрос можно назначить

также кнопке панели инструментов или элементу управления формы. Кроме

того, выполнить макрос можно с помощью уже рассмотренной панели инстY

рументов Visual Basic.

Создание кнопки выполнения макроса

Макросы общего назначения рекомендуется хранить в личной книге макY

росов и запускать с помощью кнопки, вынесенной на панель инструментов.

Чтобы создать кнопку выполнения макроса, следуйте приведенной ниже

процедуре.

1. Щелкните на панели инструментов правой кнопкой мыши и выберите

команду контекстного меню Настройка (Customize).

2. Перейдите во вкладку Команды (Commands) (рис. 1.5).

Рис. 1.5. Чтобы добавить кнопку выполнениямакроса на панель инструментов Excel, восполь&зуйтесь диалоговым окном Настройка

Page 44: ? Применение VBA и макросов в Microsoft® Excel

44 Часть I Первые шаги

3. Выберите категорию Макросы (Macros).

4. Выберите команду Настраиваемая кнопка (Custom Button) (со значком

улыбающейся рожицы) и перетащите ее на панель инструментов.

5. Щелкните на помещенном на панель инструментов значке с улыбаюY

щейся рожицей правой кнопкой мыши (не закрывайте диалоговое окно

Настройка (Customize)).

6. Выберите команду контекстного меню Назначить макрос (Assign

Macro), выберите макрос и щелкните на кнопке OK.

7. Закройте диалоговое окно Настройка.

Назначение макроса элементу управления формыМакросы, имеющие непосредственное отношение к конкретной рабочей

книге, рекомендуется хранить вместе с рабочей книгой и запускать с помоY

щью элемента управления формы, помещенного на рабочий лист.

Чтобы назначить макрос элементу управления формы, помещенному на

рабочий лист, выполните следующие действия.

1. Отобразите панель инструментов Формы (Forms), выбрав команду

главного меню Excel Вид Панели инструментов Формы (View

Toolbars Forms).

2. Щелкните на кнопке Кнопка (Button).

3. Щелкните на рабочем листе левой кнопкой мыши и, удерживая ее (кнопку)

нажатой, нарисуйте контур кнопки. Отпустите левую кнопку мыши.

4. Выберите требуемый макрос в диалоговом окне Назначить макрособъекту (Assign Macro) (рис. 1.6) и щелкните на кнопке OK.

Рис. 1.6. Макрос, хранящийся вместе с рабочейкнигой, рекомендуется назначить элементу управ&ления формы, помещенному на рабочий лист

5. Щелкните на только что созданной кнопке для выполнения макроса.

Page 45: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 45

Редактор Visual BasicНа рис. 1.7 показано типичное окно редактора Visual Basic, которое состоит

из трех основных частей. Не беспокойтесь, если ваше окно редактора Visual

Basic отличается от показанного на рисунке. Более подробно редактор Visual

Basic рассматривается в следующих разделах главы.

Рис. 1.7. Окно редактора Visual Basic

Параметры редактора Visual Basic

Редактор Visual Basic имеет несколько настраиваемых параметров. РасY

смотрим те из них, которые относятся непосредственно к написанию кода.

Настройка параметров редактора Visual Basic

Чтобы настроить параметры редактора Visual Basic, выберите команду меY

ню Tools Options (Сервис Параметры)1 и перейдите во вкладку Editor(Редактор). Из всех параметров, размещенных на этой вкладке, внимания заY

служивает только один — Require Variable Declaration (Требовать объявления

переменной). По умолчанию Excel не требует объявлять переменные, что споY

1 Примерный перевод. Редактор Visual Basic не русифицирован. YYYY Прим. ред.

Page 46: ? Применение VBA и макросов в Microsoft® Excel

46 Часть I Первые шаги

собствует более быстрому написанию кода. С другой стороны, с помощью

этого требования можно предотвратить ошибки ввода имен переменных. ПоY

ступайте так, как посчитаете нужным.

Использование цифровых подписей

Если вам надоело постоянно подтверждать безопасность собственных макY

росов, воспользуйтесь цифровой подписью, выбрав команду меню ToolsDigital Signature (Сервис Цифровая подпись).

Диспетчер проектов

Диспетчер проектов содержит список всех открытых рабочих книг и загруY

женных дополнительных модулей. Щелкнув на значке ‘‘плюс’’ рядом с узлом

VBAProject (Проект VBA), можно увидеть папки Microsoft Excel Objects(Объекты Microsoft Excel), Forms (Формы), Class Modules (Модули классов) и

Modules (Модули) (присутствует по умолчанию). Каждая папка содержит

один или несколько компонентов.

Чтобы просмотреть код компонента, щелкните на нем правой кнопкой

мыши и выберите команду контекстного меню View Code (Просмотр кода).

Такого же результата можно достичь путем двойного щелчка на названии

компонента (за исключением форм, двойной щелчок на названии которых

приводит к открытию формы в режиме конструктора).

Чтобы отобразить окно диспетчера проектов, выберите команду меню

Tools Project Explorer (Сервис Диспетчер проектов), нажмите комY

бинацию клавиш <Ctrl+R> или щелкните на кнопке Project Explorer(Диспетчер проектов), расположенной на панели инструментов.

Окно диспетчера проектов показано на рис. 1.8. Чтобы добавить к проекту

модуль, щелкните на названии проекта правой кнопкой мыши, выберите коY

манду контекстного меню Insert (Вставить), а затем — тип добавляемого модуля.

Объекты Microsoft Excel

По умолчанию проект состоит из модулей рабочих листов и модуля ЭтаКни-га (ThisWorkbook). Код, имеющий непосредственное отношение к рабочему

листу (например, код обработки событий листа), помещается в соответствуюY

щий этому листу модуль. Модуль ЭтаКнига содержит код обработки событий

рабочей книги. Об обработке событий речь идет в главе 8, ‘‘События’’.

Формы

Excel позволяет создавать формы для взаимодействия с пользователем.

О формах речь идет в главе 9, ‘‘Введение в пользовательские формы’’.

Модули

При записи макроса Excel автоматически создает модуль, куда помещает

код макроса. Именно в таких модулях хранится большая часть создаваемого

вами кода.

Page 47: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 47

Рис. 1.8. Диспетчер проектов содер&жит список всех модулей проекта

Модули классов

Модули классов Excel предназначены для создания пользовательских объY

ектов. Помимо этого, модули классов позволяют программистам обмениватьY

ся фрагментами кода, не вдаваясь в подробности работы последнего. О модуY

лях классов речь идет в главе 20, ‘‘Создание пользовательских объектов, типов

и коллекций’’.

Окно свойств

Окно свойств предназначено для редактирования параметров различных

компонентов — рабочих листов, книг, модулей или элементов управления

форм. Список параметров компонента зависит от его типа.

Чтобы открыть окно свойств, выберите команду меню View PropertiesWindow (Вид Окно свойств), нажмите клавишу <F4> или щелкните

на кнопке Project Properties (Свойства проекта), расположенной на

панели инструментов.

Практикум

Предположим, что вы работаете бухгалтером. Каждое утро вы получаете по элек&тронной почте текстовый файл с разделителями&запятыми, содержащий инфор&мацию о счетах за вчерашний день в столбцах СчетДата, СчетНомер, Продавец-Номер, КлиентНомер, ПродуктВыручка, СервисВыручка, ПродуктСтоимость(рис. 1.9).

Page 48: ? Применение VBA и макросов в Microsoft® Excel

48 Часть I Первые шаги

Рис. 1.9. Файл Счет.txt

Вы вручную импортируете этот файл в Excel, добавляете итоговый столбец, фор&матируете заголовки столбцов с помощью утолщенного шрифта и распечатываетеполученный отчет для передачи менеджерам.

Подготовка к записи макросаОписанная выше последовательность действий просто&таки напрашивается бытьоформленной в виде макроса. Прежде чем приступить к его записи, составьтеточный список выполняемых операций. В рассматриваемом случае он долженвыглядеть так.1. Выберите команду главного меню Excel Файл Открыть (File Open).

2. Отобразите содержимое папки, в которой хранится файл Счет.txt.

3. Выберите значение Все файлы (All Files) из раскрывающегося списка Типфайлов (Files of type).

4. Выберите файл Счет.txt.

5. Щелкните на кнопке Открыть (Open).

6. В группе Формат исходных данных (Original data type) диалогового окнаМастер текстов (импорт) — шаг 1 из 3 (Text Import Wizard — Step 1 of 3) устано&вите переключатель С разделителями (Delimited).

7. Щелкните на кнопке Далее (Next).

8. В группе Символом-разделителем является (Delimiters) диалогового окна Мастертекстов (импорт) — шаг 2 из 3 (Text Import Wizard — Step 2 of 3) сбросьте флажокЗнак табуляции (Tab) и установите флажок Запятая (Comma).

9. Щелкните на кнопке Далее.

10. В группе Формат данных столбца (Column data format) диалогового окнаМастер текстов (импорт) — шаг 3 из 3 (Text Import Wizard — Step 3 of 3) уста&новите переключатель Дата (Date) и выберите из раскрывающегося списказначение ДМГ (DMY).

11. Щелкните на кнопке Готово (Finish) для импортирования файла.

12. Нажмите клавишу <End>, а затем — клавишу <↓>, чтобы переместиться на по&следнюю строку импортированных данных.

Page 49: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 49

13. Нажмите клавишу <↓>, чтобы переместиться на итоговую строку.

14. Введите слово “Всего”.

15. Нажмите клавишу <→> 4 раза, чтобы переместиться в столбец E итоговой строки.

16. Щелкните на кнопке Автосумма (AutoSum) и нажмите комбинацию клавиш<Ctrl+Enter>, чтобы суммировать значения столбца ПродуктВыручка, остава&ясь при этом в той же ячейке.

17. Перетащите маркер заполнения по столбцам F и G, чтобы скопировать в нихформулу суммирования.

18. Выделите строку 1 и щелкните на кнопке Полужирный (Bold), чтобы выделитьзаголовки столбцов путем утолщения шрифта.

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

20. Нажмите комбинацию клавиш <Ctrl+A>, чтобы выделить все ячейки рабочеголиста.

21. Выберите команду Формат Столбец Автоподбор ширины (Format ColumnAutoFit Selection).

Теперь вы готовы к записи своего первого макроса. Создайте пустую рабочую книгуи сохраните ее под каким&нибудь описательным именем, например Макрос-ИмпортаСчетов.xls. Щелкните в панели инструментов Visual Basic на кнопкеЗаписать макрос (Record Macro) или выберите команду меню Сервис МакросНачать запись (Tools Macro Record New Macro).Измените предлагаемое по умолчанию имя макроса Макрос1 на более инфор&мативное, например ИмпортСчета. Убедитесь, что макрос будет сохранен в раз&мещении Эта книга (This Workbook) и задайте сочетание клавиш для выполнениямакроса, к примеру <Ctrl+и>. По умолчанию в поле Описание (Description) зано&сится ваше имя и дата создания макроса. Добавьте сюда текст, кратко описываю&щий предназначение макроса (рис. 1.10), и щелкните на кнопке OK.

Рис. 1.10. Прежде чем начать запись макроса, задайте необходимые пара&метры в диалоговом окне Запись мак-роса (Record Macro)

Page 50: ? Применение VBA и макросов в Microsoft® Excel

50 Часть I Первые шаги

Запись макросаНачиная с этого момента средство записи макросов фиксирует каждое совершен&ное вами действие. Постарайтесь не отклоняться от намеченной ранее последо&вательности операций. Если, к примеру, вы случайно переместитесь в столбец Fвместо столбца E, а затем вернетесь обратно, созданный макрос будет старатель&но повторять эту ошибку при каждом своем запуске.

Внимание Сопротивляйтесь желанию убрать из виду панель инструментов Остановитьзапись (Stop Recording). Если она будет вам мешать, перетащите ее в безо&пасное место (действие по перетаскиванию панели Остановить запись не вклю&чается в записываемый макрос). Если вы все же закроете панель инструментовОстановить запись, то для того чтобы завершить запись макроса, вам потребует&ся выбрать команду меню Сервис Макрос Остановить запись (ToolsMacro Stop Recording).Выполните все действия, необходимые для создания отчета. Чтобы остановитьзапись макроса, щелкните на панели инструментов Остановить запись на одно&именной кнопке. Панель инструментов Остановить запись исчезнет из виду.

Внимание Закрытие панели инструментов Остановить запись не приводит к остановкезаписи макроса. Этим вы только усложните себе жизнь, так как теперь длязавершения записи макроса вам потребуется выбрать команду менюСервис Макрос Остановить запись.Пришло время взглянуть на сгенерированный код макроса. Для этого от&кройте окно редактора Visual Basic, выбрав команду меню Сервис МакросРедактор Visual Basic (Tools Macro Visual Basic Editor) или воспользовав&шись комбинацией клавиш <Alt+F11>.

Изучение кода макроса Рассмотрим код, сгенерированный Excel в результате записи макроса. ОтY

кройте редактор Visual Basic, воспользовавшись комбинацией клавиш

<Alt+F11>. Щелкните на названии модуля Module1 проекта МакросИмпор-таСчетов.xls правой кнопкой мыши и выберите команду контекстного меY

ню View Code (Просмотр кода). Строки кода, начинающиеся со знака апостY

рофа, являются комментариями и игнорируются Excel. Комментарии создаY

ются на основе информации, введенной в окне Запись макроса (Record

Macro) (сюда, в частности, относится сочетание клавиш, использующееся для

вызова макроса).

Page 51: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 51

Внимание Комментарий не определяет сочетание клавиш. Другими словами, изменив вкомментарии сочетание клавиш <Ctrl+и> на <Ctrl+с>, вы ничего не добьетесь.Изменить сочетание клавиш можно только с помощью диалогового окна Макрос(Macro).

Сгенерированный код макроса, как правило, выглядит достаточно опрятно

(рис. 1.11). Все строки кода, отличные от строк комментариев, сдвинуты на

4 символа вправо. Если длина строки превышает 100 символов, средство запиY

си макросов разбивает ее на несколько строк меньшей длины, дополнительно

сдвигая их еще на 4 символа вправо. В месте разрыва строки помещаются симY

волы пробела и знака подчеркивания. Поскольку физические размеры книги не

позволяют поместить на странице строку длиной 100 символов, в приводимых

далее примерах все строки будут разбиваться на границе в 60YY65 символов. ТаY

ким образом, код на экране компьютера может несколько отличаться от приY

водимого здесь.

Рис. 1.11. Сгенерированный код макроса выглядит очень аккуратно

Приведенные ниже 8 строк кода представляют собой 1 строку, разбитую на

несколько фрагментов для удобочитаемости.

Workbooks.OpenText Filename:= _ "C:\Счет.txt", Origin:=1251, StartRow:=1, _ DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _ ConsecutiveDelimiter:=False, Tab:=False, Semicolon:=False, _ Comma:=True, Space:=False, Other:=False, _ FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), _

Page 52: ? Применение VBA и макросов в Microsoft® Excel

52 Часть I Первые шаги

Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1)), _ TrailingMinusNumbers:=True

Учитывая сказанное выше, средство записи макросов превратило 21Yшаговую

процедуру создания отчета в 14 строк кода. Весьма неплохо!

Совет Каждое действие, выполняемое посредством пользовательского интерфейса Excel,может быть описано с помощью одной или нескольких строк программного кода.

А теперь протестируем созданный макрос. Вернитесь к интерфейсу Excel,

воспользовавшись комбинацией клавиш <Alt+F11>. Закройте файл Счет.txt,

не сохранив внесенных в него изменений. При этом у вас должна остаться отY

крытой рабочая книга МакросИмпортаСчетов.xls.

Выполните сохраненный макрос, нажав комбинацию клавиш <Ctrl+и>.

Он должен сработать безукоризненно (рис. 1.12).

Рис. 1.12. Создание отчета прошло без сучка и задоринки

Непредвиденные результаты Предположим, что утром следующего дня вы получили по электронной

почте новый файл Счет.txt. Запустив созданный накануне макрос с помоY

щью сочетания клавиш <Ctrl+и>, вы были неприятно удивлены. Файл

Счет.txt от 5 июня содержал сведения о 12Yти счетах, а файл Счет.txt от

6 июня — о 16Yти. Тем не менее, макрос поместил итоговую информацию в

14Yю строку, тем самым в точности воспроизведя действия, выполненные при

его записи (рис. 1.13).

Возможное решение: использованиеотносительных ссылок

По умолчанию средство записи макросов рассматривает все действия, соY

вершаемые пользователем, как абсолютные. Если на определенном этапе

Page 53: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 53

пользователь введет данные в 14Yю строку, записанный макрос всегда будет

вводить эти данные в 14Yю строку. Поскольку исходная информация может

располагаться на разном количестве строк, использование при записи макроY

са абсолютных ссылок недопустимо.

Рис. 1.13. Записанный накануне макрос не выдержал проверки на прочность. Вместо того, что&бы добавить итоговые сведения сразу же после информации о счетах, макрос добавил их в14&ю строку

Одним из возможных решений в данной ситуации является использование

при записи макроса относительных ссылок.

Абсолютные ссылки основаны на действительных адресах ячеек, например

A1. Относительные ссылки основаны на позиции ячейки относительно другой

ячейки. Например, ссылка R[16]C[-1] указывает на ячейку, которая нахоY

дится на 16 строк ниже и на 1 столбец левее текущей ячейки.

Практикум

Запишем тот же макрос с использованием относительных ссылок. Закройте файлСчет.txt без сохранения изменений. В рабочей книге МакросИмпорта-Счетов.xls создайте новый макрос, выбрав команду меню СервисМакрос Начать запись (Tools Macro Record New Macro). Присвойте новомумакросу имя ИмпортСчетаОтносительно и назначьте другое сочетание клавиш,например <Ctrl+т> (рис. 1.14). Импортируйте данные из файла Счет.txt. Прежде чем переходить к последнейстроке данных с помощью последовательного нажатия клавиш <End> и <↓>,щелкните на кнопке Относительная ссылка (Relative Reference) в панели инстру&ментов Остановить запись (Stop Recording) (см. рис. 1.2). Выполните следующие действия.

1. Нажмите клавишу <End>, а затем — клавишу <↓>, чтобы переместиться на по&следнюю строку импортированных данных.

Page 54: ? Применение VBA и макросов в Microsoft® Excel

54 Часть I Первые шаги

2. Нажмите клавишу <↓>, чтобы переместиться на итоговую строку.

Рис. 1.14. Попытка номер 2

3. Введите слово “Всего”.

4. Нажмите клавишу <→> 4 раза, чтобы переместиться в столбец E итоговой строки.

5. Щелкните на кнопке Автосумма (AutoSum) и нажмите комбинацию клавиш<Ctrl+Enter>, чтобы суммировать значения столбца ПродуктВыручка, остава&ясь при этом в той же ячейке.

6. Перетащите маркер заполнения по столбцам F и G, чтобы скопировать в нихформулу суммирования.

7. Выделите итоговую строку с помощью комбинации клавиш <Shift+пробел> ищелкните на кнопке Полужирный (Bold), чтобы выделить суммарные значениястолбцов путем утолщения шрифта.

Не спешите перемещаться в ячейку A1 и выделять заголовки столбцов путемутолщения шрифта. Средство записи макросов зафиксирует это действие какперемещение на 17 строк вверх, а это не совсем корректно. Отключите режимотносительных ссылок, еще раз щелкнув на кнопке Относительная ссылка, ипродолжите запись макроса.

8. Выделите строку 1 и щелкните на кнопке Полужирный, чтобы выделить заголов&ки столбцов путем утолщения шрифта.

9. Нажмите комбинацию клавиш <Ctrl+A>, чтобы выделить все ячейки рабочеголиста.

10. Выберите команду Формат Столбец Автоподбор ширины (Format ColumnAutoFit Selection).

11. Остановите запись макроса.

Нажмите комбинацию клавиш <Alt+F11>, чтобы вернуться в окно редактораVisual Basic и просмотреть полученный на этот раз код. Текст макроса Импорт-СчетаОтносительно будет помещен в модуль Module1 сразу же после текстамакроса ИмпортСчета.

Page 55: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 55

Внимание Если между созданием первого и второго макроса вы завершали работу с Ex&cel, новый макрос будет помещен в модуль Module2.На рис. 1.15 показан код макроса ИмпортСчетаОтносительно с двумя ком&ментариями, указывающими на момент включения и отключения режима от&носительных ссылок.

Рис. 1.15. Код макроса, записанного с использованием режима относительных ссылок

Чтобы протестировать макрос, закройте файл Счет.txt без сохранения

изменений и нажмите комбинацию клавиш <Ctrl+т>. На этот раз работа макY

роса не должна вызывать какихYлибо нареканий.

Предположим, что файл Счет.txt от 7Yго июня содержит сведения о

21 счете (рис. 1.16).

Откройте рабочую книгу МакросИмпортаСчетов.xls и выполните ноY

вый макрос, нажав комбинацию клавиш <Ctrl+т>. На первый взгляд макрос

справился с поставленной перед ним задачей. Но взгляните на рис. 1.17 — не

кажется ли вам, что здесь чтоYто не так?

Передав подобный отчет менеджеру, вы, несомненно, навредили бы своей

репутации. Присмотритесь к ячейке E23. В левом верхнем углу ячейки нахоY

Page 56: ? Применение VBA и макросов в Microsoft® Excel

56 Часть I Первые шаги

дится маленький зеленый треугольник — верный признак ошибки. Следует

отметить, что возможность предупреждения ошибок появилась благодаря

смартYтегам — средству, недоступному в Excel 95 или Excel 97.

Рис. 1.16. Сможет ли новый макрос справиться с этими данными?

Рис. 1.17. Результат выполнения макроса, использующего относительные ссылки

Щелкните в ячейке E23 и подведите указатель к появившейся рядом с ячейY

кой кнопке примечания. На экране появится сообщение о том, что формула в

этой ячейке ссылается на диапазон, к которому прилегают другие значения.

Взглянув на строку формул, вы увидите, что макрос суммировал значения тольY

Page 57: ? Применение VBA и макросов в Microsoft® Excel

Excel и VBA — гремучая смесь Глава 1 57

ко с 7 по 22 строку. К сожалению, логику функции автоматического суммироваY

ния не может воспроизвести ни один автоматически созданный макрос.

Если же файл Счет.txt от 7Yго июня содержит сведения о меньшем колиY

честве счетов, чем 6Yго июня, Excel ‘‘наградит’’ вас аналогичной формулой

=СУММ(E10:E65531) (=SUM(E10:E65531)) и сообщением о наличии цикY

лических ссылок (рис. 1.18).

Рис. 1.18. Результат выполнения макроса, использующего относительные ссылки, при меньшемколичестве счетов

ОтчаяниеДочитав книгу до этого места, вы, вероятно, уже проклинаете Microsoft.

Представьте себе мое состояние после нескольких дней безуспешных попыток

написать хотя бы один работающий макрос. Ситуацию усугубляло знание тоY

го, что подобные макросы без проблем генерировались средством записи макY

росов Lotus 1Y2Y3, созданным в далеком 1983 году. То, что получилось у Мича

Кейпора (Mitch Kapor) 21 год назад, Microsoft не может повторить до сих пор.

Известно ли вам, что все ранние версии Excel вплоть до Excel 97 поддержиY

вали выполнение макросов командной строки Lotus? Этот факт стал известен

мне только после того, как Microsoft объявила об окончании поддержки

Excel 97. Многие компании, перешедшие на Excel XP (который уже не подY

держивал выполнение макросов Lotus 1Y2Y3), обратились к нам с просьбой пеY

реписать старые макросы Lotus на Excel VBA. Я не могу смириться с мыслью,

что начиная с Excel 5, Excel 95 и Excel 97 интерпретатор Microsoft мог выполY

нить макрос, корректно решавший поставленную нами задачу, однако средстY

во записи макросов было не в состоянии его создать.

Следующий шагЕдинственно правильное решение рассмотренной задачи заключается

в применении языка программирования Visual Basic. Первым приближением

Page 58: ? Применение VBA и макросов в Microsoft® Excel

58 Часть I Первые шаги

к цели можно считать автоматически сгенерированный макрос. Немного

здравого смысла, и он станет реальным подспорьем в решении повседневных

задач. В главе 2, ‘‘Знакомство с Visual Basic for Applications” мы попробуем

применить этот подход к двум записанным нами макросам. Научившись

‘‘читать’’ код VBA, вы с легкостью сможете подправить автоматически сгенеY

рированный код и даже написать макрос ‘‘с нуля’’.

Page 59: ? Применение VBA и макросов в Microsoft® Excel

2Загадочный код..............................59Учимся понимать “речь” VBA .....60Справочная система VBA .............63Изучение кода записанногомакроса ............................................66Использование отладчикакода ...................................................74Диспетчер объектов ......................855 советов по исправлению иоптимизации автоматическисгенерированного кода................87Исправление и оптимизацияавтоматическисгенерированного кода................90Следующий шаг..............................93

Глава 2

Çíàêîìñòâî ñ VisualBasic for Applications

Загадочный кодКод VBA способен смутить кажY

дого, кто изучал в школе один из

процедурных языков программироY

вания наподобие BASIC или COBOL.

Несмотря на то что VBA расшифроY

вывается как ‘‘Visual Basic for ApplicaY

tions’’, он представляет собой объект*но*ориентированную версию BASIC.

Рассмотрим небольшой фрагмент

кода VBA.

Selection.End(xlDown).SelectRange("A14").SelectActiveCell.FormulaR1C1 = "Всего"Range("E14").SelectSelection.FormulaR1C1 = _"=SUM(R[-12]C:R[-1]C)"Selection.AutoFillDestination:=Range("E14:G14"), _Type:=xlFillDefault

Бьюсь об заклад, что этот код не

будет иметь ни малейшего смысла

для тех, кто изучал только процедурY

ные языки программирования (к соY

жалению, практика изучения процеY

дурных языков еще весьма популярна

во многих учебных заведениях).

Ниже приведен фрагмент кода,

написанный на языке BASIC.

For x = 1 to 10 Print Rpt$(" ", x); Print "*";Next x

В результате его выполнения на экY

ране компьютера появится ‘‘лесенка’’

из символов звездочки.

Page 60: ? Применение VBA и макросов в Microsoft® Excel

60 Часть I Первые шаги

* * * * * * * * * *

Синтаксис процедурного языка программирования больше похож на синY

таксис английского языка, нежели синтаксис объектноYориентированного

языка программирования. К примеру, выражение Print "Hello World"записано в привычном формате ‘‘глаголYYобъект’’. А теперь постараемся заY

быть о программировании и рассмотрим один конкретный пример.

Учимся понимать “речь” VBAПопробуем сыграть в футбол на языке BASIC. Команда ‘‘ударить по мячу’’

будет выглядеть примерно следующим образом:

Kick the Ball

Именно так мы и говорим в повседневной жизни. Глагол ‘‘ударить’’ (kick)

следует перед существительным ‘‘мяч’’ (the ball). Аналогично, в приведенном

выше примере глагол Print следует перед существительным * (звездочка).

К сожалению, подобный синтаксис не употребляется ни в одном объектY

ноYориентированном языке, включая VBA. Исходя из самого названия этого

класса языков программирования, становится ясно, что центральное место

здесь отводится объекту, т.е. существительному. Команда ‘‘ударить по мячу’’,

записанная на языке VBA, будет выглядеть так:

Ball.Kick

В VBA существительное (объект) записывается перед глаголом (методом).

Базовая структура большинства строк VBA выглядит так:

Объект.МетодК сожалению, это не очень похоже на повседневную речь. Никто не говоY

рит ‘‘Вода.Пить’’, ‘‘Мяч.Ударить’’ или ‘‘Девушка.Целовать’’. Именно поэтому

VBA кажется очень сложным по сравнению с процедурными языками проY

граммирования.

Продолжим аналогию. Представьте, что вы стоите на зеленом газоне перед

тремя мячами: футбольным, баскетбольным и бейсбольным. Как сказать на

VBA ‘‘ударить футбольный мяч’’ члену школьной футбольной команды?

Выше была приведена команда ‘‘ударить по мячу’’ (Ball.Kick), однако в

данном случае этого недостаточно. Возможно, ребенок ударит мяч, который

находится ближе всех к нему (например, бейсбольный).

В VBA практически для каждого объекта (существительного) определяется

коллекция этих объектов. Рассмотрим электронную таблицу Excel. Строке соY

Page 61: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 61

ответствует набор строк, столбцу YYYY набор столбцов, рабочему листу YYYY набор

рабочих листов. С точки зрения синтаксиса имя коллекции объектов составY

ляется из имени объекта и суффикса ‘‘s’’, например:

Row Rows,

Cell Cells,

Ball Balls.

Существует несколько способов обращения к элементу коллекции. ПерY

вый из них состоит в использовании порядкового номера элемента, например:

Balls(2).Kick

Несмотря на то что приведенная выше запись вполне корректна, переY

упорядочивание мячей в коллекции может привести к весьма плачевному

результату.

Второй способ обращения к элементу коллекции является более безопасY

ным и состоит в использовании имени элемента, например:

Balls("Soccer").Kick

Теперь можно быть уверенным, что ребенок ударит именно по футбольноY

му мячу.

Для большинства методов (глаголов) в Excel VBA определены параметры, хаY

рактеризующие способ выполнения метода (назовем их наречиями). Ниже привеY

дена команда ‘‘сильно ударить футбольный мяч так, чтобы он полетел влево’’:

Balls("Soccer").Kick Direction:=Left, Force:=Hard

Комбинации двоеточия и знака равенства в коде VBA всегда указывают на

параметр метода.

Методы могут иметь много параметров, как обязательных, так и нет. ПредY

положим, что у метода Kick есть параметр Elevation (‘‘поднятие’’). Ниже

приведена команда ‘‘сильно ударить футбольный мяч так, чтобы он полетел

высоко влево’’:

Balls("Soccer").Kick Direction:=Left, Force:=Hard, Elevation:=High

Для каждого метода существует определенный порядок следования его параY

метров. Некоторые программисты пропускают имена параметров, указывая тольY

ко их значения. Следующая строка кода полностью эквивалентна предыдущей:

Balls("Soccer").Kick Left, Hard, High

Практика пропуска имен параметров не вносит ясности в код, так как не

зная точного порядка следования параметров, сложно судить о предназначеY

нии той или иной строки. Значения параметров Left, Hard и High сами по

себе информативны, однако так бывает далеко не всегда. Рассмотрим слеY

дующую строку кода:

WordArt.Add Left:=10, Top:=20, Width:=100, Height:=200

Если пропустить имена параметров, она будет выглядеть так:

WordArt.Add 10, 20, 100, 200

Несмотря на то что приведенная выше строка кода вполне корректна, отY

сутствие имен параметров серьезно затрудняет восприятие ее смысла. Точный

Page 62: ? Применение VBA и макросов в Microsoft® Excel

62 Часть I Первые шаги

порядок следования параметров метода можно узнать, обратившись к разделу

справочной системы, посвященному этому методу.

Ситуацию усложняет еще и то, что имена параметров требуется указывать

только в случае нарушения стандартного порядка их следования. Ниже привеY

дены две эквивалентных строки кода, соответствующих команде ‘‘ударить

футбольный мяч так, чтобы он полетел высоко влево’’ (не важно, насколько

сильным будет сам удар):

Balls("Soccer").Kick Direction:=Left, Elevation:=HighBalls("Soccer").Kick Left, Elevation:=High

Указав имя одного параметра, следует указать также имена всех параметY

ров, которые последуют за ним в этой строке кода.

Некоторые методы не имеют параметров. Ниже приведен код, имитируюY

щий нажатие клавиши <F9>:

Application.Calculate

Другие методы выполняют действие и возвращают его результат. Ниже

приведен код, добавляющий рабочий лист:

Worksheet.Add Before:=Worksheets(1)

Поскольку метод Worksheet.Add создает новый объект, результат его

выполнения может быть присвоен переменной (параметры метода при этом

следует взять в скобки):

Set MyWorksheet = Worksheet.Add (Before:=Worksheets(1))

Напоследок рассмотрим еще одну важную составляющую языка VBA —

свойства. Свойства описывают объект наподобие того, как прилагательное

описывает существительное.

Обратимся к примеру. В Excel существует объект, соответствующий активY

ной ячейке YYYY ActiveCell. Предположим, что нам необходимо изменить

цвет активной ячейки на желтый. Цвет ячейки определяется значением свойY

ства Interior.ColorIndex объекта ActiveCell. Изменение цвета ячейки

на желтый описывается следующей строкой кода:

ActiveCell.Interior.ColorIndex = 6

Обратите внимание, что в приведенном выше коде используется конструкY

ция Объект.Свойство, похожая на уже рассмотренную нами конструкцию

Объект.Метод. На первый взгляд, их невозможно отличить друг от друга. Если

же присмотреться повнимательнее, то можно заметить отсутствие двоеточия

перед знаком равенства в строке с конструкцией Объект.Свойство. Обычно

свойство всегда присутствует в левой или правой части выражений, связанных

с присвоением значения.

Ниже приведена команда, изменяющая цвет текущей ячейки на цвет

ячейки A1:

ActiveCell.Interior.ColorIndex = Range("A1").Interior.ColorIndex

Итак, изменение значения свойства Interior.ColorIndex приводит к

изменению цвета ячейки. Сравнивая свойство с прилагательным, получаем

Page 63: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 63

достаточно странный результат YYYY изменение прилагательного влечет за собой

выполнение действия.

В табл. 2.1 приведен краткий ‘‘словарь’’ терминов VBA.

Таблица 2.1. Словарь терминов VBA

Термин VBA Аналог Примечания

Объект Имя существительное YYYY

Коллекция Имя существительное

во множественном

числе

Обычно указывается элемент коллекY

ции, например Worksheets(1)

Метод Глагол Объект.Метод

Параметр Наречие Параметры указываются после имени

метода. Между именем параметра и его

значением ставится двоеточие и знак раY

венства (:=)

Свойство Имя прилагательное Обычно свойство присутствует в левой

или правой части выражения, связанY

ного с присвоением значения, например

ActiveCell.Height = 10 или x =ActiveCell.Height

Справочная система VBAНе беспокойтесь, если вы все еще не научились отличать метод от свойстY

ва. Именно здесь нам пригодится раскритикованное в предыдущей главе

средство записи макросов. Чтобы узнать, как запрограммировать то или иное

действие, запишите его в виде макроса и затем изучите сгенерированный код.

Спасительная клавиша <F1>

Приступая к написанию макросов, обязательно убедитесь в наличии на

вашем компьютере справочной системы VBA. К сожалению, она не входит в

стандартную установку Microsoft Office. Чтобы проверить наличие справочной

системы VBA, выполните следующие действия.

1. Запустите Excel и откройте окно редактора Visual Basic, воспользовавY

шись комбинацией клавиш <Alt+F11>. Выберите команду меню

Insert Module (Вставить Модуль) (рис. 2.1).

2. Введите 3 строки кода, как показано на рис. 2.2, и установите курсор

посредине слова MsgBox.

3. Нажмите клавишу <F1>. Если справочная система VBA установлена,

откроется окно, показанное на рис. 2.3.

Page 64: ? Применение VBA и макросов в Microsoft® Excel

64 Часть I Первые шаги

Рис. 2.1. Вставьте в рабочую книгуновый модуль

Рис. 2.2. Установите курсор посрединеслова MsgBox и нажмите клавишу <F1>

Рис. 2.3. Если справочная система VBA установлена, вы увидитена экране это окно

Если справочная система VBA не установлена, Excel выдаст сообщение об

ошибке. Установите справочную систему VBA, воспользовавшись установочY

ными компактYдисками Microsoft Office (при необходимости обратитесь за

помощью к системному администратору).

Page 65: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 65

Просмотр разделов справочной системы

Раздел справочной системы, посвященный тому или иному методу, содерY

жит подробное описание всех его параметров. Под именем метода или функY

ции расположены три ссылки: See Also (См. также), Example (Пример) и

Specifics (Особенности). Одной из наиболее полезных является ссылка

Example, ведущая на страницу с примером использования метода или функY

ции (рис. 2.4).

Рис. 2.4. Большинство разделов справочной системы VBA со&держат ссылку на страницу с примерами

Код примера можно выделить (рис. 2.5), скопировать в буфер обмена с поY

мощью комбинации клавиш <Ctrl+C>, а затем вставить в модуль с помощью

комбинации клавиш <Ctrl+V>.

Код записанных макросов наверняка содержит много незнакомых объекY

тов и методов. Установите курсор посредине интересующего вас ключевого

Page 66: ? Применение VBA и макросов в Microsoft® Excel

66 Часть I Первые шаги

слова и нажмите клавишу <F1>, чтобы отобразить соответствующий раздел

справочной системы VBA.

Рис. 2.5. Выделите код примера и скопируйте его в буфер обмена с по&мощью комбинации клавиш <Ctrl+C>

Изучение кода записанного макросаРассмотрим код первого макроса, записанного в главе 1, “Excel и VBA —

гремучая смесь”, и попытаемся понять его смысл в контексте объектов,

свойств и методов (рис. 2.6).

Согласно концепции Объект.Метод (или, что то же самое, Существитель*ное.Глагол) в 1Yй строке кода Workbooks является объектом, а OpenText —

методом. Установите курсор внутри слова OpenText и нажмите клавишу

<F1>, чтобы открыть раздел справочной системы VBA, посвященный этому

методу (рис. 2.7).

В справочной системе указано, что OpenText — это метод. Его параметY

ры перечислены в стандартном порядке следования в области, выделенной

серым цветом. Обратите внимание, что метод OpenText имеет всего лишь

один обязательный аргумент YYYY FileName. Все остальные параметры могут

быть пропущены.

Page 67: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 67

Рис. 2.6. Код записанного макроса

Рис. 2.7. Раздел справочной системы, посвященный методу OpenText. СсылкаApplies To (Применяется к) позволяет просмотреть список объектов, к которымможет быть применен этот метод

Page 68: ? Применение VBA и макросов в Microsoft® Excel

68 Часть I Первые шаги

Необязательные параметры

В справочной системе VBA можно найти информацию о стандартных знаY

чениях необязательных параметров. К примеру, стандартным значением параY

метра StartRow является 1, что весьма приемлемо. А вот пропустив параметр

Origin, вы рискуете попасть впросак. Дело в том, что по умолчанию Excel исY

пользует текущее значение этого параметра. Другими словами, если вы выполY

ните свой макрос после того, как ктоYто импортирует в Excel файл с китайскими

иероглифами, Excel предположит, что вы хотите сделать то же самое.

Предопределенные константы

Согласно разделу справочной системы VBA, посвященному методу Open-Text (см. рис. 2.7), DataType — это свойство, которое может иметь значение

xlDelimited или xlFixedWidth (предопределенные константы Excel VBA

типа XlTextParsingType). В редакторе Visual Basic нажмите комбинацию

клавиш <Ctrl+G>, чтобы открыть окно Immediate (Быстрое выполнение).

В окне Immediate введите следующую строку и нажмите клавишу <Enter>:

Print xlFixedWidth

Как показано на рис. 2.8, значением константы xlFixedWidth является 2.

Аналогичным образом можно узнать значение константы xlDelimited,

которое равно 1. Использование предопределенных констант с информаY

тивными именами вместо чисел значительно повышает удобочитаемость

программного кода.

Рис. 2.8. Воспользуйтесь окном Immediate, чтобы узнать значенияпредопределенных констант VBA, таких как xlFixedWidth

В большинстве случаев раздел справочной системы либо содержит допусY

тимые константы непосредственно в тексте справки, либо предлагает ссылку,

щелчок на которой приводит к их отображению (рис. 2.9).

К справочной системе VBA можно предъявить только одну претензию YYYY

она не позволяет узнать, является ли конкретный параметр нововведением теY

кущей версии Excel. К примеру, параметр TrailingMinusNumbers был

впервые представлен в Excel 2002. Попытка выполнения макроса, содержаY

щего этот параметр, в Excel 2000 завершится весьма плачевно. К сожалению,

эта проблема достаточно серьезна, поскольку решить ее можно только метоY

дом проб и ошибок.

Page 69: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 69

Рис. 2.9. Щелкните на ссылке, чтобы увидеть все допустимые константы

Изучив раздел справочной системы, посвященный методу OpenText,

можно заметить, что этот метод является в некотором смысле эквивалентом

мастера импорта текстов. Так, на первом шаге мастера необходимо выбрать

формат исходных данных YYYY С разделителями (Delimited) или Фиксированнойширины (Fixed width), YYYY а также формат файла и строку, с которой необходимо

начать импорт (рис. 2.10).

Другими словами, первый шаг мастера импорта текстов можно описать

тремя параметрами метода OpenText:

Origin:=1251StartRow:=1DataType:=xlDelimited

Page 70: ? Применение VBA и макросов в Microsoft® Excel

70 Часть I Первые шаги

Рис. 2.10. Первый шаг мастера импорта текстов описывается тремя па&раметрами метода OpenText

На втором шаге мастера импорта текстов производится выбор разделителя

для текстовых данных. Чтобы Excel не считал две последовательные запятые

одной, флажок Считать последовательные разделители одним (Treat conY

secutive delimiters as one) снят. Поля, содержащие запятую как часть данных

(например, ‘‘XYZ, Inc.’’), должны быть ограничены символом, выбранным в

раскрывающемся списке Ограничитель строк (Text qualifier) (рис. 2.11).

Рис. 2.11. Второй шаг мастера импорта текстов описывается семью па&раметрами метода OpenText

Второй шаг мастера импорта текстов можно описать следующими параY

метрами метода OpenText:

Page 71: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 71

TextQualifier:=xlDoubleQuoteConsecutiveDelimiter:=FalseTab:=FalseSemicolon:=FalseComma:=TrueSpace:=FalseOther:=False

На третьем шаге мастера импорта текстов определяется формат столбцов

данных. В рассмотренном примере мы оставили стандартный формат Общий(General) для всех столбцов, кроме первого, для которого был выбран формат

даты ДМГ (DMY) (рис. 2.12).

Рис. 2.12. Третий шаг мастера импорта текстов описывается всего лишьодним параметром метода OpenText

Третий шаг мастера импорта текстов полностью описывается параметром

FieldInfo метода OpenText.

Щелкнув на кнопке Подробнее (Advanced) диалогового окна Мастертекстов (импорт) — шаг 3 из 3 (Text Import Wizard — Step 3 of 3), можно выY

брать разделитель целой и дробной части, разделитель разрядов, а также укаY

зать на необходимость отображения знака ‘‘минус’’ в конце отрицательных

чисел (рис. 2.13).

Следует отметить, что средство записи макросов не генерирует код для паY

раметров DecimalSeparator и ThousandsSeparator до тех пор, пока не

будет выбран отличный от стандартного разделитель целой и дробной части и

разделитель разрядов, соответственно. В то же время, средство записи макроY

сов всегда генерирует код для параметра TrailingMinusNumbers.

Как видите, практически каждое действие, выполняемое с помощью польY

зовательского интерфейса Excel, находит отражение в фрагменте программY

ного кода макроса.

Page 72: ? Применение VBA и макросов в Microsoft® Excel

72 Часть I Первые шаги

Рис. 2.13. В диалоговом окне Дополнительнаянастройка импорта текста (Advanced Text Im&port Settings) можно определить три параметраметода OpenText

Рассмотрим следующую строку:

Selection.End(xlDown).Select

Щелкните на слове End и нажмите клавишу <F1>. На экране появится

диалоговое окне Context Help (Контекстная справка), предлагающее выбрать

один из двух разделов справочной системы, посвященный слову End. Один из

них находится в библиотеке Excel, а другой YYYY в библиотеке VBA (рис. 2.14).

Рис. 2.14. Иногда одному ключевому слову соответст&вует несколько разделов справочной системы

Чтобы не гадать, какой из двух разделов справочной системы вам нужен,

щелкните на кнопке Help (Справка). Как показано на рис. 2.15, раздел спраY

вочной системы из библиотеки VBA содержит сведения о выражении End. Это

не то, что нам нужно.

Закройте окно справочной системы, снова нажмите клавишу <F1> и выбеY

рите раздел, посвященный слову End, из библиотеки Excel. Свойство End возY

вращает объект Range, что эквивалентно последовательному нажатию клаY

виш <End> и <↑> или <End> и <↓> в пользовательском интерфейсе Excel.

Щелкнув на ссылке XlDirection, можно увидеть список параметров, допусY

тимых для передачи функции End (рис. 2.16).

Page 73: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 73

Рис. 2.15. Поиск нужного раздела справочной системы можно проводитьметодом проб и ошибок

Возврат объектов свойством

Ранее неоднократно упоминалось, что базовый синтаксис языка VBA предY

ставлен конструкцией Объект.Метод. В рассмотренной выше строке кода меY

тодом, очевидно, является метод .Select. Несмотря на то, что End — это

свойство, оно возвращает объект Range, а метод, таким образом, применяется

непосредственно к свойству.

Открыв раздел справочной системы, посвященный слову Selection,

можно обнаружить, что это также свойство, а не объект. Полное обращение к

свойству Selection выглядит как Application.Selection, однако в конY

тексте использования объектной модели Excel префикс Application можно

опустить. Если бы данный макрос выполнялся в текстовом редакторе Word,

нам обязательно потребовалось бы указать перед свойством .Selection пеY

ременную объекта для идентификации вызываемого приложения.

Page 74: ? Применение VBA и макросов в Microsoft® Excel

74 Часть I Первые шаги

Рис. 2.16. Нужный раздел справочной системы, посвященный свойству End

Тип возвращаемого свойством Application.Selection объекта зависит

от текущего выделенного элемента. Если это ячейка, свойство Applica-tion.Selection возвращает объект Range.

Использование отладчика кодаРедактор Visual Basic содержит великолепный отладчик, предназначенный

для поиска и устранения недостатков программного кода.

Пошаговое выполнение кода

Обычно на выполнение макроса уходит всего лишь несколько секунд. Если

во время этого произойдет какойYто сбой, отследить его будет очень трудно.

К счастью, отладчик Excel поддерживает пошаговое выполнение кода.

Разместите курсор посредине имени процедуры ИмпортСчета и выберите

команду меню Debug Step Into (Отладка Пошаговое выполнение) (или наY

жмите клавишу <F8>) (рис. 2.17).

Сейчас редактор Visual Basic находится в режиме пошагового выполнеY

ния кода. Строка, которая будет выполнена следующей, выделена желтым

цветом. Кроме того, на нее указывает желтая стрелка, расположенная слеY

ва (рис. 2.18).

Page 75: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 75

Рис. 2.17. Пошаговое выполнение кода позволяетобнаружить и устранить его недостатки

Рис. 2.18. Отладчик готов выполнить первую строку кода макроса

Выполнение строки Sub ИмпортСчета() приводит к входу в процедуру

ИмпортСчета(). Нажмите клавишу <F8>, чтобы выполнить эту строку и пеY

рейти к следующей. Редактор Visual Basic выделит желтым цветом фрагмент

кода, соответствующий методу OpenText. Нажмите клавишу <F8>. После

выполнения метода OpenText переключитесь в Excel с помощью комбинаY

ции клавиш <Alt+Tab> и убедитесь в успешном импорте файла Счет.txt.

Обратите внимание, что текущей выделенной ячейкой является ячейка A1(рис. 2.19).

Page 76: ? Применение VBA и макросов в Microsoft® Excel

76 Часть I Первые шаги

Рис. 2.19. Файл Счет.txt успешно импортирован в Excel

Переключитесь в редактор Visual Basic, воспользовавшись комбинацией

клавиш <Alt+Tab>. Нажмите клавишу <F8>, чтобы выполнить строку кода

макроса Selection.End(xlDown).Select. Переключившись в Excel,

можно увидеть, что теперь текущей выделенной ячейкой является ячейка A10(рис. 2.20).

Рис. 2.20. Выполнение команды Selection.End(xlDown).Select эквивалентно последовательному нажатию клавиш <End> и <↓>

Переключившись в редактор Visual Basic, нажмите клавишу <F8>, чтобы

выполнить команду Range("A14").Select. Вместо того чтобы выделить

ячейку в первой свободной строке после импортированных данных (A11),

макрос выделил ячейку A14, как показано на рис. 2.21.

Рис. 2.21. Записанный макрос допускает ошибку

Page 77: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 77

Обнаружив проблемный участок кода, остановите выполнение макроса,

выбрав команду меню Run Reset (Выполнить Сброс) или щелкнув на

кнопке панели инструментов Reset (Сброс) (рис. 2.22). Вернитесь в Excel и

отмените все действия, которые успел выполнить макрос. В данном случае заY

кройте файл Счет.txt без сохранения изменений.

Рис. 2.22. Щелчок на кнопке Reset приводит к остановке выполнения макроса

Точки прерывания

Длина некоторых макросов может достигать сотен строк. Чтобы добраться

к проблемному участку кода, совсем необязательно пошагово выполнять все

предшествующие ему строки. Создайте точку прерывания, и выполнение макY

роса будет остановлено на ее границе.

Чтобы создать точку прерывания, щелкните на полосе слева от строки коY

да, перед выполнением которой необходимо сделать остановку. Строка кода

будет выделена красноYкоричневым цветом, а слева от нее появится такого же

цвета маркер (рис. 2.23).

Рис. 2.23. Красно&коричневый маркер слева от строки кода свидетельствует о наличии точкипрерывания

Выберите команду Run Run Sub/UserForm (Выполнить Выполнить подY

программу/Пользовательскую форму) или нажмите клавишу <F5>. ВыполнеY

ние макроса остановится на границе точки прерывания, а соответствующая

Page 78: ? Применение VBA и макросов в Microsoft® Excel

78 Часть I Первые шаги

строка кода будет выделена желтым цветом. Нажмите клавишу <F8>, чтобы

продолжить выполнение макроса в пошаговом режиме (рис. 2.24).

Рис. 2.24. Строка кода, на которой установлена точка прерывания, выделена желтым цветом

Завершив отладку кода, следует удалить все точки прерывания. Чтобы удаY

лить точку прерывания, щелкните на соответствующей ей точке на полосе

слева от строки кода. Чтобы удалить все точки прерывания в проекте, выбериY

те команду меню Debug Clear All Breakpoints (Отладка Удалить все точки

прерывания) или воспользуйтесь комбинацией клавиш <Ctrl+Shift+F9>.

Перемещение по коду

Пошаговый режим отладки позволяет изменить порядок выполнения строк

кода. Чтобы пропустить фрагмент кода или вернуться к уже выполнявшимся

строкам, перетащите желтую стрелку, расположенную на полосе слева от кода.

При подведении указателя мыши к стрелке он меняет свою форму, как показано

на рис. 2.25. Перетащите желтую стрелку на строку кода, которая должна быть

выполнена следующей, или разместите на этой строке курсор и выберите коY

манду меню Debug Set Next Statement (Отладка Выполнить следующей).

Рис. 2.25. При подведении указателямыши к желтой стрелке он меняетсвою форму

Page 79: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 79

Выполнение фрагмента кодаИногда возникает необходимость в выполнении целого фрагмента кода, наY

пример, цикла. Вместо того чтобы возвращаться к одним и тем же строкам неY

сколько раз подряд, можно указать отладчику на необходимость выполнения

всего участка кода до указанной вами строки. Для этого разместите курсор на

требуемой строке и воспользуйтесь комбинацией клавиш <Ctrl+F8> или команY

дой меню Debug Run To Cursor (Отладка Выполнить до указанной строки).

Вычисление значения переменной или выраженияВ режиме пошагового выполнения кода можно просмотреть значение пеY

ременной или выражения (между прочим, средство записи кода никогда не

создает переменных).

Окно Immediate

Чтобы открыть окно Immediate (Быстрое выполнение) в редакторе Visual

Basic, нажмите комбинацию клавиш <Ctrl+G>. На рис. 2.26 приведен пример

вычисления различных выражений, таких как адрес текущей выделенной

ячейки, ее значение, а также имя активного рабочего листа.

Окно Immediate обычно располагается под окном просмотра программY

ного кода. Размер окна Immediate можно изменить, воспользовавшись маркеY

ром изменения размера окна (рис. 2.27).

Рис. 2.26. Пауза после выполнения каждойстроки кода позволяет узнать текущие значе&ния переменных или выражений

Рис. 2.27. Изменение размера окнаImmediate

Если содержимое окна Immediate не умещается на экране, его можно проY

смотреть с помощью полосы прокрутки, расположенной в правой части окна.

Выражение, значение которого необходимо вычислить с помощью окна

Immediate, не обязательно набирать каждый раз заново. К примеру, вычислим

значение выражения Selection.Address после выполнения нескольких

строк кода макроса (рис. 2.28).

Нажмите клавишу <F8>, чтобы выполнить следующую строку кода. ВмеY

сто повторного ввода выражения, установите курсор в конец содержащей это

выражение строки (рис. 2.29).

Page 80: ? Применение VBA и макросов в Microsoft® Excel

80 Часть I Первые шаги

Рис. 2.28. Вычисление значения выра&жения в окне Immediate

Рис. 2.29. Чтобы повторно вычис&лить результат выражения, устано&вите курсор в конец содержащей этовыражение строки и нажмите кла&вишу <Enter>

Чтобы повторно вычислить результат выражения, нажмите клавишу <Enter>.

Новый результат (в данном случае $1:$1) ‘‘сдвинет’’ старый ($E$14:$G$14) на

одну строку вниз (рис. 2.30).

Нажмите клавишу <F8> четыре раза, чтобы выполнить строку

Cells.Select. Снова расположите курсор в конце строки Print Selec-tion.Address в окне Immediate и нажмите клавишу <Enter>. Новый реY

зультат выражения Selection.Address сдвинет на одну строку вниз два

предыдущих (рис. 2.31).

Рис. 2.30. Старый результат выра&жения был сдвинут новым резуль&татом на одну строку вниз

Рис. 2.31. После выделения всехячеек текущий адрес выбранногодиапазона изменился на $1:$65536

Выражение, указанное в окне Immediate, можно изменить. Установите курсор

справа от слова Address и удалите его с помощью клавиши <Backspace>. Введите

выражение Rows.Count и нажмите клавишу <Enter>. В окне Immediate появится

значение, равное числу выделенных строк (рис. 2.32).

Изменение выражения в окне Immediate часто применяется при отладке

проблемных участков кода. В подобных ситуациях может пригодиться самая

различная информация YYYY имя активного рабочего листа (Print Active-

Page 81: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 81

sheet.Name), адрес выбранного диапазона ячеек (Print Selection.Address), адрес активной ячейки (Print ActiveCell.Address), формула

активной ячейки (Print ActiveCell.Formula), значение активной ячейки

(Print ActiveCell.Value или же просто Print ActiveCell, так как

Value является стандартным свойством ячейки) и т.д.

Рис. 2.32. Измените выражение, ука&занное в окне Immediate, и нажмитеклавишу <Enter>

Вычисление значения с помощью указателя мыши

Чтобы узнать значение выражения, подведите к нему указатель мыши и заY

держите в таком положении пару секунд. На экране появится подсказка, соY

держащая текущее значение выражения. Как правило, этот прием оказываетY

ся наиболее полезным при отладке циклов (см. главу 5, ‘‘Циклы и управление

выполнением кода’’). Пригодится он и при работе с автоматически сгенериY

рованным кодом. Заметьте, что выражение, значение которого вычисляется

описанным выше способом, не обязано содержаться в только что выполненY

ной строке кода. Как показано на рис. 2.33, макрос только выделил все ячейки

(при этом текущей активной ячейкой является ячейка A1). Подведя указатель

мыши к выражению ActiveCell.FormulaR1C1, можно узнать, что его знаY

чением является строка СчетДата.

Рис. 2.33. Чтобы узнать значение выражения, задержите над ним указатель мыши

Page 82: ? Применение VBA и макросов в Microsoft® Excel

82 Часть I Первые шаги

Иногда окно просмотра кода редактора Visual Basic не реагирует на указаY

тель мыши. Поскольку некоторые выражения не имеют значения, назвать

причину отсутствия подсказки удается не сразу. Подведите указатель мыши к

выражению, которое всегда должно иметь значение, например, к переменной.

При отсутствии подсказки щелкните на имени переменной и задержите над

ним указатель мыши до появления подсказки. Как показывает практика, это

всегда выводит редактор Visual Basic из состояния ступора.

Вам все еще не нравится Visual Basic? Бьюсь об заклад, что после знакомства

с его рабочей средой вы настроены гораздо менее категорично. Эти средства

отладки просто потрясающи!

Окно Watches

Окно Watches (Просмотр) позволяет отслеживать значение любого выраY

жения во время выполнения кода. Отследим текущий адрес выделенного диаY

пазона ячеек (Selection.Address).

Выберите команду меню редактора Visual Basic Debug Add Watch (Отладка

Добавить в окно просмотра).

Введите Selection.Address в текстовом поле Expression (Выражение)

диалогового окна Add Watch (Добавить в окно просмотра) и щелкните на

кнопке OK (рис. 2.34).

Окно Watches обычно располагается под окном просмотра программного

кода. Запустите макрос ИмпортСчета в режиме пошагового выполнения и

остановитесь перед строкой Range("A14").Select. Текущее значение выY

ражения Selection.Address будет равно $A$10 (рис. 2.35).

Рис. 2.34. Добавление в окно просмотра теку&щего адреса выделенного диапазона ячеек

Рис. 2.35. Окно Watches позволяет от&слеживать текущее значение выраже&ния на протяжении всего времени вы&полнения кода

Нажмите клавишу <F8>, чтобы выполнить строку Range("A14").Select.

В окне Watches будет отображен новый адрес выделенного диапазона ячеек YYYY

$A$14 (рис. 2.36).

Page 83: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 83

Рис. 2.36. Содержимое окна Watches обновляется после вы&полнения каждой строки кода

Установка точки прерывания с помощью окна Watches

Щелкните правой кнопкой мыши на значке с изображением очков в окне

Watches (Просмотр) и выберите команду контекстного меню Edit Watch(Изменить параметры просмотра). Установите переключатель Break WhenValue Changes (Приостановить при изменении значения) в группе переклюY

чателей Watch Type (Способ просмотра) диалогового окна Edit Watch(Изменить параметры просмотра) (рис. 2.37). Щелкните на кнопке OK.

Рис. 2.37. Установите переключатель BreakWhen Value Changes

Значок с изображением очков сменится на значок с изображением руки и

треугольника. Нажмите клавишу <F5> для выполнения макроса. Как только

значение выделенного диапазона ячеек изменится, выполнение макроса будет

приостановлено. Данная возможность является чрезвычайно полезной при

отладке кода.

Отслеживание состояния объекта с помощью окна Watches

Ранее было рассмотрено отслеживание значения свойства Selection.Address. Редактор Visual Basic позволяет также следить за состоянием целых

объектов, таких как объект Selection (рис. 2.38).

Page 84: ? Применение VBA и макросов в Microsoft® Excel

84 Часть I Первые шаги

Рис. 2.38. При отслеживании состояния объектарядом со значком с изображением очков появ&ляется значок с изображением знака “плюс”

Щелкните на значке с изображением знака ‘‘плюс’’, чтобы просмотреть все

свойства объекта Selection (рис. 2.39). Существование некоторых из них

окажется для вас настоящим сюрпризом. Кроме новых свойств наподобие

.AddIndent (значение False) и .AllowEdit (значение True), вы увидите

также уже знакомые свойства, такие как .Formula.

Рис. 2.39. Щелкните на значке с изображением знака “плюс”, чтобы просмотреть списоксвойств объекта и их текущих значений

Возле некоторых свойств объекта Selection, таких как коллекция Bor-ders, находится значок с изображением знака ‘‘плюс’’. Щелкните на нем,

чтобы получить более детальную информацию об объекте.

Page 85: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 85

Диспетчер объектовЧтобы открыть окно диспетчера объектов редактора Visual Basic, нажмите

клавишу <F2> (рис. 2.40).

Рис. 2.40. Чтобы открыть окно диспетчера объектов, нажмите клавишу <F2>

Диспетчер объектов позволяет просматривать библиотеку объектов Excel и

проводить поиск в ней. Распечатка списка всех объектов из этой библиотеки

занимает порядка 409 страниц текста, однако благодаря диспетчеру объектов

работать с библиотекой совсем нетрудно.

Окно диспетчера объектов занимает пространство окна просмотра проY

граммного кода. С помощью верхнего раскрывающегося списка можно выY

брать все подключенные библиотеки (All Libraries (Все библиотеки)), библиоY

теку Excel, Office, VBA, библиотеку каждой открытой рабочей книги, а также

все остальные библиотеки, указанные с помощью диалогового окна

References (Ссылки) (чтобы открыть диалоговое окно References, выберите

команду меню редактора Visual Basic Tools References (Сервис Ссылки)).

Раскройте список и выберите библиотеку Excel.

В левой части окна диспетчера объектов содержится список классов бибY

лиотеки Excel. Щелкните на имени класса Application. В правой части окY

на диспетчера объектов появится список свойств и методов объекта Appli-cation (рис. 2.41).

Page 86: ? Применение VBA и макросов в Microsoft® Excel

86 Часть I Первые шаги

Рис. 2.41. Выберите класс, а затем — метод или свойство. В нижней части окна диспетчераобъектов появится краткое описание выбранного элемента. Рядом с именем метода в правойчасти окна диспетчера объектов находится значок с изображением зеленой книги, а рядом сименем свойства — изображение учетной карточки с указывающей на нее кистью руки

Щелкните на имени свойства ActiveCell. В нижней части окна диспетчера

объектов появится краткое описание свойства ActiveCell, из которого можно

узнать тип возвращаемого этим свойством значения YYYY Range. Кроме того,

свойство ActiveCell предназначено только для чтения, что делает невозможY

ным присвоение ему значения с целью сдвинуть указатель активной ячейки.

Щелкните на ссылке Range в нижней части окна диспетчера объектов,

чтобы увидеть список свойств и методов объекта Range, а значит и свойства

ActiveCell. Щелкните на имени любого свойства или метода объекта

Range, а затем YYYY на кнопке с изображением желтого вопросительного знака в

верхней части диспетчера объектов. В результате откроется окно справочной

системы с разделом, посвященным выбранному элементу.

Введите любое ключевое слово в поле ввода раскрывающегося списка, наY

ходящегося справа от кнопки с изображением бинокля, и щелкните на этой

кнопке, чтобы найти все подходящие под данное ключевое слово элементы

библиотеки Excel.

Чтобы закрыть окно диспетчера объектов и вернуться к окну просмотра

программного кода, щелкните на кнопке с изображением крестика в верхнем

правом углу окна диспетчера объектов (рис. 2.42).

Page 87: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 87

Рис. 2.42. Чтобы закрыть окно диспетчера объектов, щелкните на кнопке с изображением кре&стика в верхнем правом углу окна

5 советов по исправлению и оптимизацииавтоматически сгенерированного кода

Приблизившись к концу второй главы, было бы неплохо исправить хотя

бы один из двух имеющихся у нас проблемных макросов. Ниже приведено

5 советов, направленных на оптимизацию и исправление автоматически сгеY

нерированного кода.

Совет 1: ничего не выделяйте

Отличительной особенностью автоматически сгенерированного кода являY

ется выделение элементов перед их дальнейшим использованием. В некотоY

ром смысле это подразумевает копирование действий, совершаемых с помоY

щью пользовательского интерфейса Excel. Так, чтобы сделать текст ячейки

утолщенным, ее необходимо сначала выделить.

Подобная практика является совершенно излишней в VBA. (Существуют

исключения, которые, однако же, обусловлены не вполне корректным повеY

дением некоторых методов, требующих для своего выполнения предварительY

ного выделения объекта диаграммы.) Чтобы сделать текст ячейки утолщенY

Page 88: ? Применение VBA и макросов в Microsoft® Excel

88 Часть I Первые шаги

ным, последнюю можно и не выделять. Ниже показан пример преобразования

двух строк автоматически сгенерированного кода макроса в одну.

Автоматически сгенерированный код:

Rows("1:1").SelectSelection.Font.Bold = True

Оптимизированный код:

Rows("1:1").Font.Bold = True

Подобное преобразование имеет несколько преимуществ. ВоYпервых, коY

личество строк кода уменьшается почти что вдвое. ВоYвторых, код выполняетY

ся быстрее.

Чтобы оптимизировать приведенный выше фрагмент кода, выделите

фрагмент Select в верхней строке кода и фрагмент Selection. — в нижY

ней, после чего щелкните на кнопке <Delete> (рис. 2.43 и 2.44).

Рис. 2.43. Выделите фрагмент ко&да так, как показано на рисунке...

Рис. 2.44. ...и нажмите клавишу<Delete>

Совет 2: перемещайтесь на последнюю строку данныхс конца рабочего листа

Никогда не доверяйте данным, поступившим из внешних источников. РаY

но или поздно вы столкнетесь с содержащимися в них ошибками, например,

с отсутствием номера счета. Вне зависимости от причины ошибок (сбой в

электропитании или человеческий фактор), следует запомнить одно — нет

никаких оснований полагать, что все ячейки содержат данные.

С учетом сказанного выше, последовательное нажатие клавиш <End> и

<↓> приводит не к перемещению на последнюю строку данных, а к перемеY

щению на последнюю строку данных в определенном диапазоне ячеек.

К примеру, на рис. 2.45 последовательное нажатие клавиш <End> и <↓> приY

ведет к перемещению в ячейку A6, а не в ячейку A10.

Рис. 2.45. Последовательное нажатие клавиш <End> и <↓>(выражение End(xlDown) в VBA) срабатывает некорректно приотсутствии значения в ячейке

Page 89: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 89

Одним из возможных решений этой проблемы является перемещение в

конец рабочего листа Excel и последовательное нажатие клавиш <End> и <↑>.

В контексте пользовательского интерфейса Excel подобная процедура не имеY

ет смысла, однако она способна помочь макросу VBA переместиться на нужY

ную строку:

Range("A65536").End(xlUp)

Внимание Начиная с Excel 97 максимальное количество строк в Excel равно 65 536 (ранее оноравнялось 16 384). Чтобы обеспечить совместимость кода макроса с любой вер&сией Excel, жестко закодированное значение 65 535 рекомендуется заменить вы&ражением Rows.Count (максимальное число строк в текущей версии Excel).Строка Cells(Row.Count, 1).End(xlUp) гарантирует правильность работымакроса как в будущих, так и в предыдущих версиях Excel.

Совет 3: используйте переменные

Средство записи макросов никогда не создает переменные. О переменных

речь пойдет далее в этой книге, а пока что можно отметить, что, как и в BASIC,

переменные используются для хранения значений.

Создадим переменную для хранения номера последней строки данных. ПереY

менным рекомендуется давать информативные имена, например, FinalRow.

FinalRow = Range("A65536").End(xlUp).Row

Зная номер последней строки данных, разместить в столбце A следующей

строки слово ‘‘Всего’’ можно с помощью такого кода:

Range("A" & FinalRow + 1).Value = "Всего"

См. также Более простой способ обращения к этой ячейке рассматривается в разделе“Обращение к диапазону ячеек с помощью свойства Cells” главы 3 на с. 99.

Переменные можно использовать и при построении формулы. К примеру,

приведенная ниже формула суммирует все значения, начиная с ячейки E2и заканчивая ячейкой, находящейся на пересечении последней строки данных

и столбца E:

Range("E" & FinalRow + 1).Formula = "=SUM(E2:E" & FinalRow & ")"

Совет 4: используйте одно выражение для копированияи вставки данных

Автоматически сгенерированный код ‘‘славится’’ своей четырехшаговой

процедурой копирования и вставки данных, подразумевающей выделение исY

ходного диапазона ячеек, его копирование, выделение целевого диапазона

Page 90: ? Применение VBA и макросов в Microsoft® Excel

90 Часть I Первые шаги

ячеек и, наконец, вызов метода ActiveSheet.Paste. Метод Copy, примеY

няемый к диапазону ячеек, обладает намного более широкой функциональноY

стью, позволяя задать источник и назначение копируемых данных с помощью

одного выражения.

Ниже приведен фрагмент автоматически сгенерированного кода:

Range("E14").SelectSelection.CopyRange("F14:G14").SelectActiveSheet.Paste

А это YYYY тот же код после оптимизации:

Range("E14").Copy Destination:=Range("F14:G14")

Совет 5: используйте конструкцию With...End With

Ниже приведен автоматически сгенерированный код, изменяющий разY

личные параметры шрифта выделенного диапазона ячеек:

Range("A14:G14").SelectSelection.Font.Bold = TrueSelection.Font.Size = 12Selection.Font.ColorIndex = 5Selection.Font.Underline = xlUnderlineStyleDoubleAccounting

При выполнении этого кода макрос должен 4 раза подряд вычислить знаY

чение выражения Selection.Font. Поскольку каждый раз обращение проY

исходит к одному и тому же объекту, его имя рекомендуется указать в начале

блока With. Чтобы сослаться на объект внутри блока With, соответствующие

строки кода необходимо предварить символом точки, как показано ниже:

With Range("A14:G14").Font .Bold = True .Size = 12 .ColorIndex = 5 .Underline = xlUnderlineStyleDoubleAccountingEnd With

Исправление и оптимизация автоматическисгенерированного кода

Практикум

Изменение автоматически сгенерированного кодаИспользуя приведенные выше советы, превратим автоматически сгенерированныйкод макроса ИмпортСчета (см. ниже) в эффективный и профессиональный код.Sub ИмпортСчета()'' ИмпортСчета Макрос' Макрос записан 03.01.2005 (Александр Журавлев)

Page 91: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 91

'' Сочетание клавиш: Ctrl+и' Workbooks.OpenText Filename:= _ "C:\Счет.txt", Origin:=1251, StartRow:=1, _ DataType:=xlDelimited, TextQualifier:= xlDoubleQuote, _ ConsecutiveDelimiter:=False, Tab:=False, Semicolon:= _ False, Comma:=True, Space:=False, Other:=False, _ FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), _ Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1)), _ TrailingMinusNumbers:=True Selection.End(xlDown).Select Range("A14").Select ActiveCell.FormulaR1C1 = "Всего" Range("E14").Select Selection.FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)" Selection.AutoFill Destination:=Range("E14:G14"), _Type:=xlFillDefault Range("E14:G14").Select Rows("1:1").Select Selection.Font.Bold = True Rows("14:14").Select Selection.Font.Bold = True Cells.Select Selection.Columns.AutoFitEnd Sub

Чтобы исправить и оптимизировать код макроса, выполните следующие действия.1. Оставьте метод Workbook.OpenText без изменений.

2. В следующей строке кода осуществляется попытка перейти на последнюю стро&ку с данными:Selection.End(xlDown).Select

Ничего не выделяйте. Кроме того, создайте две переменные — для номера по&следней строки с данными и для номера итоговой строки. Чтобы избежать про&блемы пустой ячейки, переместитесь на последнюю строку с данными с концарабочего листа:

' Найти последнюю строку с даннымиFinalRow = Range("A65536").End(xlUp).RowTotalRow = FinalRow + 1

3. Следующие строки кода соответствуют вводу слова “Всего” в столбец A итого&вой строки:

Range("A14").SelectActiveCell.FormulaR1C1 = "Всего"

Воспользуйтесь созданной ранее переменной TotalRow и откажитесь от выде&ления ячейки, как показано ниже:

' Создание итоговой строкиRange("A" & TotalRow).Value = "Всего"

4. Приведенные ниже строки кода описывают ввод формулы суммы в столбец E иее копирование в столбцы F и G:

Range("E14").SelectSelection.FormulaR1C1 = "=SUM(R[-12]C:R[-1]C)"Selection.AutoFill Destination:=Range("E14:G14"), _

Page 92: ? Применение VBA и макросов в Microsoft® Excel

92 Часть I Первые шаги

Type:=xlFillDefaultRange("E14:G14").Select

Вы уже наверное догадались, что выделять здесь абсолютно нечего. Приведен&ный ниже код помещает формулу суммы в требуемые ячейки итоговой строки(формат ссылок R1C1 рассматривается в главе 6, “Стиль записи ссылок R1C1”):

Range("E" & TotalRow).Resize(1, 3).FormulaR1C1 = _"=SUM(R2C:R[-1]C)"

5. Ниже приведен код, сгенерированный средством записи макросов при фор&матировании строки заголовков столбцов и итоговой строки:

Rows("1:1").SelectSelection.Font.Bold = TrueRows("14:14").SelectSelection.Font.Bold = True

А вот и его оптимизированная версия: Rows("1:1").Font.Bold = True

Rows(TotalRow & ":" & TotalRow).Font.Bold = True

6. Перед вызовом метода AutoFit средство записи макросов выделяет все ячей&ки рабочего листа:

Cells.SelectSelection.Columns.AutoFit

Как вы уже догадались, это совершенно излишне: Cells.Columns.AutoFit

7. Ниже приведен комментарий, добавляемый к каждому макросу при его создании:' ИмпортСчета Макрос' Макрос записан 03.01.2005 (Александр Журавлев)'' Сочетание клавиш: Ctrl+и

Исправив и оптимизировав автоматически сгенерированный код, вы имеетеполное право заменить слово “записан” на “создан”, как показано ниже:' ИмпортСчета Макрос' Макрос создан 03.01.2005 (Александр Журавлев)'' Сочетание клавиш: Ctrl+и

Ниже приведен полный код исправленного и оптимизированного макроса.Sub ИмпортСчетаИсправленный()'' ИмпортСчета Макрос' Макрос создан 03.01.2005 (Александр Журавлев)'' Сочетание клавиш: Ctrl+и' Workbooks.OpenText Filename:= _ "C:\Счет.txt", Origin:=1251, StartRow:=1, _ DataType:=xlDelimited, TextQualifier:= xlDoubleQuote, _ ConsecutiveDelimiter:=False, Tab:=False, Semicolon:= _ False, Comma:=True, Space:=False, Other:=False, _ FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), _ Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1)), _ TrailingMinusNumbers:=True ' Найти последнюю строку с данными

Page 93: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Visual Basic for Applications Глава 2 93

FinalRow = Range("A65536").End(xlUp).Row TotalRow = FinalRow + 1 ' Создание итоговой строки Range("A" & TotalRow).Value = "Всего" Range("E" & TotalRow).Resize(1, 3).FormulaR1C1 = _ "=SUM(R2C:R[-1]C)" Rows("1:1").Font.Bold = True Rows(TotalRow & ":" & TotalRow).Font.Bold = True Cells.Columns.AutoFitEnd Sub

Следующий шагВ этой главе были рассмотрены основы синтаксиса языка программироваY

ния Visual Basic for Applications, использование справочной системы, средств

отладки, а также несколько советов по исправлению и оптимизации автомаY

тически сгенерированного кода.

Следующая глава посвящена более детальному изучению диапазонов ячеек.

Page 94: ? Применение VBA и макросов в Microsoft® Excel
Page 95: ? Применение VBA и макросов в Microsoft® Excel

3Объект Range ..................................95Обращение к диапазону ячеекс помощью указания адресаего верхнего левого инижнего правого угла ...................96Обращение к диапазонуячеек, расположенному надругом рабочем листе ..................97Обращение к диапазону ячеекс помощью указания егоотносительного адреса................ 98Обращение к диапазону ячеекс помощью свойства Cells.............99Обращение к диапазону ячеекс помощью свойства Offset........100Изменение размерадиапазона ячеек с помощьюсвойства Resize ..............................101Обращение к диапазону ячеекс помощью свойств Columns иRows ................................................ 102Объединение диапазоновячеек с помощью методаUnion................................................ 103Создание нового диапазонаячеек из пересекающихсядиапазонов с помощьюметода Intersect ............................ 103Проверка пустых ячеек спомощью функции IsEmpty .......104Обращение к диапазону ячеекс помощью свойстваCurrentRegion................................ 105Обращение к диапазонунесмежных ячеек с помощьюколлекции Areas...........................108Следующий шаг............................ 109

Глава 3

Ðàáîòàñ äèàïàçîíîì ÿ÷ååê

Диапазон ячеек представляет соY

бой любое их объединение в пределах

одного рабочего листа. Примерами

диапазона ячеек являются ячейка,

строка, столбец и т.п. Объект

Range YYYY один из наиболее популярY

ных объектов Excel VBA.

В этой главе будут рассмотрены

различные способы обращения к диаY

пазону ячеек в пределах как одного, так

и нескольких рабочих листов, объедиY

нение диапазонов ячеек, а также создаY

ние нового диапазона ячеек из неY

скольких пересекающихся диапазонов.

Объект RangeРассмотрим следующую иерархию

объектов Excel:

Application Workbook WorksheetRange

Объект Range является свойством

объекта Worksheet. Обе приведенY

ные ниже строки кода выполняют

одно и то же действие, если рабочий

лист Worksheets(1) является акY

тивным рабочим листом.

Range("A1")Worksheets(1).Range("A1")

Таким образом, существует неY

сколько способов обращения к диаY

пазону ячеек. Range("A1") является

наиболее распространенным из них в

основном за счет того, что это станY

дартный способ обращения к диапаY

зону ячеек, использующийся средстY

Page 96: ? Применение VBA и макросов в Microsoft® Excel

96 Часть I Первые шаги

вом записи макросов. Приведенные ниже строки кода полностью эквиваY

лентны:

Range("D5")[D5]Range("B3").Range("C3")Cells(5, 4)Range("A1").Offset(4, 3)Range("МойДиапазон") 'при условии что МойДиапазон - имя ячейки D5

Более подробно различные способы обращения к диапазону ячеек расY

сматриваются далее в этой главе.

Обращение к диапазону ячеек с помощьюуказания адреса его верхнего левого и нижнегоправого угла

Существует два различных синтаксиса команды Range. Согласно первому

из них обращение к диапазону ячеек осуществляется путем указания его полY

ного адреса, как это принято в формулах Excel:

Range("A1:B5").Select

Согласно второму синтаксису обращение к диапазону ячеек осуществляетY

ся путем указания адреса его верхнего левого и нижнего правого угла, как поY

казано ниже:

Range("A1", "B5").Select

Вместо адреса любого из углов можно подставить имя диапазона ячеек,

функцию Cells, а также свойство ActiveCell. В следующей строке кода

осуществляется выделение прямоугольного диапазона ячеек, в верхнем левом

углу которого находится ячейка A1, а в нижнем правом углу YYYY активная ячейка:

Range("A1", ActiveCell).Select

А вот как выделить диапазон ячеек, в верхнем левом углу которого нахоY

дится активная ячейка, а в нижнем правом углу YYYY ячейка, находящаяся на

5 строк ниже и на 2 столбца правее активной ячейки:

Range(ActiveCell, ActiveCell.Offset(5, 2)).Select

Сокращенная форма обращения к диапазону ячеек

Сокращенная форма обращения к диапазону ячеек предполагает использоY

вание квадратных скобок ([]), как показано в табл. 3.1.

Именованные диапазоны ячеек

Именованные диапазоны ячеек можно использовать не только на рабочих

листах и в формулах Excel, но также и в VBA.

Ниже приведен пример обращения к именованному диапазону ячеек

МойДиапазон на рабочем листе Лист1:

Worksheets("Лист1").Range("МойДиапазон").Select

Page 97: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 97

Обратите внимание, что имя диапазона ячеек взято в кавычки. Это отличиY

тельная особенность использования именованных диапазонов в VBA. Без каY

вычек Excel воспримет имя диапазона ячеек как объявленную в макросе переY

менную. Единственное исключение касается сокращенной формы обращения

к диапазону ячеек, которая не предусматривает заключение имени диапазона

в кавычки.

Таблица 3.1. Сокращенная форма обращения к диапазону ячеек

Стандартная форма Сокращенная форма

Range("D5") [D5]

Range("A1:D5") [A1:D5]

Range("A1:D5", "G6:I17") [A1:D5, G6:I17]

Range("МойДиапазон") [МойДиапазон]

Обращение к диапазону ячеек, расположенномуна другом рабочем листе

Переключение между рабочими листами может существенно замедлить

выполнение кода макроса. Чтобы избежать этого, можно обратиться непоY

средственно к объекту Worksheet, как показано ниже:

Worksheets("Лист1").Range("A1")

В приведенном выше коде происходит обращение к рабочему листу Лист1,

даже если активным рабочим листом на данный момент является лист Лист2.

Чтобы обратиться к диапазону ячеек в другой рабочей книге, воспользуйY

тесь объектами Workbook, Worksheet и Range, как показано ниже:

Workbooks("Счета.xls").Worksheets("Лист1").Range("A1")

Будьте внимательны, используя свойство Range в качестве аргумента друY

гого свойства Range. В подобных случаях необходима полная идентификация

диапазона ячеек. Предположим, что активным рабочим листом является лист

Лист1, а суммирование данных производится на листе Лист2 так, как покаY

зано ниже:

WorksheetFunction.Sum(Worksheets("Лист2").Range(Range("A1"), _Range("A7")))

Приведенная выше строка кода не будет выполняться, поскольку Excel не

распространит ссылку на объект Worksheet на вложенные объекты Range.

Чтобы исправить ситуацию, можно поступить так:

WorksheetFunction.Sum(Worksheets("Лист2").Range(Worksheets( _"Лист2").Range("A1"), Worksheets("Лист2").Range("A7")))

Однако еще лучше упростить эту достаточно длинную строку кода с

помощью конструкции With...End, позволяющей заменить выражения

Page 98: ? Применение VBA и макросов в Microsoft® Excel

98 Часть I Первые шаги

Worksheets("Лист2").Range более короткой формой .Range, как поY

казано ниже:

With Worksheets("Лист2") WorksheetFunction.Sum(.Range(.Range("A1"), .Range("A7")))End With

Обращение к диапазону ячеек с помощьюуказания его относительного адреса

Обычно объект Range выступает в качестве свойства рабочего листа. ВмеY

сте с тем, он может быть свойством другого объекта Range, внося неразбериху

в и без того непростой программный код. Рассмотрим пример:

Range("B5").Range("C3").Select

В результате выполнения приведенного выше кода выделяется ячейка D7.

Чтобы понять, почему так происходит, рассмотрим ячейку C3. Ячейка C3 расY

положена на две строки ниже и на два столбца правее ячейки A1. Однако в

указанном выше коде точкой отсчета является ячейка B5. Другими словами,

VBA выделит ячейку, которая находится на том же смещении относительно

ячейки B5, что и ячейка C3 относительно ячейки A1 (на две строки ниже и на

два столбца правее), а именно D7.

Подобный стиль записи программного кода является весьма неинтуитивY

ным. На первый взгляд указанные в строке кода адреса ячеек не имеют ни маY

лейшего отношения к адресу выделяемой ячейки!

Тем не менее, данный синтаксис может пригодиться при обращении к

ячейке, расположенной на определенном смещении относительно активной

ячейки. К примеру, в результате выполнения приведенной ниже строки кода

выделяется ячейка, расположенная на 3 строки ниже и на 4 столбца правее теY

кущей активной ячейки:

Selection.Range("E4").Select

Аналогичного результата (с применением куда более понятного синтаксиY

са) можно добиться путем использования свойства Offset, которое рассматY

ривается далее в этой главе.

Зачем же нужно знать о существовании такого неудобного способа обраY

щения к диапазону ячеек? Дело в том, что именно он пришелся ‘‘по душе’’

средству записи макросов. Ниже приведена одна из строк кода, сгенерированY

ных при записи макроса импорта счета с использованием относительных ссыY

лок (см. главу 1, ‘‘Excel и VBA YYYY гремучая смесь’’):

ActiveCell.Offset(0, 4).Range("A1").Select

Выполнение этого кода приведет к выделению ячейки, соответствующей

ячейке A1 с учетом смещения относительно активной ячейки на 4 столбца

вправо.

Page 99: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 99

Обращение к диапазону ячеек с помощьюсвойства Cells

Свойство Cells используется для обращения ко всем ячейкам объекта

Range, будь то целый рабочий лист или определенный диапазон ячеек.

К примеру, результатом выполнения приведенной ниже строки кода является

выделение всех ячеек активного рабочего листа:

Cells.Select

Использование свойства Cells вместе с объектом Range выглядит избыY

точным:

Range("A1:D5").Cells

Что делает объект Cells действительно полезным, так это его свойство

Item, которое позволяет обратиться к любой ячейке диапазона.

Ниже приведен синтаксис использования свойства Item с объектом Cells:

Cells.Item(Строка, Столбец)

Идентификацию строки разрешается проводить только с помощью числоY

вого значения, а идентификацию столбца YYYY с помощью числового или строY

кового значения. В обеих приведенных ниже строках кода осуществляется обY

ращение к ячейке C5:

Cells.Item(5, "C")Cells.Item(5, 3)

Поскольку свойство Item является свойством по умолчанию объекта

Range, справедлива следующая сокращенная запись:

Cells(5, "C")Cells(5, 3)

Возможность использования числовых значений при указании параметров

будет по достоинству оценена при создании циклов. Для выделения ячейки

средство записи макросов применяет выражение наподобие Range("A1").Select, а для выделения диапазона ячеек YYYY Range("A1:C5").Select.

Следующие строки выдержаны в стиле автоматически сгенерированного кода:

FinalRow = Range("A65536").End(xlUp).RowFor i = 1 To FinalRow Range("A" & i & ":E" & i).Font.Bold = TrueNext i

В результате использования ‘‘недружелюбного’’ синтаксиса цикл, выдеY

ляющий ячейки в столбцах A–E с помощью утолщения шрифта, оказался

весьма сложным для восприятия. Попробуем записать его несколько иначе:

FinalRow = Cells(65536, 1).End(xlUp).RowFor i = 1 To FinalRow Cells(i, "A").Resize(, 5).Font.Bold = TrueNext i

Использование свойств Cells и Resize вместо адреса диапазона ячеек

делает код цикла более наглядным.

Page 100: ? Применение VBA и макросов в Microsoft® Excel

100 Часть I Первые шаги

Использование свойства Cells в качестве параметрасвойства Range

Свойство Cells можно использовать в качестве параметра свойства Range.

Приведенная ниже строка кода описывает диапазон ячеек A1:E5:

Range(Cells(1, 1), Cells(5, 5))

Применение подобного подхода оправдано в случае необходимости исY

пользования переменных, как в предыдущем примере кода цикла.

Обращение к диапазону ячеекс помощью свойства Offset

Свойство Offset используется средством записи макросов при генерироY

вании кода в режиме относительных ссылок. Это свойство позволяет обраY

щаться к ячейке с помощью относительного адреса, отсчитываемого от адреса

активной ячейки.

Ниже приведен синтаксис использования свойства Offset:

Range.Offset(СмещениеПоСтрокам, СмещениеПоСтолбцам)

Чтобы обратиться к ячейке F5 при условии, что текущей активной ячейкой

является ячейка A1, используйте выражение

Range("A1").Offset(RowOffset:=4, ColumnOffset:=5)

или его сокращенную форму

Range("A1").Offset(4, 5)

Отсчет адресов ячеек ведется с адреса ячейки A1. Сама ячейка A1 при этом

не учитывается.

Одна из замечательных особенностей свойства Offset заключается в отY

сутствии необходимости указывать оба параметра одновременно. Чтобы обраY

титься к ячейке, расположенной на один столбец правее ячейки A1, испольY

зуйте любое из следующих выражений:

Range("A1").Offset(ColumnOffset:=1)Range("A1").Offset(, 1)

А вот как обратиться к ячейке, расположенной на одну строку выше

ячейки B2:

Range("B2").Offset(RowOffset:=-1)Range("B2").Offset(-1)

Рассмотрим таблицу с двумя столбцами, в одном из которых перечислены проY

дукты питания, а в другом YYYY их запасы. Чтобы найти продукт, запасы которого

подошли к концу, и отметить это путем размещения в следующей ячейке слова

‘‘ПОПОЛНИТЬ’’, можно воспользоваться следующим макросом:

Set Rng = Range("B1:B16").Find(What:="0", LookAt:=xlWhole, _LookIn:=xlValues)Rng.Offset(, 1).Value = "ПОПОЛНИТЬ"

Page 101: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 101

Результат выполнения макроса показан на рис. 3.1.

Свойство Offset позволяет смещать не только отдельные ячейки, но даже

целые диапазоны. Приведенная ниже строка кода смещает диапазон ячеек

A1:C3 на одну строку вниз и на один столбец правее так, что он переходит в

диапазон ячеек B2:D4 (рис. 3.2).

Range("A1:C3").Offset(1, 1)

Рис. 3.1. Результат выполнения мак&роса, находящего продукты с ис&текшими запасами

Рис. 3.2. Сдвиг диапазона ячеек с помо&щью команды Range("A1:C3").Offset(1, 1).Select

Изменение размера диапазона ячеек с помощьюсвойства Resize

Свойство Resize позволяет изменять размер диапазона ячеек, используя в

качестве отправной точки текущую активную ячейку.

Ниже приведен синтаксис использования свойства Resize:

Range.Resize(КоличествоСтрок, КоличествоСтолбцов)

Чтобы создать диапазон ячеек B3:D13, используйте выражение

Range("B3").Resize(RowSize:=11, ColumnSize:=3)

или его сокращенную форму

Range("B3").Resize(11, 3)

Как и свойство Offset, свойство Resize не требует указания обоих параY

метров одновременно. Чтобы увеличить размер диапазона ячеек до двух

столбцов, используйте любое из следующих выражений:

Range("B3").Resize(ColumnSize:=2)Range("B3").Resize(, 2)

А вот как увеличить размер диапазона ячеек до двух строк:

Range("B3").Resize(RowSize:=2)Range("B3").Resize(2)

Page 102: ? Применение VBA и макросов в Microsoft® Excel

102 Часть I Первые шаги

Возвратимся к таблице с продуктами питания. Чтобы найти продукт, запаY

сы которого заканчиваются, и отметить это путем выделения цветом ячеек

с названием продукта и его запасами, воспользуйтесь следующим макросом

(рис. 3.3):

Set Rng = Range("B1:B16").Find(What:="0", LookAt:=xlWhole, _LookIn:=xlValues)Rng.Offset(, -1).Resize(, 2).Interior.ColorIndex = 15

Рис. 3.3. Изменение размерадиапазона ячеек в действии

Здесь свойство Offset используется для изменения активной ячейки,

а свойство Resize — для увеличения размера диапазона до двух столбцов.

Точно так же можно изменить и размер диапазона, состоящего из нескольY

ких ячеек. К примеру, чтобы увеличить размер именованного диапазона до

двух столбцов, воспользуйтесь следующим выражением:

Range("Продукты").Resize(, 2)

Помните, что параметры свойства Resize обозначают размер целевого

диапазона ячеек, который необходимо создать.

Обращение к диапазону ячеек с помощью свойствColumns и Rows

Свойства Columns и Rows используются для обращения к столбцам и

строкам диапазона ячеек и возвращают соответствующий объект Range.

Ранее мы рассматривали следующую строку кода макроса:

FinalRow = Range("A65536").End(xlUp).Row

В результате ее выполнения переменной FinalRow присваивается номер

последней строки (объект Range), столбец A которой содержит какиеYлибо

данные. Зная номер последней строки с данными, можно создать цикл, поY

очередно обрабатывающий все значащие строки рабочего листа.

Page 103: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 103

Внимание Для корректного использования некоторых свойств объектов Columns и Rows не&обходимо наличие непрерывного диапазона ячеек. К примеру, результат следую&щего выражения будет равен 9, так как подсчет строк будет проведен только попервому диапазону ячеек:

Range("A1:B9, C10:D19").Rows.Count

Если же не группировать несмежные диапазоны ячеек (как показано ниже), то ре&зультат подсчета количества строк будет равен 19:

Range("A1:B9", "C10:D19").Rows.Count

Объединение диапазонов ячеек с помощьюметода Union

Метод Union позволяет объединить два или более несоприкасающихся

диапазона ячеек. Он возвращает временный объект, предназначенный для

манипулирования объединенным диапазоном:

Application.Union(аргумент1 ,аргумент2 ,...)

В результате выполнения приведенного ниже кода два именованных диаY

пазона ячеек будут объединены, заполнены случайными числовыми значеY

ниями и выделены путем утолщения шрифта:

Set UnionRange = Union(Range("Диапазон1"), Range("Диапазон2"))With UnionRange' В англоязычной версии Excel:' .Formula = "=RAND()" .FormulaLocal = "=СЛЧИС()" .Font.Bold = TrueEnd With

Создание нового диапазона ячеекиз пересекающихся диапазонов с помощьюметода Intersect

Метод Intersect возвращает диапазон ячеек, полученный в результате

пересечения нескольких диапазонов:

Application.Intersect(аргумент1 ,аргумент2 ,...)

В результате выполнения приведенного ниже кода будет создан новый диапаY

зон ячеек, полученный в результате пересечения двух существующих диапазонов.

Ячейки нового диапазона выделены цветом, как показано на рис. 3.4.

Set IntersectRange = Intersect(Range("Диапазон1"), _Range("Диапазон2"))IntersectRange.Interior.ColorIndex = 6

Page 104: ? Применение VBA и макросов в Microsoft® Excel

104 Часть I Первые шаги

Рис. 3.4. Метод Intersect возвращает диапазон ячеек, по&лученный в результате пересечения нескольких диапазонов

Проверка пустых ячеек с помощьюфункции IsEmpty

Функция IsEmpty возвращает булево значение, определяющее, является

ячейка пустой (True) или нет (False). Ячейка является пустой, если она не

содержит какихYлибо данных (даже символов пробела).

IsEmpty(Ячейка)

На рис. 3.5 показана таблица с несколькими группами данных, разделенY

ными пустой строкой.

Рис. 3.5. Группы данных разделены пустой строкой

С помощью следующего кода проведем поиск пустых строк (точнее, пусY

тых ячеек в столбце A) и выделим цветом их первые 4 ячейки (рис. 3.6):

LastRow = Range("A65536").End(xlUp).RowFor i = 1 To LastRow If IsEmpty(Cells(i, 1)) Then Cells(i, 1).Resize(1, 4).Interior.ColorIndex = 1

Page 105: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 105

End IfNext i

Рис. 3.6. Первые 4 ячейки строк&разделителейвыделены черным цветом

Обращение к диапазону ячеек с помощьюсвойства CurrentRegion

Свойство CurrentRegion возвращает объект, представляющий непреY

рывный диапазон ячеек. С помощью этого свойства можно обратиться к диаY

пазону ячеек, ограниченному по крайней мере одной пустой строкой или одY

ним пустым столбцом:

ДиапазонЯчеек.CurrentRegion

В результате выполнения приведенной ниже строки кода будет выделен

диапазон ячеек A1:D3 — непрерывный диапазон ячеек, включающий в себя

ячейку A1 (рис. 3.7):

Range("A1").CurrentRegion.Select

Рис. 3.7. Используйте свойство CurrentRe-gion для обращения к непрерывному диапа&зону ячеек, включающему в себя текущую ак&тивную ячейку

Page 106: ? Применение VBA и макросов в Microsoft® Excel

106 Часть I Первые шаги

Свойство CurrentRegion рекомендуется использовать для обращения к

таблицам, размер которых постоянно меняется.

Практикум

Выделение ячеек, соответствующих определенномукритерию, с помощью метода SpecialCellsДалеко не все пользователи Excel знают о существовании диалогового окнаВыделение группы ячеек (Go To Special). Нажмите клавишу <F5>, чтобы открытьдиалоговое окно Переход (Go To) (рис. 3.8).

Рис. 3.8. Чтобы открыть диалоговое окно Выделение группы ячеек, щелкните на кноп&

ке Выделить

Щелкните на кнопке Выделить (Special) в левом нижнем углу диалогового окнаПереход, чтобы открыть диалоговое окно Выделение группы ячеек (рис. 3.9).Диалоговое окно Выделение группы ячеек позволяет выделить только пустыеячейки, только видимые ячейки или же только ячейки, содержащие формулы.Возможность выделения только видимых ячеек очень полезна при автоматиче&ской фильтрации данных.Возможности диалогового окна Выделение группы ячеек могут быть реализованыс помощью метода VBA SpecialCells. Этот метод позволяет работать с ячейка&ми, соответствующими определенному критерию:ДиапазонЯчеек.SpecialCells(Тип, Значение)Метод SpecialCells имеет два параметра: Тип и Значение (необязательныйпараметр). Тип ячейки может быть описан одной из констант xlCellType:xlCellTypeAllFormatConditionsxlCellTypeAllValidationxlCellTypeBlanksxlCellTypeComments

Page 107: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 107

xlCellTypeConstantsxlCellTypeFormulasxlCellTypeLastCellxlCellTypeSameFormatConditionsxlCellTypeSameValidationxlCellTypeVisible

Рис. 3.9. Диалоговое окно Выделение группы ячеек предлагает широкие возможности повыделению ячеек

Предусмотрено также 4 различных значения ячейки:xlErrorsxlLogicalxlNumbersxlTextValues

В результате выполнения приведенного ниже кода вокруг всех непрерывных диа&пазонов ячеек с условным форматированием будет создана граница. При отсутст&вии таких диапазонов будет выдано сообщение об ошибке:Set rngCond = ActiveSheet.Cells.SpecialCells( _xlCellTypeAllFormatConditions)If Not rngCond Is Nothing Then rngCond.BorderAround xlContinuousEnd If

В таблице, показанной на рис. 3.10, отсутствуют данные в некоторых ячейках.Несмотря на эстетическую привлекательность такого решения, оно сводит на нетвозможность сортировки данных таблицы. Подобный формат принят и в сводныхтаблицах Excel.К счастью, метод SpecialCells позволяет выделить все пустые ячейки в диапа&зоне и заполнить их нужными данными:Sub FillIn() Range("A1").CurrentRegion.SpecialCells( _xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"

Page 108: ? Применение VBA и макросов в Microsoft® Excel

108 Часть I Первые шаги

Range("A1").CurrentRegion.Value = _Range("A1").CurrentRegion.ValueEnd Sub

Рис. 3.10. Отсутствие данных в некото&

рых ячейках делает невозможной сор&тировку таблицы

В приведенном выше коде выражение Range("A1").CurrentRegion соответст&вует непрерывному диапазону ячеек рабочего листа. Свойство SpecialCellsвозвращает только пустые ячейки этого диапазона. Формула в стиле R1C1 (см. гла&ву 6, “Стиль записи ссылок R1C1”) заполняет каждую пустую ячейку данными изячейки, расположенной на одну строку выше. Вторая строка кода представляетсобой быстрый способ выполнения команд Копирование (Copy) и Специальнаявставка (Paste Special). Результат выполнения кода показан на рис. 3.11.

Рис. 3.11. После выполнения макроса

пустые ячейки в таблице заполнилисьнужными данными

Обращение к диапазону несмежных ячеекс помощью коллекции Areas

Коллекция Areas используется для представления множества диапазонов

несмежных ячеек. Она состоит из объектов Range, соответствующих непрерывY

ным диапазонам ячеек в выделенной области. Если последняя состоит из одного

непрерывного диапазона ячеек, коллекция Areas содержит один объект Range.

Page 109: ? Применение VBA и макросов в Microsoft® Excel

Работа с диапазоном ячеек Глава 3 109

Рассмотрим задачу копирования данных о запасах продуктов (ячейки, выY

деленные серым цветом) в другую часть рабочего листа (рис. 3.12).

Рис. 3.12. Содержимое ячеек, выделенных серымцветом, необходимо скопировать в другую частьрабочего листа

Наиболее очевидное решение заключается в создании цикла, поочередно

копирующего значения всех необходимых ячеек. Однако существует и более

эффективный подход (рис. 3.13):

Set NewDestination = ActiveSheet.Range("I1") For Each Rng In Cells.SpecialCells(xlCellTypeConstants, 1).Areas Rng.Copy Destination:=NewDestination Set NewDestination = NewDestination.Offset(Rng.Rows.Count)Next Rng

Рис. 3.13. Коллекция Areas предоставляет возможность эффективного мани&пулирования диапазонами несмежных ячеек

Следующий шагВ следующей главе рассматриваются функции, определенные пользоватеY

лем, а также наиболее распространенные задачи программирования в Excel.

Page 110: ? Применение VBA и макросов в Microsoft® Excel
Page 111: ? Применение VBA и макросов в Microsoft® Excel

4Создание функций,определенных пользователем .. 111Наиболее распространенныезадачи программированияв Excel ...............................................113Следующий шаг............................140

Глава 4

Ôóíêöèè,îïðåäåëåííûåïîëüçîâàòåëåì

Создание функций,определенныхпользователем

Иногда огромного количества

встроенных функций Excel бывает

недостаточно. В частности, Excel не

содержит готового решения для задаY

чи суммирования значений в ячейках,

выделенных определенным цветом.

Что же делать? Вручную скопироY

вать все нужные ячейки в другую

часть рабочего листа? Или взять

калькулятор и провести подсчет саY

мому? Оба способа отнимают много

времени и не гарантируют отсутствие

ошибок. Одно из возможных решений

заключается в написании процедуY

ры YYYY в конечном итоге, именно проY

цедурам посвящена большая часть

этой книги. Однако единственно праY

вильным решением является создание

функции, определенной пользователем.

VBA позволяет создавать функY

ции, которые могут использоваться

аналогично встроенным функциям

Excel, таким как СУММ (SUM). Чтобы

применить подобную функцию, неY

обходимо знать только ее имя и арY

гументы.

Page 112: ? Применение VBA и макросов в Microsoft® Excel

112 Часть I Первые шаги

На заметку Функции, определенные пользователем, должны храниться в стандартных моду&лях. Модули рабочих листов и модуль ЭтаКнига (ThisWorkbook) являются специ&альными модулями. Функция, размещенная в одном из таких модулей, не будетвоспринята Excel как функция, определенная пользователем.

Практикум

Практикум: пример создания и применения функции,определенной пользователемСоздадим функцию, суммирующую значения двух ячеек, и применим ее на рабо&чем листе Excel. С помощью редактора Visual Basic добавьте к проекту новый модуль и введите внего текст функции суммирования значений двух ячеек Add (см. ниже). Эта функ&ция принимает два аргумента: Add(Number1, Number2)

Здесь Number1 — это первое слагаемое, а Number2 — второе: Function Add(Number1, Number2) As IntegerAdd = Number1 + Number2End Function

Попытаемся разобраться в приведенном выше коде: имя функции — Add; аргументы функции Add — Number1 и Number2 — перечислены в скобках по&

сле ее имени; возвращаемый функцией Add результат является целым числом (As Integer) и вычисляется по формуле Add = Number1 + Number2.

Чтобы применить функцию Add на рабочем листе, выполните следующие действия.1. Введите любые два числа в ячейки A1 и A2.

2. Выделите ячейку A3.

3. Нажмите комбинацию клавиш <Shift+F3> или выберите команду меню ExcelВставка Функция (Insert Function), чтобы открыть диалоговое окно мастерафункций.

4. В раскрывающемся списке Категория (Or select a category) выберите значениеОпределенные пользователем (User Defined).

5. Выберите функцию Add и щелкните на кнопке OK.

6. В качестве первого аргумента укажите ячейку A1.

7. В качестве второго аргумента укажите ячейку A2.

8. Щелкните на кнопке OK.

Поздравляем! Вы только что создали собственную функцию и применили ее нарабочем листе.

Page 113: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 113

Большинство функций, используемых на рабочих листах, могут с успехом

применяться в VBA, и наоборот. Тем не менее, VBA требует, чтобы функция,

определенная пользователем (Add), вызывалась из процедуры (Addition),

как показано ниже:

Sub Addition ()Dim Total as IntegerTotal = Add (1, 10) 'вызов функции, определенной пользователемMsgBox "Ответ: " & TotalEnd Sub

Наиболее распространенные задачипрограммирования в Excel

В следующих разделах этой главы рассматриваются решения наиболее

распространенных задач, встречающихся при повседневном программиY

ровании в Excel.

Вывод имени файла текущей рабочей книги в ячейкеПредназначение следующей функции заключается в выводе имени файла

активной рабочей книги в ячейке, как показано на рис. 4.1:

MyName()

Рис. 4.1. Функции MyName и MyFullName используются для выводав ячейке имени и полного имени файла активной рабочей книги,соответственно

Функция MyName не имеет аргументов.

Function MyName() As String MyName = ThisWorkbook.NameEnd Function

Вывод полного имени файла текущей рабочейкниги в ячейке

Предназначение следующей функции заключается в выводе имени файла

активной рабочей книги в ячейке (см. рис. 4.1):

MyFullName()

Функция MyFullName не имеет аргументов.

Function MyFullName() As String MyFullName = ThisWorkbook.FullNameEnd Function

Page 114: ? Применение VBA и макросов в Microsoft® Excel

114 Часть I Первые шаги

Как проверить, открыта ли рабочая книга

Иногда требуется проверить, открыта ли определенная рабочая книга.

Следующая функция возвращает значение True, если рабочая книга открыта,

и False YYYY в противном случае:

BookOpen(Bk)

Функция BookOpen имеет один аргумент:

Bk — имя файла рабочей книги.

Function BookOpen(Bk As String) As Boolean Dim T As Excel.Workbook'Удалить информацию об ошибках. Err.Clear'Если при выполнении кода возникнет ошибка, она будет пропущена. On Error Resume Next Set T = Application.Workbooks(Bk) BookOpen = Not (T Is Nothing)'Если рабочая книга открыта, переменная T будет содержать'объект рабочей книги и, таким образом, не будет пустой. Err.Clear On Error GoTo 0End Function

Ниже приведен пример использования функции BookOpen:

Sub OpenAWorkbook() Dim IsOpen As Boolean Dim BookName As String BookName = "Chapter 4 samples.xls"'Вызов функции BookOpen - не забудьте указать значение параметра. IsOpen = BookOpen(BookName) If IsOpen Then MsgBox BookName & " открыта!!" Else Workbooks.Open (BookName) End IfEnd Sub

Проверка существования рабочего листа в открытой книге

Следующая функция возвращает значение True, если указанный рабочий

лист существует, и False — в противном случае. Подобная проверка возможY

на только при условии, что соответствующая рабочая книга открыта.

SheetExists(SName, WBName)

Функция SheetExists имеет 2 аргумента:

SName — имя рабочего листа;

WBName — имя рабочей книги (необязательный параметр).

Function SheetExists(SName As String, Optional WBName As _String) As Boolean Dim WS As Worksheet Dim WB As Workbook

Page 115: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 115

On Error Resume Next'Проверить, задано ли имя файла рабочей книги. If Len(WBName) > 0 Then Set WB = Workbooks(WBName)'Завершить выполнение, если рабочая книга не открыта. If WB Is Nothing Then Exit Function Else Set WB = ActiveWorkbook End If Set WS = WB.Sheets(SName)'Если рабочий лист существует, переменная WS хранит'соответствующий объект. Если рабочий лист отсутствует,'переменная WS хранит значение Nothing.

'Если переменная WS НЕ хранит Nothing, значение'выражения Not (WS Is Nothing) будет равно True. SheetExists = Not (WS Is Nothing)End Function

Ниже приведен пример использования функции SheetExists:

Sub CheckForSheet() Dim ShtExists As Boolean ShtExists = SheetExists("Sheet9")'Обратите внимание, что функции был передан только один параметр. If ShtExists Then MsgBox "Рабочий лист существует!" Else MsgBox "Рабочий лист НЕ существует!" End IfEnd Sub

Подсчет количества файлов рабочих книг в папке

Следующая функция просматривает папку (и при необходимости ее

подпапки) и, в зависимости от переданных параметров, подсчитывает лиY

бо общее количество хранящихся в ней файлов рабочих книг Excel, либо

количество файлов рабочих книг Excel, имена которых включают в себя

заданную строку.

NumFilesInCurDir(LikeText, Subfolders)

Функция NumFilesInCurDir имеет 2 аргумента:

LikeText — строка, которую должно включать в себя имя файла рабоY

чей книги (необязательный параметр);

Subfolders — булево значение, определяющее необходимость провеY

дения поиска в подпапках; по умолчанию поиск в подпапках не провоY

дится (False) (необязательный параметр).

Function NumFilesInCurDir(Optional LikeText As String, _Optional Subfolders As Boolean = False) With Application.FileSearch .NewSearch'Строка, которую должно включать в себя имя файла рабочей книги. If Len(LikeText) > 0 Then .Filename = LikeText

Page 116: ? Применение VBA и макросов в Microsoft® Excel

116 Часть I Первые шаги

End If'Выбрать тип файла - рабочие книги Excel. .FileType = msoFileTypeExcelWorkbooks'Указать на необходимость проведения поиска в текущей папке. .LookIn = CurDir'Указать на необходимость проведения поиска в подпапках. .SearchSubFolders = Subfolders .Execute NumFilesInCurDir = .FoundFiles.Count End WithEnd Function

Ниже приведен пример использования функции NumFilesInCurDir:

Sub CountMyWkbks() Dim MyFiles As Integer MyFiles = NumFilesInCurDir("Глава*", True) MsgBox MyFiles & " файл(ов) найден(о)"End Sub

Получение имени пользователя,зарегистрировавшегося в системе

Следующая функция возвращает имя пользователя, зарегистрировавшегоY

ся в системе. Вместе с функцией, возвращающей постоянное значение даты и

времени (рассматривается далее в этой главе), она может быть применена для

создания файла журнала. Кроме того, с ее помощью можно узнать имеющиеся

у пользователя права на доступ к рабочей книге.

WinUsername()

Функция WinUsername не имеет аргументов.

На заметку Функция WinUsername использует функции интерфейса прикладного програм&мирования (API), который рассматривается в главе 22, “Интерфейс прикладногопрограммирования (API) Windows”.

Следующий фрагмент кода должен быть помещен в верхнюю часть модуля:

Private Declare Function WNetGetUser Lib "mpr.dll" Alias _ "WNetGetUserA" (ByVal lpName As String, ByVal lpUserName _ As String, lpnLength As Long) As LongPrivate Const NO_ERROR = 0Private Const ERROR_NOT_CONNECTED = 2250&Private Const ERROR_MORE_DATA = 234Private Const ERROR_NO_NETWORK = 1222&Private Const ERROR_EXTENDED_ERROR = 1208&Private Const ERROR_NO_NET_OR_BAD_PATH = 1203&

Текст функции WinUsername может быть помещен в любую часть модуля

при условии, что он будет находиться ниже объявлений Private:

Page 117: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 117

Function WinUsername() As String'Переменные: Dim strBuf As String, lngUser As Long, strUn As String'Подготовка строковой переменной для использования в функции API. strBuf = Space$(255)'Использование функции WNetGetUser, возвращающей имя пользователя.'Сохранение возвращенного функцией кода в переменной lngUser. lngUser = WNetGetUser("", strBuf, 255)'Если выполнение функции API прошло успешно, If lngUser = NO_ERROR Then'убрать пробелы из переменной strBuf и возвратить результат'выполнения функции WinUsername. strUn = Left(strBuf, InStr(strBuf, vbNullChar) - 1) WinUsername = strUn Else'Ошибка, завершение работы функции. WinUsername = "Ошибка :" & lngUser End IfEnd Function

Ниже приведен пример использования функции WinUsername:

Sub CheckUserRights() Dim UserName As String UserName = WinUsername Select Case UserName Case "Administrator" MsgBox "Полные права" Case "Guest" MsgBox "Вы не можете вносить изменения в рабочую книгу" Case Else MsgBox "Ограниченные права" End SelectEnd Sub

Получение даты и времени последнегосохранения рабочей книги

Следующая функция возвращает дату и время последнего сохранения раY

бочей книги, как показано на рис. 4.2.

LastSaved(FullPath)

Рис. 4.2. Функция LastSaved возвращает дату и время последнегосохранения рабочей книги

Функция LastSaved имеет один аргумент:

FullPath — полный путь к файлу рабочей книги.

Page 118: ? Применение VBA и макросов в Microsoft® Excel

118 Часть I Первые шаги

Function LastSaved(FullPath As String) As Date LastSaved = FileDateTime(FullPath)End Function

Получение постоянного значения даты и времени

Поскольку значение, возвращаемое функцией Now, обновляется при кажY

дом открытии рабочей книги, его не рекомендуется использовать для указаY

ния даты и времени создания или изменения рабочей книги. Несмотря на то

что следующая функция основана на функции Now, ее результат куда менее

динамичен, так как он обновляется только при обновлении соответствующей

ячейки (рис. 4.3).

DateTime()

Рис. 4.3. Функция DateTime возвращает постоянное значение датыи времени

Функция DateTime не имеет аргументов.

На заметку Результат выполнения функции DateTime должен быть размещен в соответст&вующим образом отформатированной ячейке.

Function DateTime() DateTime = NowEnd Function

Проверка адреса электронной почты

Следующая функция проверяет корректность написания адреса электронY

ной почты (рис. 4.4).

IsEmailValid(StrEmail)

Рис. 4.4. Проверка корректности написания адреса электронной почты

Page 119: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 119

Внимание Функция IsEmailValid проверяет только корректность написания адреса элек&тронной почты, а не факт его существования.

Функция IsEmailValid имеет один аргумент:

StrEmail — адрес электронной почты.

Function IsEmailValid(strEmail As String) As Boolean Dim strArray As Variant Dim strItem As Variant Dim i As Long Dim c As String Dim blnIsItValid As Boolean blnIsItValid = True'Подсчет количества знаков @ в строке. i = Len(strEmail) - Len(Application.Substitute(strEmail, _"@", ""))'Если знаков @ больше, чем 1, адрес электронной почты неверный. If i <> 1 Then IsEmailValid = False: Exit Function ReDim strArray(1 To 2)'Текст слева и справа от знака @ помещается в 2 разные переменные. strArray(1) = Left(strEmail, InStr(1, strEmail, "@", 1) - 1) strArray(2) = Application.Substitute(Right(strEmail, _Len(strEmail) - Len(strArray(1))), "@", "") For Each strItem In strArray'Если хотя бы одна из переменных оказалась пустой,'адрес электронной почты неверный. If Len(strItem) <= 0 Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If'Проверка использования только допустимых символов. For i = 1 To Len(strItem)'Чтобы упростить проверку, все символы переводятся в нижний регистр. c = LCase(Mid(strItem, i, 1)) If InStr("abcdefghijklmnopqrstuvwxyz_-.", c) <= 0 _ And Not IsNumeric(c) Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If Next i'Проверка, что первым символом строк слева и справа от @'не является символ точки (.). If Left(strItem, 1) = "." Or Right(strItem, 1) = "." Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If Next strItem

Page 120: ? Применение VBA и макросов в Microsoft® Excel

120 Часть I Первые шаги

'Проверка, что в строке справа от @ есть символ точки (.). If InStr(strArray(2), ".") <= 0 Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If i = Len(strArray(2)) - InStrRev(strArray(2), ".")'Проверка длины имени домена. If i <> 2 And i <> 3 And i <> 4 Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If

'Проверка отсутствия двух символов точки подряд (..). If InStr(strEmail, "..") > 0 Then blnIsItValid = False IsEmailValid = blnIsItValid Exit Function End If

IsEmailValid = blnIsItValidEnd Function

Суммирование значений ячеек на основе цвета заливки

Следующая функция суммирует значения ячеек на основе цвета заливки.

SumByColor(CellColor, SumRange)

На заметку Функция SumByColor не поддерживает ячейки с условным форматированием.Таким образом, наличие заливки является ключевым условием, необходимым длявыполнения функции.

Функция SumByColor имеет 2 аргумента:

CellColor — адрес ячейки, имеющей заливку нужного цвета;

SumRange — диапазон ячеек, в котором необходимо провести поиск

ячеек с определенным цветом заливки.

Function SumByColor(CellColor As Range, SumRange As Range) Dim myCell As Range Dim iCol As Integer Dim myTotal'Определение цвета заливки ячейки. iCol = CellColor.Interior.ColorIndex'Просмотр ячеек в указанном диапазоне. For Each myCell In SumRange'Если цвет заливки ячейки совпадает с указанным цветом, If myCell.Interior.ColorIndex = iCol Then'добавить ее значение к сумме. myTotal = WorksheetFunction.Sum(myCell) + myTotal End If Next myCell

Page 121: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 121

SumByColor = myTotalEnd Function

Пример использования функции SumByColor на рабочем листе можно

увидеть на рис. 4.5.

Рис. 4.5. Пример суммирования значений ячеек на основе цвета заливки

Получение имени и номера цвета заливки ячейки

Следующая функция возвращает имя и номер цвета заливки ячейки:

CellColor(myCell, ColorIndex)

На заметку Функция CellColor не поддерживает ячейки с условным форматированием. На&личие заливки является ключевым условием, необходимым для выполненияфункции.

Функция CellColor имеет 2 аргумента:

myCell — адрес ячейки;

ColorIndex — если данный необязательный параметр имеет значение

True, функция CellColor возвратит номер цвета заливки ячейки (по

умолчанию функция CellColor возвращает имя цвета заливки).

Function CellColor(myCell As Range, Optional ColorIndex As Boolean) Dim myColor As String, IndexNum As Integer Select Case myCell.Interior.ColorIndex Case 1 myColor = "Черный" IndexNum = 1 Case 2 myColor = "Белый"

Page 122: ? Применение VBA и макросов в Microsoft® Excel

122 Часть I Первые шаги

IndexNum = 2 Case 3 myColor = "Красный" IndexNum = 3 Case 4 myColor = "Ярко-зеленый" IndexNum = 4 Case 5 myColor = "Синий" IndexNum = 5 Case 6 myColor = "Желтый" IndexNum = 6 Case 7 myColor = "Лиловый" IndexNum = 7 Case 8 myColor = "Бирюзовый" IndexNum = 8 Case 9 myColor = "Темно-красный" IndexNum = 9 Case 10 myColor = "Зеленый" IndexNum = 10 Case 11 myColor = "Темно-синий" IndexNum = 11 Case 12 myColor = "Коричнево-зеленый" IndexNum = 12 Case 13 myColor = "Фиолетовый" IndexNum = 13 Case 14 myColor = "Сине-зеленый" IndexNum = 14 Case 15 myColor = "Серый 25%" IndexNum = 15 Case 16 myColor = "Серый 50%" IndexNum = 16 Case 33 myColor = "Голубой" IndexNum = 33 Case 34 myColor = "Светло-бирюзовый" IndexNum = 34 Case 35 myColor = "Бледно-зеленый" IndexNum = 35 Case 36 myColor = "Светло-желтый" IndexNum = 36 Case 37 myColor = "Бледно-голубой"

Page 123: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 123

IndexNum = 37 Case 38 myColor = "Розовый" IndexNum = 38 Case 39 myColor = "Сиреневый" IndexNum = 39 Case 40 myColor = "Светло-коричневый" IndexNum = 40 Case 41 myColor = "Темно-голубой" IndexNum = 41 Case 42 myColor = "Темно-бирюзовый" IndexNum = 42 Case 43 myColor = "Травяной" IndexNum = 43 Case 44 myColor = "Золотистый" IndexNum = 44 Case 45 myColor = "Светло-оранжевый" IndexNum = 45 Case 46 myColor = "Оранжевый" IndexNum = 46 Case 47 myColor = "Сизый" IndexNum = 47 Case 48 myColor = "Серый 40%" IndexNum = 48 Case 49 myColor = "Светло-сизый" IndexNum = 49 Case 50 myColor = "Изумрудный" IndexNum = 50 Case 51 myColor = "Темно-зеленый" IndexNum = 51 Case 52 myColor = "Оливковый" IndexNum = 52 Case 53 myColor = "Коричневый" IndexNum = 53 Case 54 myColor = "Вишневый" IndexNum = 54 Case 55 myColor = "Индиго" IndexNum = 55 Case 56 myColor = "Серый 80%"

Page 124: ? Применение VBA и макросов в Microsoft® Excel

124 Часть I Первые шаги

IndexNum = 56 Case Else myColor = "Другой цвет или отсутствие заливки" End Select'Возвратить номер цвета заливки ячейки, если это указано'при вызове функции или невозможно возвратить имя цвета заливки. If ColorIndex = True Or myColor = "Другой цвет или _отсутствие заливки" Then CellColor = IndexNum Else CellColor = myColor End IfEnd Function

Пример использования функции CellColor на рабочем листе показан на

рис. 4.6.

Рис. 4.6. Пример определения имени или номера цвета заливки ячейки спомощью функции CellColor

Получение номера цвета текста в ячейке

Следующая функция возвращает номер цвета текста в ячейке:

TextColor(Rng)

На заметку Функция TextColor не поддерживает ячейки с условным или автоматическимформатированием текста (примером последнего является выделение отрицатель&ных числовых значений красным цветом).

Домашнее задание Изучив функцию TextColor, измените рассматривавшуюся в предыдущем раз&деле функцию CellColor таким образом, чтобы она возвращала имя цвета текстав ячейке.

Функция TextColor имеет один аргумент:

Rng — адрес ячейки.

Function TextColor(Rng As Range) As Long TextColor = Rng.Range("A1").Font.ColorIndexEnd Function

Page 125: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 125

Подсчет количества уникальных значений

Следующая функция возвращает количество уникальных значений в укаY

занном диапазоне ячеек (рис. 4.7):

NumUniqueValues(Rng)

Рис. 4.7. Пример подсчета количества уникальных значений в диапазонеячеек с помощью функции NumUniqueValues

Функция NumUniqueValues имеет один аргумент:

Rng — адрес диапазона ячеек.

Function NumUniqueValues(Rng As Range) As Long Dim myCell As Range, UniqueVals As New Collection'Произвести пересчет результата при изменении диапазона ячеек. Application.Volatile'Поместить значения всех ячеек диапазона в коллекцию'(в коллекции могут находиться только уникальные значения).'Продолжить выполнение функции при возникновении ошибки'(помещение в коллекцию двух одинаковых элементов). On Error Resume Next For Each myCell In Rng UniqueVals.Add myCell.Value, CStr(myCell.Value) Next myCell'Вернуться к стандартному режиму обработки ошибок. On Error GoTo 0'Возвратить количество элементов в коллекции. NumUniqueValues = UniqueVals.CountEnd Function

Удаление повторяющихся значений из диапазона ячеек Следующая функция удаляет повторяющиеся значения из указанного диаY

пазона ячеек:

UniqueValues(OrigArray)

Page 126: ? Применение VBA и макросов в Microsoft® Excel

126 Часть I Первые шаги

Функция UniqueValues имеет один аргумент:

OrigArray — массив, из которого необходимо удалить повторяющиеY

ся значения.

Следующий фрагмент кода должен быть помещен в верхнюю часть модуля:

Const ERR_BAD_PARAMETER = "Не указан исходный массив"Const ERR_BAD_TYPE = "Неверный тип"Const ERR_BP_NUMBER = 20000Const ERR_BT_NUMBER = 20001

Текст функции UniqueValues может быть помещен в любую часть модуY

ля при условии, что он будет находиться ниже объявлений Const:

Public Function UniqueValues(ByVal OrigArray As Variant) As Variant Dim vAns() As Variant Dim lStartPoint As Long Dim lEndPoint As Long Dim lCtr As Long, lCount As Long Dim iCtr As Integer Dim col As New Collection Dim sIndex As String Dim vTest As Variant, vItem As Variant Dim iBadVarTypes(4) As Integer

'Завершить выполнение функции, если массив содержит'элемент одного из следующих типов. iBadVarTypes(0) = vbObject iBadVarTypes(1) = vbError iBadVarTypes(2) = vbDataObject iBadVarTypes(3) = vbUserDefinedType iBadVarTypes(4) = vbArray

'Проверить, является ли переданное функции значение массивом. If Not IsArray(OrigArray) Then Err.Raise ERR_BP_NUMBER, , ERR_BAD_PARAMETER Exit Function End If

lStartPoint = LBound(OrigArray) lEndPoint = UBound(OrigArray) For lCtr = lStartPoint To lEndPoint vItem = OrigArray(lCtr)'Проверить допустимость значений элементов массива. For iCtr = 0 To UBound(iBadVarTypes) If VarType(vItem) = iBadVarTypes(iCtr) Or _ VarType(vItem) = iBadVarTypes(iCtr) + vbVariant Then Err.Raise ERR_BT_NUMBER, , ERR_BAD_TYPE Exit Function End If Next iCtr

'Добавить элемент в коллекцию, используя его значение'в качестве индекса. При добавлении в коллекцию'уже существующего элемента возникнет ошибка. sIndex = CStr(vItem)

Page 127: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 127

'Автоматически добавить первый элемент в коллекцию. If lCtr = lStartPoint Then col.Add vItem, sIndex ReDim vAns(lStartPoint To lStartPoint) As Variant vAns(lStartPoint) = vItem Else On Error Resume Next col.Add vItem, sIndex If Err.Number = 0 Then lCount = UBound(vAns) + 1 ReDim Preserve vAns(lStartPoint To lCount) vAns(lCount) = vItem End If End If Err.Clear Next lCtr

UniqueValues = vAnsEnd Function

Ниже приведен пример использования функции UniqueValues:

Function NoDupsArray(Rng As Range) As Variant Dim arr1() As Variant If Rng.Columns.Count > 1 Then Exit Function arr1 = Application.Transpose(Rng) arr1 = UniqueValues(arr1) NoDupsArray = Application.Transpose(arr1)End Function

Результат применения функции NoDupsArray на рабочем листе показан

на рис. 4.8.

Рис. 4.8. Создание диапазона ячеек, содержащего только уникальные зна&чения из исходного диапазона

Page 128: ? Применение VBA и макросов в Microsoft® Excel

128 Часть I Первые шаги

Поиск первой непустой ячейки в диапазоне

Следующая функция возвращает значение первой непустой ячейке в укаY

занном диапазоне:

FirstNonZeroLength(Rng)

Функция FirstNonZeroLength имеет один аргумент:

Rng — адрес диапазона ячеек.

Function FirstNonZeroLength(Rng As Range) Dim myCell As Range FirstNonZeroLength = 0# For Each myCell In Rng If Not IsNull(myCell) And myCell <> "" Then FirstNonZeroLength = myCell.Value Exit Function End If Next myCell FirstNonZeroLength = myCell.ValueEnd Function

На рис. 4.9 показан пример использования функции FirstNonZeroLengthна рабочем листе.

Рис. 4.9. Пример нахождения значения первой непустой ячейки вдиапазоне с помощью функции FirstNonZeroLength

Замена нескольких символов в строке Следующая функция используется для замены нескольких символов в

строке (рис. 4.10):

MSubstitute(trStr, frStr, toStr)

Рис. 4.10. Пример замены нескольких символов в строке с помощьюфункции MSubstitute

Page 129: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 129

Функция MSubstitute имеет 3 аргумента:

trStr — исходная строка;

frStr — символы строки, подлежащие замене;

toStr — символыYзаменители.

Внимание Функция MSubstitute предполагает, что длина строки toStr совпадает с дли&ной строки frStr. Если длина строки toStr меньше длины строки frStr, не&достающие символы считаются пустыми ("").Функция MSubstitute учитываеттакже регистр символов. Так, чтобы заменить все вхождения в строку буквы “А”,в строке frStr следует указать символы а и A. Замена одного символа двумя неподдерживается. Результатом выражения =MSubstitute("Тестовая строка"; "о"; "$@") будет Тест$вая стр$ка

Ниже приведен текст функции MSubstitute:

Function MSubstitute(ByVal trStr As Variant, frStr As String, _toStr As String) As Variant

Dim iRow As Integer Dim iCol As Integer Dim j As Integer Dim Ar As Variant Dim vfr() As String Dim vto() As String ReDim vfr(1 To Len(frStr)) ReDim vto(1 To Len(frStr))

'Помещение строк в массивы. For j = 1 To Len(frStr) vfr(j) = Mid(frStr, j, 1) If Mid(toStr, j, 1) <> "" Then vto(j) = Mid(toStr, j, 1) Else vto(j) = "" End If Next j'Сравнивание каждого символа и, при необходимости, его замена. If IsArray(trStr) Then Ar = trStr For iRow = LBound(Ar, 1) To UBound(Ar, 1) For iCol = LBound(Ar, 2) To UBound(Ar, 2) For j = 1 To Len(frStr) Ar(iRow, iCol) = Application.Substitute( _Ar(iRow, iCol), vfr(j), vto(j)) Next j Next iCol Next iRow Else Ar = trStr For j = 1 To Len(frStr)

Page 130: ? Применение VBA и макросов в Microsoft® Excel

130 Часть I Первые шаги

Ar = Application.Substitute(Ar, vfr(j), vto(j)) Next j End If MSubstitute = ArEnd Function

Извлечение чисел из смешанного текста

Следующая функция извлекает числа из смешанного текста (текста, соY

держащего числа и буквы):

RetrieveNumbers(myString)

Пример использования функции RetrieveNumbers на рабочем листе поY

казан на рис. 4.11.

Рис. 4.11. Пример извлечения чисел из смешанного текста с помощью функ&ции RetrieveNumbers

Функция RetrieveNumbers имеет один аргумент:

myString — строка смешанного текста.

Function RetrieveNumbers(myString As String)

Dim i As Integer, j As Integer Dim OnlyNums As String

'Просмотр строки, начиная с ее конца (с шагом -1). For i = Len(myString) To 1 Step -1'IsNumeric - это функция VBA, возвращающая True,'если значение переменной является числом.'Все найденные таким образом числа помещаются в строку OnlyNums. If IsNumeric(Mid(myString, i, 1)) Then j = j + 1 OnlyNums = Mid(myString, i, 1) & OnlyNums End If If j = 1 Then OnlyNums = CInt(Mid(OnlyNums, 1, 1)) Next i RetrieveNumbers = CLng(OnlyNums)End Function

Преобразование номера недели в дату Следующая функция преобразовывает строку вида ‘‘Неделя НН ГГГГ’’ (где

НН YYYY это номер недели, а ГГГГ YYYY номер года) в дату, соответствующую поY

недельнику этой недели:

Weekday(Str)

Page 131: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 131

На заметку Результат выполнения функции Weekday должен быть помещен в ячейку, отфор&матированную для отображения даты.

Пример использования функции Weekday на рабочем листе показан на

рис. 4.12.

Рис. 4.12. Пример преобразования номера недели в дату с помощьюфункции Weekday

Функция Weekday имеет один аргумент:

Str — строка вида ‘‘Неделя НН ГГГГ’’.

Function ConvertWeekDay(str As String) As Date

Dim Week As Long Dim FirstMon As Date Dim TStr As String FirstMon = DateSerial(Right(str, 4), 1, 1) FirstMon = FirstMon - FirstMon Mod 7 + 2 TStr = Right(str, Len(str) - 7) Week = Left(TStr, InStr(1, TStr, " ", 1)) + 0 ConvertWeekDay = FirstMon + (Week - 1) * 7End Function

Разбор строки с символамиLразделителями

Следующая функция извлекает элемент с заданным номером из строки с

символамиYразделителями:

StringElement(str, chr, ind)

Пример использования функции StringElement на рабочем листе покаY

зан на рис. 4.13.

Рис. 4.13. Пример извлечения элемента с заданным номером из стро&ки с символами&разделителями с помощью функции StringElement

Page 132: ? Применение VBA и макросов в Microsoft® Excel

132 Часть I Первые шаги

Функция StringElement имеет 3 аргумента:

str — строка с символамиYразделителями;

chr — символYразделитель;

ind — номер элемента, который нужно извлечь из строки.

Function StringElement(str As String, chr As String, ind As Integer)

Dim arr_str As Variant arr_str = Split(str, chr) StringElement = arr_str(ind - 1)End Function

Сортировка и конкатенация значений ячеекиз заданного диапазона

Следующая функция сортирует значения ячеек из заданного диапазона и

проводит их конкатенацию с помощью символаYразделителя ,:

SortConcat(Rng)

Пример использования функции SortConcat на рабочем листе показан

на рис. 4.14.

Рис. 4.14. Пример сортировки и конкатенации значений ячеек из заданногодиапазона с помощью функции SortConcat

Функция SortConcat имеет один аргумент:

Rng — адрес диапазона ячеек.

На заметку Для работы функции SortConcat используется процедура сортировки массиваBubbleSort.

Page 133: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 133

Function SortConcat(Rng As Range) As Variant

Dim MySum As String, arr1() As String Dim j As Integer, i As Integer Dim cl As Range Dim concat As Variant On Error GoTo FuncFail:'Инициализация результата функции. SortConcat = 0#'Завершить выполнение функции, если диапазон ячеек пуст. If Rng.Count = 0 Then Exit Function'Создать массив с размером, равным размеру диапазона ячеек. ReDim arr1(1 To Rng.Count)'Заполнить массив. i = 1 For Each cl In Rng arr1(i) = cl.Value i = i + 1 Next'Отсортировать элементы массива. Call BubbleSort(arr1)'Создать строку из элементов массива. For j = UBound(arr1) To 1 Step -1 If Not IsEmpty(arr1(j)) Then MySum = arr1(j) & "," & MySum End If Next j'Присвоить значение функции. SortConcat = Left(MySum, Len(MySum) - 2)'Точка выхода из функции SortConcat.concat_exit: Exit Function'Вывести в ячейке номер ошибки и ее описание.FuncFail: SortConcat = Err.Number & "-" & Err.Description Resume concat_exitEnd Function

Следующая процедура реализует один из наиболее популярных методов сорY

тировки массива, получившего название ‘‘метода пузырьковой сортировки’’:

Sub BubbleSort(List() As String)'Данная процедура сортирует содержимое массива по возрастанию. Dim First As Integer, Last As Integer Dim i As Integer, j As Integer Dim Temp

First = LBound(List) Last = UBound(List) For i = First To Last - 1 For j = i + 1 To Last If UCase(List(i)) > UCase(List(j)) Then Temp = List(j) List(j) = List(i) List(i) = Temp End If Next j

Page 134: ? Применение VBA и макросов в Microsoft® Excel

134 Часть I Первые шаги

Next iEnd Sub

Сортировка числовых и строковых значений

Следующая функция сортирует значения ячеек из смешанного диапазона

(диапазона, содержащего как числовые, так и строковые значения) YYYY сперва

в числовом, а затем в алфавитном порядке. Результат помещается в массив, коY

торый может быть отображен на рабочем листе с помощью формулы массива.

Sorter(Rng)

Пример использования функции Sorter показан на рис. 4.15.

Рис. 4.15. Сортировка значений ячеек из смешанного диапазона спомощью функции Sorter

Функция Sorter имеет один аргумент:

Rng — адрес диапазона ячеек.

Function Sorter(Rng As Range) As Variant

Dim arr1() As Variant If Rng.Columns.Count > 1 Then Exit Function arr1 = Application.Transpose(Rng) QuickSort arr1'Возвратить массив. Sorter = Application.Transpose(arr1)End Function

Для сортировки значений ячеек в смешанном диапазоне функция Sorterиспользует две процедуры.

Public Sub QuickSort(ByRef vntArr As Variant, _Optional ByVal lngLeft As Long = -2, _Optional ByVal lngRight As Long = -2) Dim i, j, lngMid As Long Dim vntTestVal As Variant If lngLeft = -2 Then lngLeft = LBound(vntArr) If lngRight = -2 Then lngRight = UBound(vntArr)

Page 135: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 135

If lngLeft < lngRight Then lngMid = (lngLeft + lngRight) \ 2 vntTestVal = vntArr(lngMid) i = lngLeft j = lngRight

Do Do While vntArr(i) < vntTestVal i = i + 1 Loop Do While vntArr(j) > vntTestVal j = j - 1 Loop If i <= j Then Call SwapElements(vntArr, i, j) i = i + 1 j = j - 1 End If Loop Until i > j

If j <= lngMid Then Call QuickSort(vntArr, lngLeft, j) Call QuickSort(vntArr, i, lngRight) Else Call QuickSort(vntArr, i, lngRight) Call QuickSort(vntArr, lngLeft, j) End If End IfEnd Sub

Private Sub SwapElements(ByRef vntItems As Variant, _ ByVal lngItem1 As Long, _ ByVal lngItem2 As Long) Dim vntTemp As Variant vntTemp = vntItems(lngItem2) vntItems(lngItem2) = vntItems(lngItem1) vntItems(lngItem1) = vntTempEnd Sub

Поиск строки в диапазоне ячеек

Следующая функция проводит поиск строки в указанном диапазоне ячеек.

Результатом выполнения функции являются адреса ячеек, в которых была

найдена заданная строка.

ContainsText(Rng, Text)

Пример использования функции ContainsText показан на рис. 4.16.

Рис. 4.16. Пример поиска строки в диапазоне ячеек с помощью функцииContainsText

Page 136: ? Применение VBA и макросов в Microsoft® Excel

136 Часть I Первые шаги

Функция ContainsText имеет 2 аргумента:

Rng — адрес диапазона ячеек;

Text — строка, которую необходимо найти.

Function ContainsText(Rng As Range, Text As String) As String

Dim T As String Dim myCell As Range'Просмотр каждой ячейки в диапазоне. For Each myCell In Rng'Поиск указанной строки. If InStr(myCell.Text, Text) > 0 Then'Если строка найдена, добавить ее адрес к результату'выполнения функции. If Len(T) = 0 Then T = myCell.Address(False, False) Else T = T & "," & myCell.Address(False, False) End If End If Next myCell ContainsText = TEnd Function

Запись содержимого ячейки в обратном порядке

Следующая функция записывает содержимое ячейки в обратном порядке:

ReverseContents(myCell, IsText)

Функция ReverseContents имеет 2 аргумента:

myCell — адрес ячейки;

IsText — необязательный булев параметр, определяющий, является

значение ячейки текстом (True, используется по умолчанию) или чисY

лом (False).

Function ReverseContents(myCell As Range, Optional IsText _As Boolean = True)

Dim i As Integer Dim OrigString As String, NewString As String'Удалить символы пробела в начале и конце строки. OrigString = Trim(myCell) For i = 1 To Len(OrigString)'Запись исходной строки в обратном порядке путем добавления'строки NewString после символа исходной строки. NewString = Mid(OrigString, i, 1) & NewString Next i If IsText = False Then ReverseContents = CLng(NewString) Else ReverseContents = NewString End IfEnd Function

Page 137: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 137

Поиск наибольших значений в диапазоне ячеек

Следующая функция возвращает адреса ячеек диапазона, содержащих наиY

большее значение:

ReturnMaxs(Rng)

Пример использования функции ReturnMaxs на рабочем листе показан

на рис. 4.17.

Рис. 4.17. Пример нахождения адресов ячеек диапазона, содержа&щих наибольшее значение, с помощью функции ReturnMaxs

Функция ReturnMaxs имеет один аргумент:

Rng — адрес диапазона ячеек.

Function ReturnMaxs(Rng As Range) As String

Dim Mx As Double Dim myCell As Range'Если диапазон состоит из одной ячейки, вернуть ее адрес'в качестве результата выполнения функции. If Rng.Count = 1 Then ReturnMaxs = Rng.Address(False, _False): Exit Function'Использование встроенной функции Max для нахождения'наибольшего значения в диапазоне ячеек. Mx = Application.Max(Rng)'Зная максимальное значение в диапазоне ячеек, найти все'ячейки, содержащие это значение, и возвратить их адреса. For Each myCell In Rng If myCell = Mx Then If Len(ReturnMaxs) = 0 Then ReturnMaxs = myCell.Address(False, False) Else ReturnMaxs = ReturnMaxs & "," & _myCell.Address(False, False)

Page 138: ? Применение VBA и макросов в Microsoft® Excel

138 Часть I Первые шаги

End If End If Next myCellEnd Function

Получение адреса гиперссылки

Следующая функция возвращает адрес гиперссылки:

GetAddress(Hyperlink)

Пример использования функции GetAddress на рабочем листе показан

на рис. 4.18.

Рис. 4.18. Пример получения адреса гиперссылки с помощью функцииGetAddress

Функция GetAddress имеет один аргумент:

Hyperlink — адрес ячейки, содержащей гиперссылку.

Function GetAddress(HyperlinkCell As Range)

GetAddress = Replace(HyperlinkCell.Hyperlinks(1).Address, _"mailto:", "")End Function

Получение адреса столбца ячейки

Следующая функция возвращает адрес столбца ячейки:

ColName(Rng)

Функция ColName имеет один аргумент:

Rng — адрес ячейки.

Function ColName(Rng As Range) As String

ColName = Left(Rng.Range("A1").Address(True, False), _ InStr(1, Rng.Range("A1").Address(True, False),"$", 1) - 1)End Function

Генерация постоянных случайных чисел

Следующая функция используется для помещения в ячейку случайного

числа.

StaticRAND()

В отличие от встроенной функции СЛЧИС (RAND), значение которой измеY

няется при каждом открытии рабочей книги, значение функции StaticRAND

Page 139: ? Применение VBA и макросов в Microsoft® Excel

Функции, определенные пользователем Глава 4 139

изменяется только при принудительном пересчете значения ячейки. Пример

использования функции StaticRAND на рабочем листе показан на рис. 4.19.

Функция StaticRAND не имеет аргументов.

Function StaticRAND() As Double Randomize StaticRAND = RndEnd Function

Рис. 4.19. Пример генерации постоянного случайного числа с по&мощью функции StaticRAND

Использование структуры Select...Case

Следующая функция демонстрирует пример использования структуры Se-lect...Case для замены вложенных выражений If...Then...Else(рис. 4.20).

Рис. 4.20. Пример замены вложенных выражений If...Then...Else с помощью структуры Select...Case

Function state_period(mth As Integer, yr As Integer) Select Case mth Case 1 state_period = "C 1 июля " & yr - 1 & " по _31 июля " & yr - 1 Case 2 state_period = "С 1 августа " & yr - 1 & " по _31 августа " & yr - 1 Case 3 state_period = "С 1 сентября " & yr - 1 & " по _30 сентября " & yr - 1 Case 4

Page 140: ? Применение VBA и макросов в Microsoft® Excel

140 Часть I Первые шаги

state_period = "С 1 октября " & yr - 1 & " по _31 октября " & yr - 1 Case 5 state_period = "С 1 ноября " & yr - 1 & " по _30 ноября " & yr - 1 Case 6 state_period = "С 1 декабря " & yr - 1 & " по _31 декабря " & yr - 1 Case 7 state_period = "С 1 января " & yr & " по _31 января " & yr Case 8 state_period = "С 1 февраля " & yr & " по _28 февраля " & yr Case 9 state_period = "С 1 марта " & yr & " по _31 марта " & yr Case 10 state_period = "С 1 апреля " & yr & " по _30 апреля " & yr Case 11 state_period = "С 1 мая " & yr & " по _31 мая " & yr Case 12 state_period = "С 1 июня " & yr & " по _30 июня " & yr Case 13 state_period = "Подготовка к распродаже" Case 14 state_period = "Распродажа" End SelectEnd Function

Следующий шагВ следующей главе будет рассмотрен один из фундаментальных компонентов

любого языка программирования YYYY цикл. Помимо базовых циклов, присутстY

вующих практически в каждом языке программирования, будет рассмотрен

цикл For Each...Next, являющийся исключительной особенностью VBA.

Page 141: ? Применение VBA и макросов в Microsoft® Excel

5Цикл For...Next............................... 141Циклы Do...Loop ............................ 147Цикл For Each...Next...................... 152Управление выполнениемкода: использованиеконструкций If...Then...Else иSelect Case ...................................... 155Следующий шаг............................ 160

Глава 5

Öèêëû è óïðàâëåíèåâûïîëíåíèåì êîäà

Цикл YYYY это фундаментальный

компонент любого языка програмY

мирования. VBA поддерживает все

наиболее распространенные виды

циклов, а также специальный цикл, явY

ляющийся исключительной особенноY

стью VBA как представителя класY

са объектноYориентированных языков

программирования.

В этой главе рассматриваются слеY

дующие базовые конструкции циклов:

For...Next;

Do...While;

Do...Until;

While...Loop;

Until...Loop.

Также будет рассмотрен специальY

ный цикл, уникальный для объектY

ноYориентированных языков прогY

раммирования:

For Each...Next.

Цикл For...Next For...Next — один из самых

распространенных видов цикла, приY

сутствующий практически в каждом

языке программирования. Суть данY

ного цикла заключается во множестY

венном выполнении фрагмента кода,

заключенного между выражениями

For и Next, с различным значением

переменнойYсчетчика (указывается в

выражении For).

Page 142: ? Применение VBA и макросов в Microsoft® Excel

142 Часть I Первые шаги

Рассмотрим следующий фрагмент кода:

For I = 1 To 10 Cells(I, I).Value = iNext I

ПеременнаяYсчетчик носит имя I. При первом выполнении цикла значеY

ние переменной I равно 1. Это приводит к тому, что ячейке, расположенной в

1Yй строке 1Yго столбца, будет присвоено значение 1 (рис. 5.1).

Рассмотрим действия VBA при достижении строки Next I. Перед выполY

нением этой строки значение переменной I равно 1. После выполнения строY

ки Next I VBA необходимо принять решение. Если после добавления к пеY

ременнойYсчетчику 1 ее значение не превысило максимально допустимое знаY

чение, заданное с помощью оператора To, цикл следует продолжить. В данном

случае значение переменной I увеличится до 2 и выполнение кода будет проY

должено с первой строки после выражения For. Значение переменной I до и

после выполнения строки Next показано на рис. 5.2 и 5.3, соответственно.

Рис. 5.1. При первом выполнениицикла ячейке, расположенной в 1&йстроке 1&го столбца, будет присвое&но значение 1

Рис. 5.2. Перед выполнением строки NextI значение переменной I равно 1. Увеличе&ние переменной I на 1 не приведет к пре&вышению максимального значения, задан&ного с помощью оператора To

Во время второго выполнения цикла значение переменной I равно 2, в реY

зультате чего ячейке, расположенной во 2Yй строке 2Yго столбца, будет приY

своено значение 2 (рис. 5.4).

Рис. 5.3. После выполнения строки Next Iзначение переменной I равно 2. Выполне&ние кода будет продолжено с первой строкипосле выражения For

Рис. 5.4. Во время второго выпол&нения цикла ячейке, расположен&ной во 2&й строке 2&го столбца, бу&дет присвоено значение 2

При последующих выполнениях цикла значение переменной I будет увеY

личено до 3, 4 и т.д. На 10Yм шаге ячейке, расположенной в 10Yй строке 10Yго

столбца, будет присвоено значение 10.

Page 143: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 143

Рассмотрим, что произойдет с переменной I после выполнения строки

Next I в 10Yй раз. Как показано на рис. 5.5, перед выполнением строки NextI в 10Yй раз значение переменной I равно 10.

Как всегда, после увеличения значения переменнойYсчетчика VBA предY

стоит принять решение относительно дальнейшего выполнения цикла. ВыY

полнение строки Next I в 10Yй раз приводит к увеличению значения переY

менной I до 10, что больше, чем максимальное значение, заданное с помощью

оператора To. VBA завершает цикл и переходит к выполнению первой строки

кода после выражения Next (рис. 5.6).

Рис. 5.5. Перед выполнением строкиNext I в 10&й раз значение переменнойI равно 10

Рис. 5.6. После увеличения значения пе&ременной I до 11 VBA выходит из циклаи продолжает выполнение кода с пер&вой строки после выражения Next

При намерении использовать переменную I после выполнения цикла слеY

дует помнить, что ее значение может превысить максимально допустимое знаY

чение, заданное с помощью оператора To.

Результат выполнения цикла после 10 итераций показан на рис. 5.7.

Рис. 5.7. Результат выполнения цикла после 10 итераций

Наиболее распространенное применение цикла For...Next заключается

в обработке строк заданного диапазона на основе некоторого критерия. ПриY

веденный ниже цикл используется для выделения всех строк, содержащих поY

ложительное число в столбце F:

For i = 2 To 10 If Cells(i, 6).Value > 0 Then Cells(i, 8).Value = "Выручка от сервиса" Cells(i, 1).Resize(1, 8).Interior.ColorIndex = 4 End IfNext i

Page 144: ? Применение VBA и макросов в Microsoft® Excel

144 Часть I Первые шаги

Данный цикл обрабатывает 2YY10 строки рабочего листа. Если в столбце Fстроки находится положительное число, в столбец H помещается надпись

‘‘Выручка от сервиса’’, а все ячейки данной строки, расположенные в столбY

цах A–H, выделяются зеленым цветом (рис. 5.8).

Рис. 5.8. Пример использования цикла For...Next для обработки строкзаданного диапазона

Использование переменных в выражении For

Предыдущий пример не очень практичен, поскольку он рассчитан на рабоY

ту с фиксированным диапазоном ячеек. Для указания максимального значеY

ния счетчика в выражении For рекомендуется использовать переменные, как

показано ниже:

FinalRow = Cells(65536, 1).End(xlUp).RowFor i = 2 To FinalRow If Cells(i, 6).Value > 0 Then Cells(i, 8).Value = "Выручка от сервиса" Cells(i, 1).Resize(1, 8).Interior.ColorIndex = 4 End IfNext I

Использование переменных имеет определенные особенности, которые

необходимо учитывать. Если импортированный файл счетов будет содержать

только одну строку заголовка, значение переменной FinalRow окажется равY

ным 1, а первая строка цикла примет вид For I = 2 to 1. Поскольку наY

чальное значение счетчика больше его максимально допустимого значения,

цикл будет пропущен и выполнение кода начнется со строки, следующей за

строкой Next I.

Изменение шага в цикле For...Next

Цикл For...Next предусматривает возможность изменения значения пеY

ременнойYсчетчика с шагом, отличным от 1. Рассмотрим задачу выделения

цветом каждой второй строки в заданном диапазоне ячеек. Чтобы добиться

этого, следует изменить шаг приращения значения переменнойYсчетчика,

воспользовавшись оператором Step:

FinalRow = Cells(65536, 1).End(xlUp).RowFor I = 2 To FinalRow Step 2 Cells(I, 1).Resize(1, 8).Interior.ColorIndex = 35Next I

Page 145: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 145

В результате выполнения приведенного выше кода строки 2, 4, 6 и т.д. буY

дут выделены бледноYзеленым цветом (рис. 5.9).

Рис. 5.9. Пример изменения шага приращения значения переменной&счетчика цикла For...Next с помощью оператора Step

Значение переменнойYсчетчика может изменяться практически с любым

шагом. Ниже приведен пример извлечения каждой десятой строки (Step 10)

из заданного диапазона ячеек:

FinalRow = Cells(65536, 1).End(xlUp).RowNextRow = FinalRow + 5Cells(NextRow - 1, 1).Value = "Выборка из приведенных выше данных"For I = 2 To FinalRow Step 10 Cells(I, 1).Resize(1, 8).Copy Destination:=Cells(NextRow, 1) NextRow = NextRow + 1Next I

Значение переменнойYсчетчика может изменяться и в направлении от

большего к меньшему. В частности, это может пригодиться при выборочном

удалении строк, как показано ниже:

'Удаление строк со значением S54 в столбце C.FinalRow = Cells(65536, 1).End(xlUp).RowFor I = FinalRow To 2 Step -1 If Cells(I, 3).Value = "S54" Then Cells(I, 1).EntireRow.Delete End IfNext I

Досрочное завершение выполнения цикла

Иногда выполнение цикла можно завершить досрочно. Рассмотрим задачу

поиска строки, удовлетворяющей определенному критерию. Как только данY

ная строка будет найдена, выполнение оставшейся части цикла теряет смысл.

Для досрочного выхода из цикла применяется выражение Exit For.

Следующий код используется для поиска строки с положительным числом

в столбце F и нулем в столбце E. При нахождении такой строки выдается соY

Page 146: ? Применение VBA и макросов в Microsoft® Excel

146 Часть I Первые шаги

общение об ошибке, а указатель помещается в ячейку проблемной строки,

расположенную в столбце F:

'Следующий код используется для поиска ошибок в исходных данных.FinalRow = Cells(65536, 1).End(xlUp).RowProblemFound = FalseFor I = 2 To FinalRow If Cells(I, 6).Value > 0 Then If Cells(I, 5).Value = 0 Then Cells(I, 6).Select ProblemFound = True Exit For End If End IfNext I

If ProblemFound Then MsgBox "Ошибка в строке " & I Exit SubEnd If

Вложение циклов

Цикл может выполняться внутри другого цикла. Одним из наиболее наглядY

ных примеров вложения циклов является цикл, обрабатывающий строки в заY

данном диапазоне ячеек, внутри которого выполняется цикл, обрабатывающий

столбцы этих строк. Рассмотрим набор данных, представленный на рис. 5.10.

Рис. 5.10. Вложение циклов позволяет реализовать последовательную обработку всехячеек этого диапазона

FinalRow = Cells(65536, 1).End(xlUp).RowFinalCol = Cells(1, 255).End(xlToLeft).ColumnFor I = 2 To FinalRow'Если номер строки - четный, начать с 1-го столбца.'Если номер строки - нечетный, начать со 2-го столбца. If I Mod 2 = 1 Then StartCol = 1 Else StartCol = 2 End If For j = StartCol To FinalCol Step 2 Cells(I, j).Interior.ColorIndex = 35 Next jNext I

Для обработки строк набора данных используется внешний цикл с переY

меннойYсчетчиком I, а для обработки столбцов этих строк YYYY внутренний

Page 147: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 147

цикл с переменнойYсчетчиком J. Поскольку набор данных состоит из 7 строк

(см. рис. 5.10), внешний цикл проходит 7 итераций. Каждой итерации внешY

него цикла соответствует 6 или 7 итераций внутреннего цикла (это зависит от

номера обрабатываемой строки). Результат выполнения приведенного выше

кода показан на рис. 5.11.

Рис. 5.11. Результат выполнения вложенных циклов

Циклы Do...Loop Существует несколько разновидностей цикла Do...Loop. Его наиболее проY

стой вариант используется для выполнения большого числа однообразных операY

ций. Рассмотрим задачу преобразования списка адресов, показанного на рис. 5.12.

Рис. 5.12. Преобразование этого списка адресов вформат базы данных позволит автоматизироватьпроцесс рассылки стандартных писем

Page 148: ? Применение VBA и макросов в Microsoft® Excel

148 Часть I Первые шаги

Чтобы преобразовать подобный список адресов в формат базы данных

(имя в столбце B, название улицы в столбце C, город и почтовый индекс в

столбце D), можно записать макрос, включив режим относительных ссылок

(см. главу 1, ‘‘Excel и VBA YYYY гремучая смесь’’). Предназначение макроса соY

стоит в преобразовании в формат базы данных одного адреса и установке укаY

зателя на ячейку, содержащую имя следующего адресата в списке:

Sub Macro3()' Макрос3 Макрос' Макрос записан 29.01.2005 (Александр Журавлев)'' Преобразовать в формат базы данных один адрес.' Установить указатель на ячейку, содержащую имя следующего' адресата в списке.'' Сочетание клавиш: Ctrl+Shift+A' Selection.Copy ActiveCell.Offset(0, 1).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(1, -1).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-1, 2).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(2, -2).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-2, 3).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(4, -3).Range("A1").SelectEnd Sub

См. также Об относительных ссылках рассказывается в разделе “Возможное решение:использование относительных ссылок” главы 1 на с. 52.

Внимание Приведенный выше макрос не предназначен для профессионального примененияи является примером решения единовременной задачи.

С помощью макроса преобразование в формат базы данных одного адреса

сводится к установке указателя на ячейку, содержащую имя адресата, и нажаY

тию комбинации клавиш <Ctrl+Shift+A>. После копирования составляющих

адреса в столбцы B, C и D указатель устанавливается на ячейку, содержащую

имя следующего адресата в списке (рис. 5.13).

Использование макроса позволяет преобразовывать список адресов в форY

мат базы данных со скоростью 1 адрес в секунду. Однако эффективно ли данY

ное решение при условии, что список состоит из 5000 адресов?

Page 149: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 149

Рис. 5.13. После преобразования в формат базы данных одного адреса указатель устанавли&вается на ячейку, содержащую имя следующего адресата

Поместив код макроса между выражениями Do и Loop, его можно выполY

нять бесконечно. Таким образом, часы монотонной работы можно свести

к нескольким минутам наблюдения за ходом выполнения макроса.

Чтобы остановить выполнение макроса, следует воспользоваться комбиY

нацией клавиш <Ctrl+Break>. Очевидно, подобное решение также не являетY

ся оптимальным, поскольку оно все еще требует непосредственного участия

человека.

Sub Macro3()' Макрос3 Макрос' Макрос записан 29.01.2005 (Александр Журавлев)'' Преобразовать в формат базы данных один адрес.' Установить указатель на ячейку, содержащую имя следующего' адресата в списке.'' Сочетание клавиш: Ctrl+Shift+A'Do Selection.Copy ActiveCell.Offset(0, 1).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(1, -1).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-1, 2).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(2, -2).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-2, 3).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(4, -3).Range("A1").SelectLoopEnd Sub

Приведенный выше цикл представляет собой компромиссное решение,

направленное на быстрое выполнение поставленной задачи. К счастью, цикл

Do...Loop поддерживает возможность своего досрочного завершения.

Логичным условием выхода из приведенного выше цикла является достиY

жение конца набора данных, признаком чего может служить выделение пусY

той ячейки:

Page 150: ? Применение VBA и макросов в Microsoft® Excel

150 Часть I Первые шаги

Sub Macro3()' Макрос3 Макрос' Макрос записан 29.01.2005 (Александр Журавлев)'' Преобразовать в формат базы данных один адрес.' Установить указатель на ячейку, содержащую имя следующего' адресата в списке.'' Сочетание клавиш: Ctrl+Shift+A'Do If Not Selection.Value > "" then Exit Do Selection.Copy ActiveCell.Offset(0, 1).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(1, -1).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-1, 2).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(2, -2).Range("A1").Select Application.CutCopyMode = False Selection.Copy ActiveCell.Offset(-2, 3).Range("A1").Select ActiveSheet.Paste ActiveCell.Offset(4, -3).Range("A1").SelectLoopEnd Sub

Использование операторов While и Until

Операторы While и Until могут использоваться как в выражении Do, так

и в выражении Loop. Единственным обязательным условием является налиY

чие некоторого критерия, принимающего значение True или False.

При использовании конструкции Do While <критерий>...Loop цикл

не выполняется, если <критерий> равен False. К примеру, при чтении соY

держимого текстового файла цикл не должен выполняться, если был достигнут

конец файла (об этом свидетельствует значение функции EOF, равное True):

'Считать содержимое текстового файла,'за исключением итоговых строк. Open "C:\Счет.txt" For Input As #1 r = 1 Do While Not EOF(1) Line Input #FileNumber, Data If Not Left(Data, 5) = "ВСЕГО" Then'Импортировать строку. r = r + 1 Cells(r, 1).Value = Data End If Loop Close #1

В приведенном выше коде было использовано ключевое слово NOT. При досY

тижении конца файла значение функции EOF(1) становится равным True. НеY

Page 151: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 151

которые программисты считают, что частое использование ключевых слов NOTзатрудняет восприятие кода. Чтобы избавиться от NOT, можно воспользоваться

альтернативной конструкцией Do Until <критерий>...Loop:

'Считать содержимое текстового файла,'за исключением итоговых строк. Open "C:\Счет.txt" For Input As #1 r = 1 Do Until EOF(1) Line Input #FileNumber, Data If Not Left(Data, 5) = "ВСЕГО" Then'Импортировать строку. r = r + 1 Cells(r, 1).Value = Data End If Loop Close #1

Иногда цикл необходимо выполнить хотя бы один раз. Для этого оператоY

ры While и Until помещают в конец цикла, в выражение Loop. В результате

выполнения приведенного ниже кода пользователю предлагается ввести некоY

торое число (сумму, указанную в счете) до тех пор, пока он не введет 0:

TotalSales = 0Do x = InputBox(Prompt:="Введите сумму следующего счета _или 0 для завершения.") TotalSales = TotalSales + xLoop Until x = 0MsgBox "Общая сумма сегодняшних продаж составила $" & TotalSales

В следующем примере пользователю предлагается ввести сумму, указанY

ную в чеке. Оплата нескольких счетов одним чеком — весьма распространенY

ная практика. Макрос последовательно ‘‘погашает’’ счета (начиная с самых

ранних) до тех пор, пока не исчерпает сумму чека.

'Ввести сумму, указанную в чеке.AmtToApply = InputBox("Введите сумму, указанную в чеке")'Погасить счета, начиная с самых ранних,'уменьшая при этом значение переменной AmtToApply.NextRow = 2Do While AmtToApply > 0 OpenAmt = Cells(NextRow, 3) If OpenAmt > AmtToApply Then'Погасить счет с помощью чека. Cells(NextRow, 4).Value = AmtToApply AmtToApply = 0 Else Cells(NextRow, 4).Value = OpenAmt AmtToApply = AmtToApply - OpenAmt End If NextRow = NextRow + 1Loop

Возможность использования операторов While и Until как в начале, так

и в конце конструкции Do...Loop, позволяет осуществлять тонкий контроль

над ходом выполнения цикла.

Page 152: ? Применение VBA и макросов в Microsoft® Excel

152 Часть I Первые шаги

Цикл While...Wend

Цикл While...Wend был включен в VBA для обеспечения обратной соY

вместимости. В справочной системе VBA Microsoft рекомендует использоY

вать циклы Do...Loop как обладающие более широкими возможностями.

Чтобы объяснить принцип работы цикла While...Wend, приведем неY

большой пример.

'Считывание информации о счетах и вычисление общей суммы продаж.Open "C:\Счет.txt" For Input As #1 TotalSales = 0 While Not EOF(1) Line Input #1, Data TotalSales = TotalSales + Data Wend MsgBox "Общая сумма продаж = " & TotalSales Close #1

Первой строкой цикла While...Wend всегда является строка While<критерий>, последней YYYY строка Wend. Возможность досрочного выхода из

цикла не предусмотрена. За счет наличия операторов While и Until, котоY

рые могут применяться как в выражении Do, так и в выражении Loop,

а также возможности досрочного выхода из цикла, конструкция Do...Loopзаслуженно считается более надежной и гибкой, нежели конструкция

While...Wend.

Цикл For Each...Next Цикл For Each...Next является одним из наиболее полезных циклов

объектноYориентированного языка программирования. К сожалению, этот

цикл не поддерживается средством записи макросов.

Рабочая книга Excel переполнена всевозможными коллекциями объекY

тов YYYY рабочие листы в рабочей книге, ячейки в диапазоне, сводные таблицы

на рабочем листе, последовательности данных на диаграмме и т.п. Цикл ForEach...Next предназначен для последовательной обработки элементов колY

лекции. Прежде чем перейти к его более подробному изучению, рассмотрим

понятие объектной переменной.

Объектные переменные

Обычные переменные хранят только одно значение. В отличие от них, объект*ные переменные хранят много значений, которые являются значениями

свойств соответствующего объекта.

Существует мнение, согласно которому все переменные, используемые в

процедуре, необходимо объявлять в ее начале с помощью ключевого слова

Dim. Это позволяет указать тип переменной, например Integer или Double.

Несмотря на то что таким образом удается сэкономить немного оперативной

памяти, вам следует заранее знать весь список переменных, которые вы собиY

Page 153: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 153

раетесь использовать в процедуре. В отличие от обычных переменных, объявY

ление объектных переменных имеет множество преимуществ, одним из котоY

рых является возможность автоматического завершения ввода. Следующий

код содержит объявления трех объектных переменных, соответствующих раY

бочему листу, диапазону ячеек и сводной таблице:

Sub Test() Dim WSD As Worksheet Dim MyCell As Range Dim PT As PivotTable Set WSD = ThisWorkbook.Worksheets("Данные") Set MyCell = WSD.Cells(65536, 1).End(xlUp).Offset(1, 0) Set PT = WSD.PivotTables(1) ...

Чтобы присвоить значение объектной переменной, помимо знака равенстY

ва следует воспользоваться ключевым словом Set, как показано выше.

Одним из наиболее существенных преимуществ использования объектных

переменных является возможность быстрого обращения к нужному объекту,

например, WSD вместо ThisWorkbook.Worksheets("Данные").

Кроме того, как уже отмечалось выше, объектная переменная предоставляY

ет доступ ко всем свойствам соответствующего объекта.

Вместо переменнойYсчетчика в цикле For Each...Next используется

объектная переменная. В приведенном ниже коде такой переменной является

переменная Cell:

For Each Cell In Range("A1").CurrentRegion.Resize(, 1) If Left(Cell.Value, 5) = "Всего" Then Cell.Resize(1, 8).Font.Bold = True End IfNext Cell

Свойство CurrentRegion используется для выделения непрерывного диаY

пазона ячеек, а свойство Resize — для ограничения диапазона столбцом A.

С помощью следующего кода производится поиск рабочего листа с заданY

ным именем в коллекции всех открытых рабочих книг:

For Each wb in Workbooks If wb.Worksheet(1).Name = "Menu" Then WBFound = True WBName = wb.NameEnd IfNext wb

В результате выполнения приведенного ниже кода с текущего рабочего

листа будут удалены все находящиеся на нем фигуры:

For Each Sh In ActiveSheet.Shapes Sh.DeleteNext Sh

Выполнение следующего кода приведет к удалению с текущего рабочего

листа всех сводных таблиц:

For Each PT In ActiveSheet.PivotTables PT.TableRange2.ClearNext PT

Page 154: ? Применение VBA и макросов в Microsoft® Excel

154 Часть I Первые шаги

Обработка всех файлов в папке Рассмотрим несколько полезных процедур, построенных на применении циклов.Первая процедура использует объект VBA FileSearch для нахождения всех JPG&файлов в указанной папке и вывода их списка на рабочем листе Excel. Внешний цикл, использующий переменную&счетчик I, обрабатывает список най&денных файлов. На каждой итерации цикла полное имя файла помещается в пе&ременную ThisEntry. Чтобы отделить путь к файлу от его имени, применяетсявнутренний цикл, использующий переменную&счетчик J. Sub ListJpgFiles()

'Этот макрос находит все JPG-файлы в заданной'папке и выводит их список на рабочем листе Excel.

'Очистить все ячейки рабочего листа. Cells.Clear'Создать заголовки столбцов. Range("A1:D1").Value = Array("FileName", "Path", _"FileName", "NewPath") NextRow = 2'Поиск файлов осуществляется с помощью объекта FileSearch. With Application.FileSearch .NewSearch .LookIn = "C:\" .SearchSubFolders = True .Filename = "*.jpg" .Execute FilesToProcess = .FoundFiles.Count'Обработать список найденных файлов. For I = 1 To .FoundFiles.Count ThisEntry = .FoundFiles(I) Cells(NextRow, 1).Value = ThisEntry'Отделить путь к файлу от его имени. For j = Len(ThisEntry) To 1 Step -1 If Mid(ThisEntry, j, 1) = _Application.PathSeparator Then Cells(NextRow, 2) = Left(ThisEntry, j) Cells(NextRow, 3) = Mid(ThisEntry, j + 1) Exit For End If Next j NextRow = NextRow + 1 Next I End WithEnd Sub

Приведенная выше процедура может быть использована для перемещения JPG&файлов. Введите в столбце D полный путь к папке, в которую необходимо пере&местить соответствующий файл. На каждой итерации приведенного ниже циклаFor Each...Next объектная переменная Cell содержит ссылку на ячейку встолбце A (исходное имя файла), а выражение Cell.Offset(0, 3) — ссылку насоответствующую ячейку в столбце D (полный путь к папке, в которую необходимопереместить файл).

Page 155: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 155

Sub CopyToNewFolder() FinalRow = Range("A65536").End(xlUp).Row For Each Cell In Range("A2:A" & FinalRow) OrigFile = Cell.Value If Cell.Offset(0, 3).Value > "" Then NewFile = Cell.Offset(0, 3) & _Application.PathSeparator & Cell.Offset(0, 2) FileCopy OrigFile, NewFile End If Next CellEnd Sub

Управление выполнением кода: использованиеконструкций If...Then...Else и Select Case

Управление выполнением кода YYYY это еще один фундаментальный аспект

программирования, игнорируемый средством записи макросов. VBA поддерY

живает две конструкции, реализующие концепцию управления выполнением

кода, — If...Then...Else и Select Case.

Знакомство с конструкцией If...Then...Else

Краеугольным камнем концепции управления выполнением кода является

выражение If. Рассмотрим задачу копирования списка продуктов, показанY

ного на рис. 5.14, в два списка YYYY ‘‘Фрукты’’ и ‘‘Овощи’’.

Рис. 5.14. Задача разделения спи&ска продуктов на два списка мо&жет быть решена с помощью од&ного цикла

Page 156: ? Применение VBA и макросов в Microsoft® Excel

156 Часть I Первые шаги

Начинающему программисту может придти в голову идея создания двух

циклов YYYY по одному для составления каждого списка. Тем не менее, данная

задача решается с помощью всего лишь одного цикла и конструкции

If...Then...Else.

Условие Обязательной частью выражения If является условие, имеющее значение

True или False. Ниже приведены примеры простых и сложных условий:

If Range("A1").Value = "Товар";

If Not Range("A1").Value = "Товар";

If Range("A1").Value = "Товар" And Range("B1").Value= "Фрукт";

If Range("A1").Value = "Товар" Or Range("B1").Value ="Фрукт".

Конструкция If...Then...End If Строки кода, размещенные после выражения If, будут выполнены только

при соблюдении указанного условия. Чтобы завершить блок If, следует восY

пользоваться выражением End If, как показано ниже:

Sub ColorFruitRedBold() FinalRow = Cells(65536, 1).End(xlUp).Row

For I = 2 To FinalRow If Cells(I, 1).Value = "Фрукт" Then Cells(I, 1).Resize(1, 3).Font.Bold = True Cells(I, 1).Resize(1, 3).Font.ColorIndex = 3 End If Next I

MsgBox "Все фрукты выделены красным цветом и утолщением _шрифта"End Sub

Конструкция If...Then...Else...End If Иногда необходимо выполнить один фрагмент кода, если условие равно

True, и другой YYYY если оно равно False. В VBA для этого следует указать втоY

рой фрагмент кода после ключевого слова Else. Для завершения блока

If...Then...Else используется выражение End If:

Sub FruitRedVegGreen() FinalRow = Cells(65536, 1).End(xlUp).Row

For I = 2 To FinalRow If Cells(I, 1).Value = "Фрукт" Then Cells(I, 1).Resize(1, 3).Font.ColorIndex = 3 Else Cells(I, 1).Resize(1, 3).Font.ColorIndex = 50

Page 157: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 157

End If Next I

MsgBox "Все фрукты выделены красным цветом, _а все овощи - изумрудным"End Sub

Конструкция If...ElseIf...End If Структура If...End If поддерживает возможность проверки

нескольких условий с помощью ключевого слова ElseIf. Как показано на

рис. 5.14, список продуктов содержит одно травянистое растение, что

наводит на мысль о необходимости проверки трех условий — является ли

элемент списка фруктом, овощем или травянистым растением? При

негативном результате всех трех проверок можно сделать вывод, что элемент

списка содержит ошибку:

Sub MultipleIf() FinalRow = Cells(65536, 1).End(xlUp).Row

For I = 2 To FinalRow If Cells(I, 1).Value = "Фрукт" Then Cells(I, 1).Resize(1, 3).Font.ColorIndex = 3 ElseIf Cells(I, 1).Value = "Овощ" Then Cells(I, 1).Resize(1, 3).Font.ColorIndex = 50 ElseIf Cells(I, 1).Value = "Растение" Then Cells(I, 1).Resize(1, 3).Font.ColorIndex = 5 Else 'Элемент списка содержит ошибку. Cells(I, 1).Resize(1, 3).Interior.ColorIndex = 6 End If Next I

MsgBox "Фрукты выделены красным цветом, овощи - изумрудным, _а травянистые растения - синим"End Sub

Конструкция Select Case...End Select Когда условий становится слишком много, использование структуры

If...ElseIf теряет свою привлекательность. Для таких случаев VBA распоY

лагает конструкцией Select Case, первая строка которой содержит так наY

зываемое условное выражение:

Select Case Cells(I, 1).Value

После строки с условным выражением перечислены его возможные значеY

ния, записанные после ключевого слова Case. Для каждого значения должен

быть указан фрагмент кода, который будет выполнен, если условное выражеY

ние примет это значение.

Если необходимо предусмотреть возможность принятия условным выY

ражением значения, отличного от всех перечисленных, воспользуйтесь

ключевыми словами Case Else. Завершает блок Select Case выражеY

ние End Select.

Page 158: ? Применение VBA и макросов в Microsoft® Excel

158 Часть I Первые шаги

Единственное отличие следующего кода от приведенного ранее заключаетY

ся в использовании конструкции Case Select вместо конструкции

If...ElseIf:

Sub SelectCase() FinalRow = Cells(65536, 1).End(xlUp).Row

For I = 2 To FinalRow Select Case Cells(I, 1).Value Case "Fruit" Cells(I, 1).Resize(1, 3).Font.ColorIndex = 3 Case "Vegetable" Cells(I, 1).Resize(1, 3).Font.ColorIndex = 50 Case "Herbs" Cells(I, 1).Resize(1, 3).Font.ColorIndex = 5 Case Else End Select Next I

MsgBox "Фрукты выделены красным цветом, овощи - изумрудным, _а травянистые растения - синим"End Sub

Использование сложных выражений Case Выражения Case могут быть как простыми (рассматривались в предыY

дущем разделе), так и сложными. Следующее выражение определяет единое

действие для ячеек, содержащих значения ‘‘Клубника’’, ‘‘Голубика’’ и

‘‘Малина’’:

Case "Клубника", "Голубика", "Малина" AdCode = 1

В качестве значения условного выражения можно указать диапазон, как

показано ниже:

Case 1 To 20 Discount = 0.05Case 21 To 100 Discount = 0.1

Кроме того, воспользовавшись ключевым словом Is и оператором сравнеY

ния (например, > или <), можно задать значение условного выражения как

открытый диапазон:

Case Is < 10 Discount = 0Case Is > 100 Discount = 0.2Case Else Discount = 0

Вложение выражений If Выражение If может находиться внутри другого выражения If. Вложение

выражений If требует от программиста аккуратности при оформлении проY

граммного кода. Поскольку в конце подобных конструкций скапливается неY

Page 159: ? Применение VBA и макросов в Microsoft® Excel

Циклы и управление выполнением кода Глава 5 159

сколько строк End If, соблюдение отступов поможет определить, к какому

выражению If относится та или иная строка End If.

Итоговый макрос содержит большое количество правил, описывающих

политику скидок.

Если объем заказа фруктов составляет менее 5 ящиков, скидка не преY

доставляется.

Если объем заказа фруктов составляет от 5 до 20 ящиков, предоставляY

ется скидка в размере 10%.

Если объем заказа фруктов составляет более 20 ящиков, предоставляетY

ся скидка в размере 15%.

Если объем заказа травянистых растений составляет менее 10 ящиков,

скидка не предоставляется.

Если объем заказа травянистых растений составляет от 10 до

15 ящиков, предоставляется скидка в размере 3%.

Если объем заказа травянистых растений составляет более 15 ящиков,

предоставляется скидка в размере 6%.

Если объем заказа овощей, за исключением спаржи, составляет

5 ящиков и более, предоставляется скидка в размере 12%.

Если объем заказа спаржи составляет 20 ящиков и более, предоставляY

ется скидка в размере 12%.

Во время распродажи продукта на него предоставляется скидка в разY

мере 25%. Никакие другие скидки при этом не предоставляются.

На этой неделе проводится распродажа клубники, салата и помидоров.

Ниже приведен код, реализующий указанную политику скидок.

Sub ComplexIf() FinalRow = Cells(65536, 1).End(xlUp).Row

For I = 2 To FinalRow ThisClass = Cells(I, 1).Value ThisProduct = Cells(I, 2).Value ThisQty = Cells(I, 3).Value

'Определение продуктов, находящихся на распродаже. Select Case ThisProduct Case "Клубника", "Салат", "Помидоры" Sale = True Case Else Sale = False End Select

'Расчет скидки. If Sale Then Discount = 0.25 Else If ThisClass = "Фрукт" Then Select Case ThisQty Case Is < 5

Page 160: ? Применение VBA и макросов в Microsoft® Excel

160 Часть I Первые шаги

Discount = 0 Case 5 To 20 Discount = 0.1 Case Is > 20 Discount = 0.15 End Select ElseIf ThisClass = "Растение" Then Select Case ThisQty Case Is < 10 Discount = 0 Case 10 To 15 Discount = 0.03 Case Is > 15 Discount = 0.05 End Select ElseIf ThisClass = "Овощ" Then'Расчет скидки на спаржу. If ThisProduct = "Спаржа" Then If ThisQty < 20 Then Discount = 0 Else Discount = 0.12 End If Else If ThisQty < 5 Then Discount = 0 Else Discount = 0.12 End If End If 'Является ли продукт спаржей? End If 'Является ли продукт овощем? End If 'Проводится ли распродажа продукта?

Cells(I, 4).Value = Discount

If Sale Then Cells(I, 4).Font.Bold = True End If

Next I

Range("D1").Value = "Скидка"

MsgBox "Расчет скидок завершен"

End Sub

Следующий шагЦикл YYYY это фундаментальный компонент любого языка программирования.

VBA поддерживает как традиционные циклы For...Next и Do...Loop, так и

цикл For Each...Next, характерный для объектноYориентированных языY

ков. В следующей главе будет рассмотрен очень важный для Excel VBA стиль

записи ссылок с таинственным названием R1C1.

Page 161: ? Применение VBA и макросов в Microsoft® Excel

6Сравнение стилей записиссылок A1 и R1C1.............................161Использование стиля ссылокR1C1 в Excel ..................................... 162Чудесный мир формул Excel ..... 163Ссылки в стиле R1C1 ..................... 166Использование ссылок в стилеR1C1 при условномформатировании ячеек...............171Использование ссылок в стилеR1C1 при создании формулымассива........................................... 174Следующий шаг............................ 175

Глава 6

Ñòèëü çàïèñèññûëîê R1C1

Сравнение стилейзаписи ссылок A1 и R1C1

Стиль записи ссылок A1 берет

свое начало от приложения VisiCalc.

Для обращения к ячейке, располоY

женной в верхнем левом углу элекY

тронной таблицы, Дэн Бриклин (Dan

Bricklin) и Боб Фрэнкстон (Bob

Frankston) предложили использовать

запись ‘‘A1’’. Аналогичную адресную

схему взял на вооружение Мич КейY

пор (Mitch Kapor) в своем легендарY

ном продукте Lotus 1Y2Y3. Вскоре заY

конодательницей мод попыталась

стать Microsoft, предложив рынку

программу Multiplan и стиль записи

ссылок R1C1. Согласно этому стилю

для обращения к ячейке, располоY

женной в верхнем левом углу элекY

тронной таблицы, использовалась

запись ‘‘R1C1’’, указывающая на то,

что ячейка находится в 1Yй строке

(Row) 1Yго столбца (Column).

Благодаря лидирующему положеY

нию, которое занимал на рынке проY

дукт Lotus 1Y2Y3 в 1980Yх и начале

1990Yх годов, стиль записи ссылок A1

стал общепризнанным стандартом.

Осознав всю невыгодность своей

стратегии, Microsoft добавила в Excel

поддержку адресации A1, сделав ее

используемой по умолчанию. СледуY

ет отметить, что официально MicroY

soft поддерживает оба способа записи

ссылок.

Page 162: ? Применение VBA и макросов в Microsoft® Excel

162 Часть I Первые шаги

R1C1 — дела давно минувших дней?

Подавляющее большинство пользователей Excel единогласны во мнении,

что стиль записи ссылок R1C1 давно утратил свою актуальность. К сожалеY

нию, именно этот стиль ‘‘пришелся по душе’’ средству записи макросов. ТаY

ким образом, на первый взгляд знание адресной схемы R1C1 вызвано необхоY

димостью уметь ‘‘читать’’ автоматически сгенерированный код.

R1C1 — сильные стороны

И все же необходимо отдать должное Microsoft. Познакомившись с R1C1Y

формулами, вы поймете, что они намного полезнее обычных формул

(особенно ярко это проявляется при использовании формул в VBA). ПримеY

нение ссылок в стиле R1C1 позволяет создавать более эффективный код.

Кроме того, употребление адресации R1C1 является обязательным требованиY

ем при создании формул массивов и при задании условного форматирования

ячеек. Именно последнее и обуславливает необходимость ознакомления с таY

инственным стилем записи ссылок R1C1.

Использование стиля ссылок R1C1 в Excel Чтобы указать на необходимость использования в Excel адресации R1C1,

выберите команду главного меню Сервис Параметры (Tools Options), пеY

рейдите во вкладку Общие (General) и установите флажок Стиль ссылокR1C1 (R1C1 reference style) (рис. 6.1).

Рис. 6.1. Чтобы выбрать адресацию R1C1, установите флажок Стиль ссылокR1C1 на вкладке Общие диалогового окна Параметры

Page 163: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 163

После перехода к стилю ссылок R1C1 буквы в заголовках столбцов (A, B,

C и т.д.) будут заменены цифрами (1, 2, 3 и т.д.), как показано на рис. 6.2.

Рис. 6.2. После перехода к стилю ссылок R1C1 буквы взаголовках столбцов будут заменены цифрами

В соответствии с новой адресацией ячейка B5 будет называться R5C2, поY

скольку она расположена в 5Yй строке 2Yго столбца.

Чудесный мир формул Excel Возможность автоматического пересчета значений тысяч ячеек стала осY

новным преимуществом электронных таблиц перед перфокартами, испольY

зуемыми вплоть до 1979 года. В наши дни одной из наиболее востребованных

функций электронных таблиц является функция автоматического копироваY

ния формулы из одной ячейки в другую.

Как “размножаются” формулы

Рассмотрим достаточно простую электронную таблицу, показанную на

рис. 6.3.

Рис. 6.3. С помощью маркера заполнения формула можетбыть скопирована из одной ячейки в другую

Введите в ячейку D4 формулу =C4*B4 и с помощью маркера заполнения

скопируйте ее в ячейки D5:D9.

Page 164: ? Применение VBA и макросов в Microsoft® Excel

164 Часть I Первые шаги

Формула в ячейке F4 включает в себя как абсолютные, так и относительY

ные ссылки: =ЕСЛИ(E4;ОКРУГЛ(D4*$B$1;2);0) (=IF(E4,ROUND(D4*$B$1,2),0)). Благодаря наличию знаков доллара ($) эта формула всегда вычисляет

произведение общей цены товара, находящейся в столбце D текущей строки,

на величину налога, внесенную в ячейку B1.

Результат вычисления значений ячеек, показанный на рис. 6.4, был достигнут с

помощью формул, показанных на рис. 6.5. (Чтобы переключиться в режим отоY

бражения формул в Excel, воспользуйтесь комбинацией клавиш <Ctrl+~>.)

Рис. 6.4. Результат вычисления значений ячеек в столбцах D,F и G достигнут с помощью формул, показанных на рис. 6.5

Рис. 6.5. Чтобы переключиться в режим отображения формул в Excel, воспользуйтеськомбинацией клавиш <Ctrl+~>. Возможность автоматического копирования форму&лы из одной ячейки в другую поистине удивительна!

Обратите внимание, что для достижения показанного на рис. 6.5 результаY

та необходимо ввести вручную всего лишь 4 формулы: 3 в ячейки D4, F4, G4и 1 в ячейку G10. В остальные ячейки формулы могут быть скопированы авY

томатически. Превращение формулы =F4+D4 в ячейке G4 при ее копировании

в ячейку G5 в формулу =F5+D5 приводит начинающих пользователей Excel

в настоящий восторг!

Разоблачение

На самом деле Excel оперирует только R1C1Yформулами. Поддержка

формул в стиле A1 для совместимости со стандартом VisiCalc и Lotus реализоY

вана исключительно на уровне интерфейса Excel.

Page 165: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 165

Перейдя к стилю ссылок R1C1, можно заметить, что ‘‘различные’’ формуY

лы в ячейках D4:D9 на самом деле являются одной и той же R1C1Yформулой.

Это же справедливо и по отношению к ячейкам F4:F9 и G4:G9 (рис. 6.6).

Рис. 6.6. Переход к стилю ссылок R1C1 дает неожиданный результат — все формулы,расположенные в столбцах 4 и 6, одинаковые

Поскольку поддержка формул в стиле A1 реализована исключительно на уровY

не интерфейса Excel, становится ясно, что автоматическое копирование формулы

из одной ячейки в другую отнюдь не является чемYто экстраординарным.

Поддержка ссылок в стиле R1C1 делает возможным более эффективное

применение формул в макросах VBA. В частности, это позволяет ввести одну

и ту же формулу в целый диапазон ячеек с помощью одной строки кода.

Практикум

Использование ссылок в стиле A1 и R1C1 в VBA Заполним ячейки рассмотренной выше таблицы с помощью VBA, используя ссыл&ки в стиле A1. Прежде всего, введем формулы в ячейки D4, F4 и G4. Далее, скопи&руем их и вставим в требуемые ячейки, как показано ниже: Sub BookA1Style()' Нахождение последней строки с данными. FinalRow = Range("B65536").End(xlUp).Row' Ввод формул. Range("D4").Formula = "=B4*C4"' В англоязычной версии Excel:' Range("F4").Formula = "=IF(E4,ROUND(D4*$B$1,2),0)" Range("F4").FormulaLocal = "=ЕСЛИ(E4;ОКРУГЛ(D4*$B$1;2);0)" Range("G4").Formula = "=F4+D4"' Копирование формул в строке 4 в требуемые ячейки. Range("D4").Copy Destination:=Range("D5:D" & FinalRow) Range("F4:G4").Copy Destination:=Range("F5:G" & FinalRow)' Формирование итоговой строки. Cells(FinalRow + 1, 1).Value = "Всего"' В англоязычной версии Excel:' Cells(FinalRow + 1, 6).Formula = "=SUM(G4:G" & FinalRow & ")" Cells(FinalRow + 1, 6).FormulaLocal = "=СУММ(G4:G" & _FinalRow & ")"End Sub

Page 166: ? Применение VBA и макросов в Microsoft® Excel

166 Часть I Первые шаги

Как видим, понадобилось 3 строки для ввода формул и еще 2 для их копированияв требуемые ячейки. Эквивалентный код, в котором используются ссылки в стиле R1C1, позволяет вве&сти формулу сразу в целый диапазон ячеек с помощью одной строки кода, как по&казано ниже: Sub BookR1C1Style()' Нахождение последней строки с данными. FinalRow = Range("B65536").End(xlUp).Row' Ввод формул. Range("D4:D" & FinalRow).FormulaR1C1 = "=RC[-1]*RC[-2]"' В англоязычной версии Excel: ' Range("F4:F" & FinalRow).FormulaR1C1 = _"=IF(RC[-1],ROUND(RC[-2]*R1C2,2),0)" Range("F4:F" & FinalRow).FormulaR1C1Local = _"=ЕСЛИ(RC[-1];ОКРУГЛ(RC[-2]*R1C2;2);0)" Range("G4:G" & FinalRow).FormulaR1C1 = "=+RC[-1]+RC[-3]"' Формирование итоговой строки. Cells(FinalRow + 1, 1).Value = "Всего"' В англоязычной версии Excel:' Cells(FinalRow + 1, 6).Formula = "=SUM(G4:G" & FinalRow & ")" Cells(FinalRow + 1, 6).FormulaLocal = _"=СУММ(G4:G" & FinalRow & ")"End Sub

Ссылки в стиле R1C1 Согласно стилю R1C1, обращение к ячейке осуществляется по номеру ее

строки (R) и столбца (С). Подробное рассмотрение ссылок в стиле R1C1 начY

нем с относительных ссылок как наиболее часто используемых в формулах на

рабочем листе и в VBA.

Относительные ссылки в стиле R1C1

Рассмотрим задачу обращения к ячейке в формуле Excel. Чтобы определить

адрес ячейки, следует задать смещение по строкам и столбцам в квадратных

скобках после букв ‘‘R’’ и ‘‘C’’, соответственно.

Положительное смещение по столбцам обозначает смещение вправо на

указанное число позиций, а отрицательное смещение по столбцам YYYY смещеY

ние влево на указанное число позиций. К примеру, адрес ячейки F5 относиY

тельно ячейки E5 выглядит как RC[1], а адрес ячейки D5 относительно ячейY

ки E5 — как RC[-1].

Положительное смещение по строкам обозначает смещение вниз на укаY

занное число позиций, а отрицательное смещение по строкам YYYY смещение

вверх на указанное число позиций. К примеру, адрес ячейки E6 относительно

ячейки E5 выглядит как R[1]C, а адрес ячейки E4 относительно ячейки E5 —

как R[-1]C.

Нулевое смещение по строкам или столбцам (обозначается отсутствием

соответствующих квадратных скобок) используется для обращения к ячейкам,

Page 167: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 167

расположенным в той же строке или столбце, что и ячейка с формулой. РасY

смотрим несколько примеров.

Чтобы обратиться к ячейке D4 из ячейки E5, следует воспользоваться

формулой =R[-1]C[-1].

Чтобы обратиться к ячейке D5 из ячейки E5, следует воспользоваться

формулой =RC[-1].

Чтобы обратиться к ячейке F5 из ячейки E5, следует воспользоваться

формулой =RC[1].

Чтобы обратиться к ячейке E5 из ячейки E5, следует воспользоваться

формулой =RC. Последняя формула определяет так называемую цикY

лическую ссылку и, как правило, никогда не применяется на практике.

Более наглядно обращение к различным ячейкам из ячейки E5 продемонY

стрировано на рис. 6.7.

Рис. 6.7. Пример использования относительных ссылок встиле R1C1

Относительные ссылки в стиле R1C1 можно применять и для обращения к

диапазону ячеек. К примеру, следующая формула суммирует значение

12 ячеек, расположенных слева от ячейки с формулой:

=СУММ(RC[-12]:RC[-1])

(В англоязычной версии Excel эта формула записывается как =SUM(RC[-12]:RC[-1]).)

Абсолютные ссылки в стиле R1C1

Абсолютная ссылка всегда указывает на ячейку, расположенную в опредеY

ленном месте. При использовании адресации в стиле A1 абсолютные ссылки

задаются путем предварения буквы столбца и номера строки знаком доллара

($), например $B$2.

При использовании адресации в стиле R1C1 абсолютные ссылки задаются

путем опускания квадратных скобок, например R2C2.

Смешанные ссылки в стиле R1C1

Смешанная ссылка содержит либо абсолютный столбец и относительную

строку, либо абсолютную строку и относительный столбец.

Page 168: ? Применение VBA и макросов в Microsoft® Excel

168 Часть I Первые шаги

Рассмотрим макрос, импортирующий в Excel файл Счет.txt. Адрес итоY

говой строки вычисляется с помощью выражения .End(xlUp). В определенY

ные ячейки итоговой строки необходимо поместить сумму значений всех ячеек,

расположенных выше ячейки с формулой вплоть до 2Yй строки включительно:

Sub MixedReference() TotalRow = Cells(65536, 1).End(xlUp).Row + 1 Cells(TotalRow, 1).Value = "Всего"' В англоязычной версии Excel:' Cells(TotalRow, 5).Resize(1, 3).FormulaR1C1 = _'"=SUM(R2C:R[-1]C)" Cells(TotalRow, 5).Resize(1, 3).FormulaR1C1Local = _"=СУММ(R2C:R[-1]C)"End Sub

Как показано в приведенном выше коде, упомянутый диапазон ячеек задаY

ется как R2C:R[-1]C. Таким образом, единственная R1C1Yформула может

быть использована для обращения к диапазону ячеек неопределенного размеY

ра, что еще раз подтверждает эффективность использования ссылок в стиле

R1C1 (рис. 6.8).

Рис. 6.8. Пример использования смешанной ссылки в стиле R1C1

Обращение к строке или столбцу с помощью ссылокв стиле R1C1

Рассмотрим задачу нахождения максимального значения в столбце G. ПоY

скольку точное число строк с данными заранее неизвестно, для этого можно

применить A1Yформулу =МАКС($G:$G) (=MAX($G:$G)) или R1C1Yформулу

=МАКС(C7) (=MAX(C7)). Аналогично, для того чтобы найти минимальное

значение в строке 1, можно применить A1Yформулу =МИН($1:$1)(=MIN($1:$1)) или R1C1Yформулу =МИН(R1) (=MIN(R1)). Обратиться к

строке или столбцу можно также с помощью относительной ссылки в стиле

R1C1. Например, чтобы найти среднее всех значений в строке, расположенной

над текущей ячейкой, можно воспользоваться формулой =СРЗНАЧ(R[-1]) (=AVERAGE(R[-1])).

Page 169: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 169

Замена нескольких A1Lформул одной R1C1Lформулой

Формулы R1C1 намного эффективнее A1Yформул. Рассмотрим классичеY

ский пример построения таблицы умножения с помощью однойYединственной

формулы, использующей смешанные ссылки в стиле R1C1.

Построение таблицы умножения с помощью единственнойR1C1Lформулы

Введите числа от 1 до 12 в ячейки B1:M1. Выделите эти ячейки и скопируйY

те их с применением транспонирования в ячейки A2:A13. Создадим формулу,

вычисляющую для каждой ячейки из диапазона B2:M13 произведение соотY

ветствующих чисел из 1Yго столбца и 1Yй строки. Естественно, здесь не обойY

тись без ссылок в стиле R1C1:

Sub MultiplicationTable()' Построение таблицы умножения с помощью одной R1C1-формулы. Range("B1:M1").Value = Array(1, 2, 3, 4, 5, 6, 7, _8, 9, 10, 11, 12) Range("B1:M1").Font.Bold = True Range("B1:M1").Copy Range("A2:A13").PasteSpecial Transpose:=True Range("B2:M13").FormulaR1C1 = "=RC1*R1C" Cells.EntireColumn.AutoFitEnd Sub

Формула =RC1*R1C проста до гениальности. Результатом выполнения приY

веденного выше кода является таблица умножения, показанная на рис. 6.9.

Рис. 6.9. Таблица умножения, построенная с по&мощью формулы =RC1*R1C

Внимание Обратите внимание, что после выполнения макроса диапазон ячеек B1:M1 остаетсяактивным элементом буфера обмена. Если нажать клавишу <Enter>, содержимоеэтого диапазона будет скопировано в текущую выделенную область рабочего листа,что, вообще говоря, нежелательно. Чтобы выйти из режима копирования/вставки,добавьте в конце макроса строку Application.CutCopyMode = False.

Page 170: ? Применение VBA и макросов в Microsoft® Excel

170 Часть I Первые шаги

Интересный факт

Проведем небольшой эксперимент. Выделите ячейку F6 и начните запись

нового макроса, выбрав в меню Excel команду Сервис Макрос Начать запись(Tools Macro Record New Macro). Щелкните на кнопке Относительнаяссылка (Relative Reference), расположенной на панели инструментов

Остановить запись (Stop Recording). Введите формулу =A1 и нажмите комбиY

нацию клавиш <Ctrl+Enter>, чтобы остаться в ячейке F6. Щелкните на кнопY

ке Остановить запись, расположенной на одноименной панели инструменY

тов, чтобы остановить запись макроса.

Код, сгенерированный средством записи макросов, фактически будет

представлять собой одну формулу, ссылающуюся на ячейку, расположенную

на 5 строк выше и на 5 столбцов левее текущей активной ячейки:

Sub PointFiveRowsUp() ActiveCell.FormulaR1C1 = "=R[-5]C[-5]"End Sub

А теперь выделите ячейку A1 и выполните только что созданный макрос.

Вероятно, вы ожидаете получить сообщение о распространенной ошибке вреY

мени выполнения 1004? Как бы не так! В результате выполнения макроса

формула в ячейке A1 будет ссылаться на ячейку IR65532, что фактически озY

начает переход из левой верхней в правую нижнюю часть рабочего листа. НеY

смотря на то, что этот весьма любопытный факт не имеет какойYлибо практиY

ческой ценности, его знание может пригодиться при написании программY

ного кода.

Тренируем память

Преимущество использования R1C1Yформул в коде VBA частично нивелиY

руется необходимостью переключения интерфейса Excel в режим ссылок в

стиле R1C1. Многие пользователи предпочитают не делать этого и стараются

запомнить соответствие между буквами, применяемыми в качестве заголовка

столбцов, и порядковыми номерами последних.

К сожалению, запомнить, что буква ‘‘U’’ является 21Yй буквой латинского

алфавита, получается далеко не сразу. Следующая игра поможет вам быстрее

натренировать свою память:

Sub QuizColumnNumbers() Do i = Int(Rnd() * 26) + 1 Ans = InputBox("Заголовком какого столбца является _буква " & Chr(64 + i) & "?") If Ans = "" Then Exit Do If Not (Ans + 0) = i Then MsgBox "Буква " & Chr(64 + i) & " является _заголовком столбца # " & i End If LoopEnd Sub

Page 171: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 171

Если вы не считаете подобную игру забавной или же вам необходимо узY

нать порядковый номер какогоYнибудь ‘‘удаленного’’ столбца (например, DG),

обратитесь к интерфейсу Excel. Выделите ячейку A1 и, удерживая нажатой

клавишу <Shift>, нажмите несколько раз клавишу <→>. Пока длина выделенY

ного диапазона ячеек не вышла за пределы экрана, порядковый номер поY

следнего столбца можно узнать с помощью поля Имя (Name Box), располоY

женного слева от поля ввода формулы, как показано на рис. 6.10.

Рис. 6.10. Пока длина выделенного диапазона ячеек невышла за пределы экрана, количество выделенных строк истолбцов отображается в поле Имя слева от поля вводаформулы

Когда длина выделенного диапазона ячеек выйдет за пределы экрана, коY

личество выделенных строк и столбцов будет отображаться с помощью всплыY

вающей подсказки. В частности, порядковый номер столбца DG равен 111, как

показано на рис. 6.11.

Рис. 6.11. Когда длина выделенного диапазона ячеек выходит запределы экрана, количество выделенных строк и столбцов ото&бражается с помощью всплывающей подсказки

Использование ссылок в стиле R1C1 при условномформатировании ячеек

При условном форматировании ячеек рекомендуется использовать R1C1Y

формулы. Применение A1Yформул является нежелательным (по имеющимся

наблюдениям, примерно 1 из 50 ячеек с условным форматированием, опредеY

ленным с помощью A1Yформул, содержит ошибку).

Задание условного форматирования с помощьюпользовательского интерфейса

Существует два вида условного форматирования. Открыв диалоговое окно

Условное форматирование (Conditional Formatting) с помощью команды меY

ню Формат Условное форматирование (Format Conditional Formatting),

можно заметить, что по умолчанию в качестве критерия форматирования исY

пользуется значение ячейки. Например, вы можете определить особый форY

Page 172: ? Применение VBA и макросов в Microsoft® Excel

172 Часть I Первые шаги

мат для ячеек, содержащих отрицательные числа. Согласно второму типу усY

ловного форматирования критерий форматирования определяется с помощью

формулы, принимающей значение True или False. Формула может содерY

жать ссылки на любые ячейки рабочего листа, а также объединять несколько

критериев с помощью функций ИЛИ (OR) и И (AND). Для каждой ячейки можно

определить 3 различных критерия форматирования.

Рассмотрим задачу сокрытия текста ячеек, содержащих сообщения об

ошибке, и выделения текста ячеек с отрицательными числами красным цвеY

том. Наиболее очевидным ее решением является задание условного форматиY

рования. Первый критерий будет основываться на формуле, второй YYYY на знаY

чении ячейки. Пример установки подобного условного форматирования с поY

мощью интерфейса Excel показан на рис. 6.12.

Рис. 6.12. В качестве первого критерия форматирования ячейки ис&пользуется формула, в качестве второго — значение ячейки

Задание условного форматирования с помощью VBA

Задача сокрытия текста ячеек, содержащих сообщения об ошибке, может

быть решена путем установки цвета заливки ячейки равным цвету ее текста.

Для реализации такого решения создадим небольшой макрос VBA.

Задание условного форматирования ячеек осуществляется посредством

использования объекта FormatConditions. Поскольку для каждой ячейки

может быть определено три критерия форматирования, следующий код сперва

отменяет любое условное форматирование в пределах рабочего листа, после

чего применяет два критерия форматирования к каждой непустой ячейке.

Первый критерий форматирования основывается на R1C1Yформуле (тип

xlExpression), второй YYYY на значении ячейки (тип xlCellValue). ОбратиY

те внимание, что кроме значения ячейки необходимо указать также и операY

тор сравнения. После задания критериев форматирования определяется сам

формат ячеек (в данном случае YYYY цвет текста), как показано ниже:

Sub ApplySpecialFormattingAll()' Сокрытие текста ячеек, содержащих сообщения об ошибке. For Each ws In ThisWorkbook.Worksheets

Page 173: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 173

ws.UsedRange.FormatConditions.Delete For Each cell In ws.UsedRange.Cells If Not IsEmpty(cell) Then' В англоязычной версии Excel:' cell.FormatConditions.Add Type:=xlExpression, _' Formula1:="=OR(ISERR(RC),ISNA(RC))" cell.FormatConditions.Add Type:=xlExpression, _ Formula1:="=ИЛИ(ЕОШИБКА(RC);ЕНД(RC))" cell.FormatConditions(1).Font.Color = _cell.Interior.Color cell.FormatConditions.Add Type:=xlCellValue, _Operator:=xlLess, Formula1:="0" cell.FormatConditions(2).Font.ColorIndex = 3 End If Next cell Next wsEnd Sub

Внимание Не используйте A1&формулы для задания критерия условного форматированияв VBA. Соответствующий код может выполняться корректно лишь для небольшогочисла ячеек, однако при попытке его применения к 50 и более ячейкам существуетвероятность сбоя (более подробно об этом рассказывается в следующем практи&куме). Использование R1C1&формул полностью лишено подобного недостатка.

Практикум

Поиск минимального и максимальногозначения в столбцеРассмотрим классический пример использования условного форматированияячеек. На рис. 6.13 показано, как выделить строки, содержащие минимальное имаксимальное значение в определенном столбце, с помощью интерфейса Excel.

Рис. 6.13. Классический пример, позволяющий выявить одну из про&

блем задания условного форматирования ячеек с помощью VBA

Page 174: ? Применение VBA и макросов в Microsoft® Excel

174 Часть I Первые шаги

Ниже приведен соответствующий код VBA:Sub FindMinMax()' Выделить строку, содержащую наибольший доход, зеленым цветом.' Выделить строку, содержащую наименьший доход, желтым цветом. FinalRow = Cells(Application.Rows.Count, 1).End(xlUp).Row With Range("A2:I" & FinalRow) .FormatConditions.Delete' В англоязычной версии Excel:' .FormatConditions.Add Type:=xlExpression, _'Formula1:="=RC7=MAX(C7)" .FormatConditions.Add Type:=xlExpression, _Formula1:="=RC7=МАКС(C7)" .FormatConditions(1).Interior.ColorIndex = 4' В англоязычной версии Excel:' .FormatConditions.Add Type:=xlExpression, _'Formula1:="=RC7=MIN(C7)" .FormatConditions.Add Type:=xlExpression, _Formula1:="=RC7=МИН(C7)" .FormatConditions(2).Interior.ColorIndex = 6 End WithEnd Sub

Для нахождения строки с наибольшим значением в столбце G используется фор&мула МАКС(C7) (MAX(C7)), синтаксис которой позволяет считать ее и A1&, и R1C1&формулой. Вспомним, что Microsoft изначально использовала ссылки в стиле R1C1и ввела поддержку ссылок в стиле A1 только для совместимости с Lotus 1&2&3. По&скольку в первую очередь Excel пытается проинтерпретировать формулу с исполь&зованием ссылок в стиле R1C1 (это недокументированная особенность Excel), вы&полнение приведенного выше кода приведет к желаемому результату.А теперь представьте себе, что случится, если вы зададите условное форматиро&вание с помощью формулы, ссылающейся на ячейку C7 или R22. Вы получите со&всем не тот результат, на который рассчитывали, поскольку Excel воспримет этиссылки как ссылки на 7&й столбец и 22&ю строку, соответственно. Именно поэтомупри задании условного форматирования рекомендуется использовать толькоR1C1&формулы.

Использование ссылок в стиле R1C1при создании формулы массива

Формулы массива YYYY это одни из наиболее мощных формул в Excel. ИноY

гда их называют CSEYформулами, поскольку при вводе формулы массива исY

пользуется комбинация клавиш <Ctrl+Shift+Enter>.

Формула массива, введенная в ячейке E20 (рис. 6.14), реализует 18 операций

умножения и суммирование полученных при каждом умножении результатов.

Если ввести формулу массива без применения комбинации клавиш

<Ctrl+Shift+Enter>, в ячейке будет выведено сообщение об ошибке #ЗНАЧ!(#VALUE!). Обратите внимание, что при вводе формулы массива брать ее в

фигурные скобки не нужно.

Page 175: ? Применение VBA и макросов в Microsoft® Excel

Стиль записи ссылок R1C1 Глава 6 175

Рис. 6.14. Формула массива, введенная в ячейке E20, реали&зует 18 операций умножения и суммирование полученных прикаждом умножении результатов. Для ввода формулы необхо&димо использовать комбинацию клавиш <Ctrl+Shift+Enter>

Ниже приведен код, использующийся для ввода формулы массива:

Sub EnterArrayFormulas()' Ввод формулы массива.FinalRow = Cells(65536, 1).End(xlUp).RowCells(FinalRow + 1, 5).FormulaArray = _"=SUM(R2C[-1]:R[-1]C[-1]*R2C:R[-1]C)"End Sub

Несмотря на то что в интерфейсе Excel отображаются ссылки в стиле A1,

помните, что формулу массива необходимо вводить с использованием ссылок

в формате R1C1.

Следующий шагСогласно стилю R1C1, обращение к ячейке осуществляется по номеру ее

строки (R) и столбца (С). Использование R1C1Yформул позволяет создавать

более эффективный и корректный код VBA. Кроме того, употребление адреY

сации R1C1 является обязательным требованием при создании формул массиY

вов и при задании условного форматирования ячеек. В следующей главе будут

рассмотрены именованные диапазоны ячеек YYYY еще одно средство, упроY

щающее разработку макросов в Excel.

Page 176: ? Применение VBA и макросов в Microsoft® Excel
Page 177: ? Применение VBA и макросов в Microsoft® Excel

7Глобальные и локальныеимена .............................................. 177Создание имен.............................. 179Удаление имен .............................180Типы имен......................................180Скрытие имен ............................... 185Проверка существованияимени.............................................. 185Следующий шаг............................ 187

Глава 7

Èìåíà

Поле для ввода имени диапазона

ячеек, формулы, массива и т.п. распоY

лагается на рабочем листе слева от поY

ля ввода формулы. Присваивание

имен различным объектам Excel сущеY

ственно упрощает их использование.

Возможность создавать имена и

манипулировать ими доступна также

и в VBA. Далее в этой главе будут расY

смотрены различные типы имен и

способы их применения на практике.

Глобальные илокальные имена

Все имена можно разделить на две

категории YYYY глобальные имена (область

действия распространяется на всю раY

бочую книгу) и локальные имена

(область действия ограничена одним

рабочим листом). В рабочей книге моY

жет содержаться несколько одинакоY

вых локальных имен, однако только

одно уникальное глобальное имя. При

обращении к локальному имени необY

ходимо указывать соответствующий

рабочий лист (Лист1!Фрукты), тогда

как при обращении к глобальному

имени никаких дополнительных треY

бований не ставится (Фрукты).

Показанное на рис. 7.1 диалогоY

вое окно Присвоение имени (Define

Name) содержит смешанный спиY

сок, состоящий из глобальных и лоY

кальных имен.

Имя рабочего листа, соответстY

вующего локальному имени, вывоY

дится справа от последнего.

Page 178: ? Применение VBA и макросов в Microsoft® Excel

178 Часть I Первые шаги

Рис. 7.1. Диалоговое окно Присвоение имени со&держит список глобальных и локальных имен

При совпадении глобального и локального имени в окне Присвоениеимени выводится только локальное имя при условии, что соответствующий

ему рабочий лист является активным (рис. 7.2).

Рис. 7.2. При совпадении глобального и локаль&ного имени в списке имен выводится только ло&кальное имя при условии, что соответствующийему рабочий лист является активным

Если же активным является другой рабочий лист, в окне Присвоениеимени выводится только глобальное имя, как показано на рис. 7.3.

Совет Средство проверки вводимых значений (чтобы воспользоваться этим средством,выберите команду меню Excel Данные Проверка (Data Validation)) позволяетвыделить диапазон ячеек только на активном рабочем листе. Чтобы обойти этоограничение, присвойте имя диапазону данных, которые вы хотите проверить.

Page 179: ? Применение VBA и макросов в Microsoft® Excel

Имена Глава 7 179

Рис. 7.3. При совпадении глобального и локаль&ного имени в списке имен выводится только гло&бальное имя при условии, что соответствующийлокальному имени рабочий лист НЕ являетсяактивным

Создание имен Рассмотрим пример кода, сгенерированного средством записи макросов

при создании именованного диапазона ячеек:

ActiveWorkbook.Names.Add Name:="Фрукты", _RefersToR1C1:="=Лист2!R1C1:R6C6"

Как следует из приведенного выше кода, именованный диапазон ячеек ноY

сит имя Фрукты и охватывает ячейки A1:F6 (R1C1:R6C6). Формулу, опредеY

ляющую диапазон ячеек, следует предварить знаком равенства и взять в каY

вычки. Адрес диапазона задается с помощью абсолютной ссылки (с использоY

ванием знаков $) или с помощью ссылки в стиле R1C1. Если диапазон ячеек

находится на текущем активном листе, имя последнего можно не указывать

(тем не менее, указание полного адреса диапазона ячеек повышает читабельY

ность кода).

Чтобы создать локальное имя, предварите его именем рабочего листа, как

показано ниже:

ActiveWorkbook.Names.Add Name:="Лист2!Фрукты", _RefersToR1C1:="=Лист2!R1C1:R6C6"

или воспользуйтесь коллекцией Names данного рабочего листа:

Worksheets("Лист1").Names.Add Name:="Фрукты", _RefersToR1C1:="=Лист1!R1C1:R6C6"

Существует и более простой способ создания имен. Ниже приведены приY

меры создания глобального и локального имени, соответственно:

Range("A1:F6").Name = "Фрукты"Range("A1:F6").Name = "Лист1!Фрукты"

К сожалению, указанный выше способ имеет одно существенное ограниY

чение YYYY он позволяет создавать только имена диапазонов ячеек. Для создания

имен формул, строк, чисел и массивов необходимо использовать метод Add.

Page 180: ? Применение VBA и макросов в Microsoft® Excel

180 Часть I Первые шаги

Чтобы изменить существующее имя, воспользуйтесь свойством Name, как

показано ниже:

Names("Фрукты").Name = "Товар"

В результате выполнения приведенного выше кода имя Фрукты становится

недействительным; к соответствующему диапазону ячеек можно обратиться

по новому имени Товар.

Если строка Range("A1:F6").Name = "Фрукты" расположена выше

строки Range("A1:F6").Name = "Товар", имя Товар переопределяет имя

Фрукты, как показано на рис. 7.4.

Рис. 7.4. Локальное имя Фрукты было замененолокальным именем Товар. Обратите вниманиена то, что глобальное имя Фрукты по&прежнемудоступно

Попытка обращения к локальному имени Фрукты приведет к возникновеY

нию ошибки, поскольку такое имя больше не существует.

Удаление имен Чтобы удалить имя, воспользуйтесь методом Delete, как показано ниже:

Names("ТоварНомер").Delete

Попытка удаления несуществующего имени приведет к возникновению

ошибки.

Внимание При совпадении глобального и локального имени следует обратить особое вни&мание на необходимость корректного указания удаляемого имени.

Типы имен Наиболее распространенный способ использования имен заключается в

создании именованных диапазонов ячеек. Тем не менее, предназначение

имен гораздо шире YYYY они позволяют упростить доступ к большим объемам

Page 181: ? Применение VBA и макросов в Microsoft® Excel

Имена Глава 7 181

информации практически любого рода. В отличие от переменных, имена храY

нят данные и после завершения выполнения программного кода.

В следующих разделах рассматриваются имена формул, строк, чисел и

массивов.

Имена формул

Синтаксис создания имени формулы аналогичен синтаксису создания

имени диапазона ячеек, поскольку при определении последнего используется

формула:

Names.Add Name:="ТоварСписок", RefersTo:="=СМЕЩ(_Лист2!A2;0;0;СЧЁТЗ(Лист2!$A:$A))"

(В англоязычной версии Excel функции СМЕЩ соответствует функция OFFSET.)

В результате выполнения приведенной выше строки кода будет определено

имя формулы, ссылающейся на динамический столбец (рис. 7.5).

Рис. 7.5. Пример создания имени формулы

Имена строк

При создании имени строки значение последней заключается в кавычки

(знак равенства, как при создании имени диапазона и формулы, не ставится):

Names.Add Name:="Компания", RefersTo:="КомпанияА"

На рис. 7.6 показано диалоговое окно Присвоение имени (Define Name),

в списке имен которого содержится имя строки.

Совет Поскольку имена не теряют свои значения между сеансами работы в Excel, онибольше подходят для хранения данных, чем ячейки. Рассмотрим задачу храненияназвания компании, ставшей лучшим поставщиком за определенный промежутоквремени. Одним из решений этой задачи является создание имени ЛучшийПо-ставщик. Альтернативный способ хранения имени лучшего поставщика заключа&ется в использовании ячейки на отдельном рабочем листе, что менее удобно.

Page 182: ? Применение VBA и макросов в Microsoft® Excel

182 Часть I Первые шаги

Рис. 7.6. Пример создания имени строки

Следующая процедура демонстрирует пример использования ячеек для

хранения данных между сеансами работы в Excel:

Sub NoNames(ByRef CurrentTop As String) TopSeller = Worksheets("Переменные").Range("A1").Value If CurrentTop = TopSeller Then MsgBox ("Лучшим поставщиком снова стал ' &&TopSeller &'!") Else MsgBox ("Лучшим поставщиком стал " & CurrentTop) End IfEnd Sub

Ниже приведен код аналогичной процедуры, использующий для хранения

данных между сеансами работы в Excel имена:

Sub WithNames() If Evaluate("Текущий") = Evaluate("Предыдущий") Then MsgBox ("Лучшим поставщиком снова стал " & _Evaluate("Предыдущий") & "!") Else MsgBox ("Лучшим поставщиком стал " & Evaluate("Текущий")) End IfEnd Sub

Поскольку Текущий и Предыдущий являются заранее созданными именаY

ми, доступ к их значениям осуществляется напрямую, без необходимости созY

дания переменных. Обратите внимание, что для доступа к значению имени

используется метод Evaluate.

Внимание Длина строки не может превышать 255 символов.

Имена чисел

Имена могут использоваться и для хранения чисел. Ниже приведены два

примера создания имени числа YYYY с участием переменной и без нее:

NumofSales = 5123Names.Add Name:="ПродажиВсего", RefersTo:=NumofSales

Names.Add Name:="ПродажиВсего", RefersTo:=5123

Page 183: ? Применение VBA и макросов в Microsoft® Excel

Имена Глава 7 183

Обратите внимание на отсутствие кавычек и знака равенства. Кавычки

способны превратить число в строку, а знак равенства YYYY в формулу.

Чтобы извлечь значение имени числа, можно воспользоваться двумя метоY

дами YYYY простым и сокращенным:

NumofSales = Names("ПродажиВсего").Value

NumofSales = [ПродажиВсего]

Следует отметить, что использование квадратных кавычек равносильно

вызову метода Evaluate и способно в определенной степени затруднить поY

нимание программного кода. Чтобы сделать код более читабельным, рекоY

мендуется воздержаться от использования метода Evaluate или снабдить соY

ответствующие фрагменты кода комментариями.

Имена массивов

Имена могут использоваться для хранения целых массивов. Размер массиY

ва ограничен 256 столбцами и 5461 элементами (более подробно массивы расY

сматриваются в главе 17, ‘‘Массивы’’).

Создание имени массива похоже на создание имени числа:

Sub NamedArray() Dim myArray(10, 5) Dim i As Integer, j As Integer' Заполнение массива myArray значениями. For i = 1 To 10 For j = 1 To 5 myArray(i, j) = i + j Next j Next i' Создание имени массива. Names.Add Name:="Массив", RefersTo:=myArrayEnd Sub

Как и при создании имени числа, обратите внимание на отсутствие кавыY

чек и знака равенства.

Зарезервированные имена

Excel содержит несколько зарезервированных имен, которые не рекоменY

дуется использовать при создании собственных имен.

Рассмотрим небольшой пример. Выделите произвольный диапазон ячеек

на рабочем листе и выберите команду меню Excel Файл Область печатиЗадать (File Print Area Set Print Area).

Как показано на рис. 7.7, Excel автоматически присваивает выделенному

диапазону ячеек имя Область_печати (Print_Area).

Это одно из зарезервированных имен, значение которого сохраняется межY

ду сеансами работы в Excel (попробуйте сохранить, закрыть, а затем снова отY

крыть рабочую книгу, и вы убедитесь, что имя Область_печати соответствуY

ет все тому же диапазону ячеек).

Page 184: ? Применение VBA и макросов в Microsoft® Excel

184 Часть I Первые шаги

Рис. 7.7. Область_печати — одно из заре&зервированных имен Excel

Внимание Каждый рабочий лист имеет собственную область печати. Назначение новой об&ласти печати переопределяет текущее значение имени Область_печати для дан&ного рабочего листа.

Ниже приведен список зарезервированных имен Excel:

Критерии (Criteria);

База_данных (Database);

Извлечь (Extract);

Область_печати (Print_Area);

Заголовки_для_печати (Print_Titles).

Имена Критерии и Извлечь используются при копировании результата

применения расширенного фильтра в новое место (чтобы применить расY

ширенный фильтр, выберите команду меню Excel Данные ФильтрРасширенный фильтр (Data Filter Advanced Filter)).

Имя База_данных использовалось в предыдущих версиях Excel для обоY

значения данных, которыми манипулировали определенные функции. Сейчас

имя База_данных используется разве что при создании форм ввода данных

(чтобы создать форму ввода данных, выберите команду меню Excel ДанныеФорма (Data Form)).

Имя Область_печати используется при задании области печати (выберите

команду Файл Область печати Задать) или ее изменении посредством

диалогового окна Параметры страницы (Page Setup) (выберите команду

Файл Параметры страницы (File Page Setup)).

Имя Заголовки_для_печати используется при установке заголовков пеY

чати (выберите команду Файл Параметры страницы, перейдите во вкладку

Лист (Sheet) и установите флажок Заголовки строк и столбцов (Row and coY

lumn headings)).

Зарезервированные имена (а также похожие на них) не рекомендуется исY

пользовать при создании собственных имен. Предположим, что вы создали

имя ОбластьПечати и по ошибке написали следующий код:

Worksheets("Лист4").Names("Область_печати").Delete

Page 185: ? Применение VBA и макросов в Microsoft® Excel

Имена Глава 7 185

В результате выполнения приведенного выше кода вместо имени Область-Печати будет удалено зарезервированное имя Excel.

Скрытие именБлагодаря наличию у объекта Name свойства Visible имя можно скрыть.

Чтобы скрыть имя, установите значение свойства Visible равным False;

чтобы вновь сделать имя видимым, установите значение свойства Visibleравным True:

Names.Add Name:="ТоварНомер", RefersTo:="=$A$1", Visible:=False

Внимание Если пользователь создаст имя, совпадающее с существующим скрытым именем,последнее будет переопределено безо всякого предупреждения. Чтобы избежатьэтого, защитите рабочий лист.

Проверка существования имениСледующая функция проверяет существование имени (включая скрытые

имена), за исключением зарезервированных имен Excel:

Function NameExists(FindName As String) As Boolean Dim Rng As Range Dim myName As String On Error Resume Next myName = ActiveWorkbook.Names(FindName).Name If Err.Number = 0 Then NameExists = True Else NameExists = FalseEnd Function

Предыдущий код также является великолепным примером того, как можно

извлечь выгоду из ошибок. Если переданное функции имя не существует, генеY

рируется ошибка, однако благодаря строке On Error Resume Next код проY

должает выполняться как ни в чем не бывало. Определить факт наличия ошибки

поможет свойство Err.Number. Если значение этого свойства равно 0, переY

данное функции имя существует (при выполнении кода не было сгенерировано

ошибки), в противном случае YYYY нет (была сгенерирована ошибка).

Практикум

Использование именованных диапазонов ячеекпри поиске значений в столбце данныхРассмотрим следующую задачу. Каждый день в Excel импортируется файл со све&дениями о продажах товара в сети розничных магазинов. Файл содержит номера

Page 186: ? Применение VBA и макросов в Microsoft® Excel

186 Часть I Первые шаги

магазинов, но не их названия. Необходимо реализовать автоматическое добавле&ние названий магазинов с целью последующего создания отчетов.Типичное решение этой задачи заключается в создании таблицы с названиямивсех магазинов на дополнительном рабочем листе и применении макроса для до&бавления названий магазинов на основном рабочем листе.Всю процедуру можно разбить на 6 этапов.1. Импортирование файла данных.

2. Нахождение всех уникальных номеров магазинов.

3. Проверка, все ли номера магазинов внесены в таблицу соответствия номеров иназваний магазинов.

4. Если необходимо, занести в таблицу соответствия номеров и названий магази&нов сведения о новых магазинах.

5. Переопределить именованный диапазон ячеек так, чтобы он включал в себяобновленную таблицу соответствия номеров и названий магазинов.

6. Добавить названия магазинов на основном рабочем листе.

Представленный далее исходный код макроса реализует приведенную выше по&следовательность действий:Sub ImportData()

Dim WSD As Worksheet Dim WSM As Worksheet Dim WB As Workbook

Set WB = ThisWorkbook' Основной рабочий лист - "Данные". Set WSD = ThisWorkbook.Worksheets("Данные")' Вспомогательный рабочий лист - "Таблица". Set WSM = ThisWorkbook.Worksheets("Таблица")

' Код импорта файла закомментирован.' Предполагается, что данные уже импортированы.' Импортировать файл. ' Workbooks.Open Filename:="C:\Sales.csv"' Скопировать данные и закрыть файл. 'Range("A1").CurrentRegion.Copy Destination:=WSD.Range("A1") 'ActiveWorkbook.Close SaveChanges:=False

' Активизировать рабочий лист с данными.' Составить список уникальных номеров магазинов. WSD.Activate FinalRow = Cells(65536, 1).End(xlUp).Row Range("A1").Resize(FinalRow, 1).AdvancedFilter _Action:=xlFilterCopy, CopyToRange:=Range("Z1"), Unique:=True

' Проверить, все ли номера магазинов находятся в таблице' соответствия номеров и названий магазинов. FinalStore = Range("Z65536").End(xlUp).Row Range("AA1").Value = "В списке?"' В англоязычной версии Excel:' Range("AA2:AA" & FinalStore).FormulaR1C1 = _' "=ISNA(VLOOKUP(RC[-1],СписокМагазинов,1,False))"

Page 187: ? Применение VBA и макросов в Microsoft® Excel

Имена Глава 7 187

Range("AA2:AA" & FinalStore).FormulaR1C1Local = _ "=ЕНД(ВПР(RC[-1];СписокМагазинов;1;ЛОЖЬ))"

' Найти строку для ввода сведений о новом магазине. NextRow = WSM.Range("A65536").End(xlUp).Row + 1

' Добавить сведения о новых магазинах. For i = 2 To FinalStore If Cells(i, 27).Value = True Then ThisStore = Cells(i, 26).Value WSM.Cells(NextRow, 1).Value = ThisStore WSM.Cells(NextRow, 2).Value = InputBox(Prompt:=" _Введите имя магазина " & ThisStore, Title:="Найден новый магазин") NextRow = NextRow + 1 End If Next i

' Удалить вспомогательный список магазинов. Range("Z1:AA" & FinalStore).Clear

' Переопределить имя "СписокМагазинов". FinalStore = WSM.Range("A65536").End(xlUp).Row WSM.Range("A1:B" & FinalStore).Name = "СписокМагазинов"

' Добавить названия магазинов. Range("B1").EntireColumn.Insert Range("B1").Value = "МагазинНазвание"' В англоязычной версии Excel:' Range("B2:B" & FinalRow).FormulaR1C1 = _"=VLOOKUP(RC1,СписокМагазинов,2,False)" Range("B2:B" & FinalRow).FormulaR1C1Local = _"=ВПР(RC1;СписокМагазинов;2;ЛОЖЬ)"

'Заменить формулы значениями. Range("B2:B" & FinalRow).Value = Range("B2:B" &FinalRow).ValueEnd Sub

Следующий шагСледующая глава посвящена событиям YYYY концепции, позволяющей VBA

реагировать на действия пользователя, такие как выделение ячейки, смена теY

кущего активного рабочего листа и т.п.

Page 188: ? Применение VBA и макросов в Microsoft® Excel
Page 189: ? Применение VBA и макросов в Microsoft® Excel

8Использование событий............. 190События рабочей книги...............191События рабочего листа............. 199События листа диаграммы....... 204События приложения................. 208Следующий шаг............................214

Глава 8

Ñîáûòèÿ

События позволяют реагировать

на всевозможные действия, происхоY

дящие в пределах текущего сеанса

работы с Excel.

Различают следующие уровни соY

бытий.

Уровень приложения. ОхватыY

вает действия, имеющие неY

посредственное отношение к

Excel, например Applica-tion_NewWorkbook.

Уровень рабочей книги. ОхваY

тывает действия, имеющие

непосредственное отношение

к рабочей книге, например

Workbook_Open.

Уровень рабочего листа. ОхватыY

вает действия, имеющие непоY

средственное отношение к раY

бочему листу, например Work-sheet_SelectionChange.

Уровень листа диаграммы. ОхY

ватывает действия, имеющие

непосредственное отношение

к листу диаграммы, например

Chart_Activate.

Код обработки событий рабочей

книги размещается в модуле Эта-Книга (ThisWorkbook), код обработY

ки событий рабочего листа YYYY в модуY

ле этого рабочего листа (например,

Лист1), код обработки событий листа

диаграммы и Excel — в соответствуюY

щих модулях классов. При обработке

событий можно вызывать процедуры

и функции из других модулей.

Page 190: ? Применение VBA и макросов в Microsoft® Excel

190 Часть I Первые шаги

Таким образом, нет необходимости дублировать один и тот же код для неY

скольких рабочих листов YYYY его можно поместить в отдельный модуль и вызыY

вать при обработке события каждого листа.

В этой главе рассматриваются события различных уровней и их использоY

вание на практике.

Использование событий Запомнить синтаксис всех событий достаточно сложно. К счастью, редакY

тор Visual Basic позволяет быстро выбрать требуемое событие и добавить код

его обработки в соответствующий модуль.

При выборе модуля ЭтаКнига (ThisWorkbook), модуля листа или модуля

класса соответствующие события становятся доступны посредством расY

крывающихся списков Object (Объект) и Procedure (Процедура), как поY

казано на рис. 8.1.

Рис. 8.1. Редактор Visual Basic позволяет выбрать требуемое событие с помощью раскрываю&щихся списков Object и Procedure

После выбора объекта из раскрывающегося списка Object в раскрывающемY

ся списке Procedure появляются соответствующие этому объекту события. ВыY

бор события приводит к автоматической генерации верхнего (Private Sub) и

нижнего (End Sub) заголовка процедуры, как показано на рис. 8.2.

Рис. 8.2. Редактор Visual Basic автоматически генерирует верхний и нижний заголовок процедуры

Параметры событий

Некоторые события имеют параметры (например, Target и Cancel),

предназначенные для передачи коду обработки события определенной инY

формации. Рассмотрим событие Worksheet_BeforeRightClick, срабатыY

вающее перед выполнением действия, соответствующего щелчку правой

кнопкой мыши в пользовательском интерфейсе Excel. Присвоение параметру

Page 191: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 191

Cancel значения True предотвращает выполнение стандартного действия,

в данном случае YYYY отображения контекстного меню:

Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, _Cancel As Boolean) Cancel = TrueEnd Sub

Запрет обработки событий

Некоторые события могут вызывать другие события, включая самих себя.

Например, событие Worksheet_Change срабатывает при изменении ячейки

на рабочем листе. Если при обработке этого события вновь будет изменена

ячейка, событие сработает снова, что приведет к зацикливанию.

Чтобы избежать описанной выше ситуации, запретите обработку событий

в начале кода процедуры и разрешите ее в конце, как показано ниже:

Private Sub Worksheet_Change(ByVal Target As Range) Application.EnableEvents = False Range("A1").Value = Target.Value Application.EnableEvents = TrueEnd Sub

На заметку Чтобы прервать выполнение макроса, нажмите клавишу <Esc> или воспользуй&тесь комбинацией клавиш <Ctrl+Break>.

События рабочей книги Ниже приведен список событий, существующих на уровне рабочей

книги Excel:

Activate;

Deactivate;

Open;

BeforeSave;

BeforePrint;

BeforeClose;

NewSheet;

SheetActivate;

SheetDeactivate;

SheetCalculate;

SheetBeforeDoubleClick;

SheetSelectionChange;

Page 192: ? Применение VBA и макросов в Microsoft® Excel

192 Часть I Первые шаги

SheetBeforeRightClick;

SheetChange;

WindowResize;

WindowActivate;

WindowDeactivate;

AddinInstall;

AddinUninstall.

Событие Workbook_Activate()

Событие Workbook_Activate срабатывает, когда содержащая это собыY

тие рабочая книга становится активной.

Событие Workbook_Deactivate()

Событие Workbook_Deactivate срабатывает, когда содержащая это соY

бытие рабочая книга перестает быть активной.

Событие Workbook_Open()

Событие Workbook_Open является стандартным событием рабочей книги.

Код его обработки выполняется непосредственно при открытии файла рабочей

книги, перед выводом на экран пользовательского интерфейса. Одним из наиY

более распространенных применений события Workbook_Open является проY

верка имени пользователя и определение его прав на доступ к рабочей книге.

Следующий код проверяет имя пользователя и, если оно не равно

‘‘Администратор’’, защищает рабочий лист от внесения изменений со стороY

ны пользователя (за это отвечает параметр UserInterfaceOnly):

Private Sub Workbook_Open() Dim sht As Worksheet If Application.UserName <> "Администратор" Then For Each sht In Worksheets sht.Protect UserInterfaceOnly:=True Next sht End IfEnd Sub

Событие Workbook_Open можно применять и для создания пользовательY

ских меню или панелей управления. Следующий код создает меню МенюMrExcel с двумя пунктами, как показано на рис. 8.3.

См. также Более подробно создание пользовательского меню рассматривается в разделе“Создание пользовательского меню” главы 24 на с. 575.

Page 193: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 193

Private Sub Workbook_Open() Dim cbWSMenuBar As CommandBar Dim Ctrl As CommandBarControl, muCustom As CommandBarControl Dim iHelpIndex As Integer Dim sht As Worksheet

' Инициализация событий приложения и листа диаграммы. InitializeAppEvent InitializeChart

CreateToolbar

Set cbWSMenuBar = Application.CommandBars("Worksheet menu bar") iHelpIndex = cbWSMenuBar.Controls("Справка").Index Set muCustom = cbWSMenuBar.Controls.Add(Type:=msoControlPopup, _Before:=iHelpIndex, Temporary:=True) For Each Ctrl In cbWSMenuBar.Controls If Ctrl.Caption = "Меню &MrExcel" Then cbWSMenuBar.Controls("Меню MrExcel").Delete End If Next Ctrl With muCustom .Caption = "Меню &MrExcel" With .Controls.Add(Type:=msoControlButton) .Caption = "&Импорт" .OnAction = "Import" End With With .Controls.Add(Type:=msoControlButton) .Caption = "&Экспорт" .OnAction = "Export" End With End WithEnd Sub

Рис. 8.3. Событие Workbook_Open можно применять для создания пользова&тельского меню

Событие Workbook_BeforeSave(ByVal SaveAsUI As Boolean,Cancel As Boolean)

Событие Workbook_BeforeSave срабатывает при попытке сохранения

рабочей книги. Чтобы отобразить диалоговое окно Сохранение документа(Save As), установите значение параметра SaveAsUI равным True. Чтобы заY

претить сохранение рабочей книги, установите равным True значение параY

метра Cancel.

Событие Workbook_BeforePrint(Cancel As Boolean)

Событие Workbook_BeforePrint срабатывает при попытке печати раY

бочей книги (способ инициирования процесса печати YYYY с помощью команды

меню, кнопки панели инструментов, комбинации клавиш или программного

Page 194: ? Применение VBA и макросов в Microsoft® Excel

194 Часть I Первые шаги

кода YYYY не играет роли). Чтобы запретить печать, установите значение параY

метра Cancel равным True.

Приведенный ниже код отслеживает попытки печати рабочего листа, заноY

ся в журнал дату и время печати, имя пользователя и имя рабочего листа

(рис. 8.4):

Private Sub Workbook_BeforePrint(Cancel As Boolean) Dim LastRow As Long Dim PrintLog As Worksheet

Set PrintLog = Worksheets("PrintLog") LastRow = PrintLog.Range("A65536").End(xlUp).Row + 1 With PrintLog .Cells(LastRow, 1).Value = Now() .Cells(LastRow, 2).Value = Application.UserName .Cells(LastRow, 3).Value = ActiveSheet.Name End WithEnd Sub

Рис. 8.4. Событие Workbook_BeforePrint можно ис&пользовать для ведения журнала печати

Событие Workbook_BeforePrint можно использовать для создания

верхнего и нижнего колонтитула печатаемой страницы. Несмотря на то, что

теперь это можно сделать с помощью диалогового окна Параметры страницы(Page Setup), раньше подобная возможность реализовывалась только с помоY

щью программного кода:

Private Sub Workbook_BeforePrint(Cancel As Boolean) ActiveSheet.PageSetup.RightFooter = ActiveWorkbook.FullNameEnd Sub

Событие Workbook_BeforeClose(Cancel As Boolean)

Событие Workbook_BeforeClose срабатывает при попытке закрыть раY

бочую книгу. Чтобы сделать закрытие рабочей книги невозможным, устаноY

вите значение параметра Cancel равным True.

Событие Workbook_BeforeClose можно применить для удаления польY

зовательского меню:

Private Sub Workbook_BeforeClose(Cancel As Boolean) Dim cbWSMenuBar As CommandBar On Error Resume Next Set cbWSMenuBar = Application.CommandBars("Worksheet menu bar") cbWSMenuBar.Controls("Меню MrExcel").DeleteEnd Sub

Приведенный выше код имеет один недостаток. Если в рабочую книгу быY

ли внесены изменения, Excel предложит сохранить их, отобразив соответстY

Page 195: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 195

вующее диалоговое окно после выполнения кода обработки события Work-book_BeforeClose. Если вы передумаете закрывать книгу и щелкните на

кнопке Отмена (Cancel), то уже не сможете вернуть удаленное меню.

Решение этой проблемы заключается в выводе на экран собственного диаY

логового окна сохранения рабочей книги:

Private Sub Workbook_BeforeClose(Cancel As Boolean) Dim Msg As String Dim Response Dim cbWSMenuBar As CommandBar

If Not ThisWorkbook.Saved Then Msg = "Сохранить изменения, внесенные в " & Me.Name & "?" Response = MsgBox(Msg, vbQuestion + vbYesNoCancel)

Select Case Response Case vbYes ThisWorkbook.Save Case vbNo ThisWorkbook.Saved = True Case vbCancel Cancel = True Exit Sub End Select End If

Set myAppEvent = Nothing Set myClassModule = Nothing

On Error Resume Next Set cbWSMenuBar = Application.CommandBars("Worksheet menu bar") cbWSMenuBar.Controls("Меню MrExcel").DeleteEnd Sub

Событие Workbook_NewSheet(ByVal Sh As Object)

Событие Workbook_NewSheet срабатывает при добавлении в текущую

активную рабочую книгу нового листа. Sh — это объект нового рабочего листа

или листа диаграммы.

Событие Workbook_WindowResize(ByVal Wn As Window)

Событие Workbook_WindowResize срабатывает при изменении размера

окна текущей активной рабочей книги. Wn — это объект окна.

На заметку Событие Workbook_WindowResize срабатывает только при изменении размераокна текущей активной рабочей книги. Изменение размера окна Excel является со&бытием уровня приложения и не имеет никакого отношения к событиям уровнярабочей книги.

Page 196: ? Применение VBA и макросов в Microsoft® Excel

196 Часть I Первые шаги

Следующий код делает невозможным изменение размера окна текущей акY

тивной рабочей книги:

Private Sub Workbook_WindowResize(ByVal Wn As Window) Wn.EnableResize = FalseEnd Sub

Внимание Запрет изменения размера окна рабочей книги приводит к удалению кнопок окнаСвернуть (Minimize) и Развернуть (Maximize). Чтобы вернуть кнопки на место,выполните в окне Immediate (Быстрое выполнение) строку ActiveWin-dow.EnableResize = True.

Событие Workbook_WindowActivate(ByVal Wn As Window)

Событие Workbook_WindowActivate срабатывает при активизации окY

на любой рабочей книги. Wn — это объект окна.

На заметку Событие Workbook_WindowActivate срабатывает только при активизации окнарабочей книги.

Событие Workbook_WindowDeactivate(ByValWn As Window)

Событие Workbook_WindowDeactivate срабатывает при деактивизации

окна любой рабочей книги. Wn — это объект окна.

На заметку Событие Workbook_WindowDeactivate срабатывает только при деактивизацииокна рабочей книги.

Событие Workbook_AddinInstall()

Событие Workbook_AddinInstall срабатывает при установке рабочей

книги в качестве надстройки (чтобы установить надстройку, выберите команY

ду меню Excel Сервис Надстройки (Tools AddYIns)). Обратите внимание,

что событие Workbook_AddinInstall не срабатывает при двойном щелчке

на значке файла надстройки (файл с расширением .xla).

Событие Workbook_AddinUninstall()

Событие Workbook_AddinUninstall срабатывает при удалении рабочей

книги, используемой в качестве надстройки. Обратите внимание, что надY

стройка не закрывается автоматически.

Page 197: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 197

Событие Workbook_SheetActivate(ByVal Sh As Object)

Событие Workbook_SheetActivate срабатывает при активизации люY

бого рабочего листа или листа диаграммы в рабочей книге. Sh — это объект

активного листа.

Кроме того, активизация рабочего листа или листа диаграммы приводит к

срабатыванию событий активного рабочего листа (Worksheet_Activate)

или листа диаграммы (Chart_Activate).

Событие Workbook_SheetBeforeDoubleClick(ByVal Sh AsObject, ByVal Target As Range, Cancel As Boolean)

Событие Workbook_SheetBeforeDoubleClick срабатывает при выY

полнении двойного щелчка на рабочем листе или листе диаграммы текущей

активной рабочей книги. Sh — это объект активного рабочего листа или листа

диаграммы, а Target — объект, на котором был выполнен двойной щелчок.

Чтобы запретить стандартное действие, предпринимаемое при обработке

двойного щелчка, установите значение параметра Cancel равным True.

Кроме того, двойной щелчок на рабочем листе или листе диаграммы приводит

к срабатыванию событий активного рабочего листа (Worksheet_Before-DoubleClick) или листа диаграммы (Chart_BeforeDoubleClick).

Событие Workbook_SheetBeforeRightClick(ByVal Sh AsObject, ByVal Target As Range, Cancel As Boolean)

Событие Workbook_SheetBeforeRightClick срабатывает при выполY

нении щелчка правой кнопкой мыши на рабочем листе или листе диаграммы

текущей активной рабочей книги. Sh — это объект активного рабочего листа

или листа диаграммы, а Target — объект, на котором был выполнен щелчок

правой кнопкой мыши. Чтобы запретить стандартное действие, предприниY

маемое при обработке щелчка правой кнопкой мыши, установите значение

параметра Cancel равным True.

Кроме того, щелчок правой кнопкой мыши на рабочем листе или листе

диаграммы приводит к срабатыванию событий активного рабочего листа

(Worksheet_BeforeRightClick) или листа диаграммы (Chart_Before-RightClick).

Событие Workbook_SheetCalculate(ByVal Sh As Object)

Событие Workbook_SheetCalculate срабатывает при пересчете рабоY

чего листа или обновлении листа диаграммы. Sh — это объект активного раY

бочего листа или листа диаграммы.

Page 198: ? Применение VBA и макросов в Microsoft® Excel

198 Часть I Первые шаги

Кроме того, пересчет рабочего листа или обновление листа диаграммы

приводит к срабатыванию событий активного рабочего листа (Worksheet_Calculate) или листа диаграммы (Chart_Calculate).

Событие Workbook_SheetChange(ByVal Sh As Object, ByValTarget As Range)

Событие Workbook_SheetChange срабатывает при изменении любого

диапазона ячеек на рабочем листе. Sh — это объект рабочего листа, Target —

объект измененного диапазона ячеек.

Кроме того, изменение диапазона ячеек рабочего листа приводит к срабаY

тыванию события конкретного рабочего листа (Worksheet_Change).

Событие Workbook_SheetDeactivate(ByVal Sh As Object)

Событие Workbook_SheetDeactivate срабатывает при деактивизации

любого рабочего листа или листа диаграммы в текущей активной рабочей

книге. Sh — это объект рабочего листа или листа диаграммы, который был деY

активизирован.

Кроме того, деактивизация рабочего листа или листа диаграммы приводит к

срабатыванию событий конкретного рабочего листа (Worksheet_Deactivate)

или листа диаграммы (Chart_Deactivate).

Событие Workbook_SheetFollowHyperlink(ByVal Sh AsObject, ByVal Target As Hyperlink)

Событие Workbook_SheetFollowHyperlink срабатывает при щелчке

на гиперссылке, расположенной на любом рабочем листе активной рабочей

книги. Sh — это объект активного рабочего листа, Target — объект гиперY

ссылки.

Кроме того, щелчок на гиперссылке, расположенной на рабочем листе,

приводит к срабатыванию события активного рабочего листа (Worksheet_FollowHyperlink).

Событие Workbook_SheetSelectionChange(ByVal Sh AsObject, ByVal Target As Range)

Событие Workbook_SheetSelectionChange срабатывает при выделеY

нии нового диапазона ячеек на любом рабочем листе активной рабочей книги.

Sh — это объект активного рабочего листа, Target — объект выделенного

диапазона ячеек.

Кроме того, выделение нового диапазона ячеек приводит к срабатыванию

события активного рабочего листа (Worksheet_SelectionChange).

Page 199: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 199

События рабочего листа Ниже приведен список событий, существующих на уровне рабочего

листа Excel:

Activate;

BeforeDoubleClick;

BeforeRightClick;

Calculate;

Change;

Deactivate;

FollowHyperlink;

SelectionChange.

Событие Worksheet_Activate()

Событие Worksheet_Activate срабатывает при активизации соответстY

вующего этому событию рабочего листа. Примером использования события

Worksheet_Activate является создание плавающей панели инструментов:

Private Sub Worksheet_Activate() On Error Resume Next Application.CommandBars("Панель инструментов _MrExcel").Visible = TrueEnd Sub

Событие Worksheet_Deactivate()

Событие Worksheet_Deactivate срабатывает при деактивизации соотY

ветствующего этому событию рабочего листа:

Private Sub Worksheet_Deactivate() On Error Resume Next Application.CommandBars("Панель инструментов _MrExcel").Visible = FalseEnd Sub

На заметку При переключении между рабочими листами первым срабатывает событие Work-sheet_Deactivate исходного рабочего листа, и только затем — событие Work-sheet_Activate активизированного рабочего листа.

Событие Worksheet_BeforeDoubleClick(ByVal TargetAs Range, Cancel As Boolean)

Событие Worksheet_BeforeDoubleClick срабатывает в результате

двойного щелчка на соответствующем этому событию рабочем листе. Tar-

Page 200: ? Применение VBA и макросов в Microsoft® Excel

200 Часть I Первые шаги

get — это объект выделенного диапазона ячеек. По умолчанию параметр

Cancel имеет значение False. Присвоение этому параметру значения Trueприведет к отмене стандартного действия, предпринимаемого при обработке

двойного щелчка (в данном случае YYYY переход в режим изменения содержиY

мого ячейки).

Следующий код делает невозможным переход в режим изменения содерY

жимого ячейки путем двойного щелчка на ней:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, _Cancel As Boolean) Cancel = TrueEnd Sub

На заметку Приведенный выше код не запрещает применять двойной щелчок для изменениявысоты строки и ширины столбца.

Запретив использование двойного щелчка для перехода в режим изменеY

ния содержимого ячейки, ему можно найти другое применение. Выполнение

следующего кода приведет к смене цвета заливки ячейки:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, _Cancel As Boolean) Target.Interior.ColorIndex = 3End Sub

Событие Worksheet_BeforeRightClick(ByVal Target AsRange, Cancel As Boolean)

Событие Worksheet_BeforeRightClick срабатывает при щелчке праY

вой кнопкой мыши на рабочем листе. Target — это объект, на котором

щелкнули правой кнопкой мыши. Установка значения параметра Cancelравным True запрещает выполнение стандартного действия, предпринимаеY

мого при обработке щелчка правой кнопкой мыши.

Событие Worksheet_Calculate()

Событие Worksheet_Calculate срабатывает при пересчете рабочего

листа.

Рассмотрим небольшой пример. Если прибыль, полученная за определенY

ный месяц текущего года, превысила прибыль, полученную за аналогичный

период в прошлом году, под названием месяца выводится зеленая стрелка,

указывающая вверх; в противном случае выводится красная стрелка, указыY

вающая вниз, как показано на рис. 8.5:

Private Sub Worksheet_Calculate() Select Case Range("C3").Value Case Is > Range("C4").Value SetArrow 10, msoShapeDownArrow Case Is < Range("C4").Value

Page 201: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 201

SetArrow 3, msoShapeUpArrow End SelectEnd Sub

Private Sub SetArrow(ByVal ArrowColor As Integer, ByVal ArrowDegree)' Удалить все существующие фигуры. For Each Sh In ActiveSheet.Shapes If Left(Sh.Name, 4) = "Auto" Then Sh.Delete End If Next Sh ActiveSheet.Shapes.AddShape(ArrowDegree, 17.25, _43.5, 5, 10).Select With Selection.ShapeRange With .Fill .Visible = msoTrue .Solid .ForeColor.SchemeColor = ArrowColor .Transparency = 0# End With With .Line .Weight = 0.75 .DashStyle = msoLineSolid .Style = msoLineSingle .Transparency = 0# .Visible = msoTrue .ForeColor.SchemeColor = 64 .BackColor.RGB = RGB(255, 255, 255) End With End With Range("A3").SelectEnd Sub

Рис. 8.5. Пример использования события Work-sheet_Calculate для добавления на рабочийлист фигуры

Page 202: ? Применение VBA и макросов в Microsoft® Excel

202 Часть I Первые шаги

Событие Worksheet_Change(ByVal Target As Range)

Событие Worksheet_Change срабатывает при изменении содержимого

ячейки, например, при вводе, редактировании или удалении текста. Tar-get — это объект ячейки, содержимое которой было изменено.

На заметку Событие Worksheet_Change срабатывает также при вставке значения в ячейку,однако оно не срабатывает при пересчете ячейки. При пересчете ячейки срабаты&вает событие Worksheet_Calculate.

Практикум

Рассмотрим задачу введения времени отправки и прибытия авиарейсов в 24&часовом формате (например, 23:45). Ее можно упростить, поручив Excel вводсимвола двоеточия. Вот как это сделать с помощью события Worksheet_Change: Private Sub Worksheet_Change(ByVal Target As Range) Dim ThisColumn As Integer Dim UserInput As String, NewInput As String

ThisColumn = Target.Column If ThisColumn < 3 Then UserInput = Target.Value If IsNumeric(UserInput) Then If UserInput > 1 Then NewInput = Left(UserInput, Len(UserInput) - 2) _& ":" & Right(UserInput, 2) Application.EnableEvents = False Target = NewInput Application.EnableEvents = True End If End If End If

End Sub

Приведенный выше код будет автоматически преобразовывать числа, введенныев ячейки столбцов A и B рабочего листа (If ThisColumn < 3), во время в 24&часовом формате (например, 2345 в 23:45).

Внимание Чтобы избежать зацикливания в результате изменения содержимогоячейки, запретите обработку событий с помощью строки Applicati-on.EnableEvents = False.

Page 203: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 203

Событие Worksheet_SelectionChange(ByValTarget As Range)

Событие Worksheet_SelectionChange срабатывает при выделении ноY

вого диапазона ячеек. Target — это объект выделенного диапазона ячеек.

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

и строки, на пересечении которых находится выделенная ячейка:

Private Sub Worksheet_SelectionChange(ByVal Target As Range) Dim iColor As Integer

On Error Resume Next iColor = Target.Interior.ColorIndex If iColor < 0 Then iColor = 36 Else iColor = iColor + 1 End If If iColor = Target.Font.ColorIndex Then iColor = iColor + 1 Cells.FormatConditions.Delete With Range("A" & Target.Row, Target.Address)' В англоязычной версии Excel:' .FormatConditions.Add Type:=2, Formula1:="TRUE" .FormatConditions.Add Type:=2, Formula1:="ИСТИНА" .FormatConditions(1).Interior.ColorIndex = iColor End With With Range(Target.Offset(1 - Target.Row, 0).Address & ":" & _Target.Offset(-1, 0).Address)' В англоязычной версии Excel:' .FormatConditions.Add Type:=2, Formula1:="TRUE" .FormatConditions.Add Type:=2, Formula1:="ИСТИНА" .FormatConditions(1).Interior.ColorIndex = iColor End WithEnd Sub

Внимание Указанный код обработки события Worksheet_SelectionChange отменяет лю&бое условное форматирование, заданное на рабочем листе. Кроме того, он можеточистить буфер обмена, затрудняя тем самым выполнение операций копированияи вставки в пределах данного рабочего листа.

Событие Worksheet_FollowHyperlink(ByVal TargetAs Hyperlink)

Событие Worksheet_FollowHyperlink срабатывает при щелчке на гиY

перссылке. Target — это объект гиперссылки.

Page 204: ? Применение VBA и макросов в Microsoft® Excel

204 Часть I Первые шаги

События листа диаграммы События листа диаграммы срабатывают при изменении или активизации

диаграммы. Для доступа к событиям встроенных диаграмм используются моY

дули классов.

См. также Более подробно модули классов рассматриваются в главе 20, “Создание пользо&вательских объектов, типов и коллекций”.

Ниже приведен список событий, существующих на уровне листа диаграмY

мы Excel:

Activate;

BeforeDoubleClick;

BeforeRightClick;

Calculate;

Deactivate;

DragOver;

DragPlot;

MouseDown;

MouseMove;

MouseUp;

Resize;

Select;

SeriesChange.

Встроенные диаграммы

Поскольку встроенные диаграммы не имеют отдельного листа, для доступа

к их событиям необходимо использовать модуль класса.

1. Добавьте к проекту модуль класса.

2. Переименуйте его в cl_ChartEvents.

3. Разместите в модуле класса следующую строку кода:

Public WithEvents myChartClass As Excel.Chart

Это сделает события встроенной диаграммы доступными через модуль

класса, как показано на рис. 8.6.

4. Добавьте к проекту стандартный модуль.

5. Разместите в стандартном модуле следующие строки кода:

Page 205: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 205

Dim myClassModule As New cl_ChartEventsSub InitializeChart() Set myClassModule.myChartClass = _Worksheets(1).ChartObjects(1).ChartEnd Sub

Рис. 8.6. События встроенной диаграммы доступны посредством модуля класса

Тем самым вы сделаете объект встроенной диаграммы доступным как

обычный объект диаграммы. Процедуру InitializeChart необходиY

мо выполнить один раз при открытии рабочей книги (воспользуйтесь

событием Workbook_Open).

Внимание Первая часть имени события встроенной диаграммы будет совпадать с именемобъекта диаграммы, заданном в модуле класса (в данном случае — myChart-Class).

Событие Chart_Activate()

Событие Chart_Activate срабатывает при активизации листа диаграммы.

Событие Chart_BeforeDoubleClick(ByVal ElementID As Long,ByVal Arg1 As Long, ByVal Arg2 As Long, Cancel As Boolean)

Событие Chart_BeforeDoubleClick срабатывает в результате двойного

щелчка на любом элементе диаграммы. ElementID — это объект, представY

ляющий элемент диаграммы, на котором был сделан двойной щелчок

(например, легенду). Параметры Arg1 и Arg2 зависят от значения параметра

ElementID. Чтобы запретить выполнение стандартного действия, предприY

нимаемого при обработке двойного щелчка, установите значение параметра

Cancel равным True.

Согласно приведенному ниже коду, двойной щелчок на легенде диаграммы

приводит к скрытию легенды. Чтобы вернуть легенду на место, дважды щелкY

ните на области диаграммы.

Private Sub myChartClass_BeforeDoubleClick(ByVal ElementID As _Long, ByVal Arg1 As Long, ByVal Arg2 As Long, Cancel As Boolean) Select Case ElementID

Page 206: ? Применение VBA и макросов в Microsoft® Excel

206 Часть I Первые шаги

Case xlLegend myChartClass.HasLegend = False Cancel = True Case xlChartArea myChartClass.HasLegend = True Cancel = True End SelectEnd Sub

Событие Chart_BeforeRightClick(Cancel As Boolean)

Событие Chart_BeforeRightClick срабатывает в результате щелчка на

диаграмме правой кнопкой мыши. Чтобы запретить выполнение стандартного

действия, предпринимаемого при обработке щелчка правой кнопкой мыши,

установите значение параметра Cancel равным True.

Событие Chart_Calculate()

Событие Chart_Calculate срабатывает при изменении исходных данY

ных диаграммы.

Событие Chart_Deactivate()

Событие Chart_Deactivate срабатывает при деактивизации листа диаY

граммы.

Событие Chart_DragOver()

Событие Chart_DragOver срабатывает при перетаскивании диапазона

ячеек на диаграмму.

Событие Chart_DragPlot()

Событие Chart_DragPlot срабатывает в результате перетаскивания с поY

следующим опусканием диапазона ячеек на диаграмму.

Событие Chart_MouseDown(ByVal Button As Long, ByValShift As Long, ByVal x As Long, ByVal y As Long)

Событие Chart_MouseDown срабатывает в результате нажатия любой кнопки

мыши при условии, что указатель мыши находится над диаграммой. Параметр

Button определяет кнопку мыши, которая была нажата; параметр Shift — были

ли нажаты при этом кнопки <Shift>, <Ctrl> и <Alt>; параметр x — координату

указателя мыши по горизонтали; параметр y — координату указателя мыши

по вертикали.

Рассмотрим пример. При щелчке на диаграмме левой кнопкой мыши знаY

чения по оси Y сместятся на 50 единиц вверх, а при щелчке правой кнопкой

мыши YYYY на 50 единиц вниз. Для запрета выполнения стандартного действия,

Page 207: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 207

предпринимаемого при обработке щелчка правой кнопкой мыши (в данном

случае YYYY отображения контекстного меню) используется параметр Cancelсобытия Chart_BeforeRightClick.

Private Sub myChartClass_MouseDown(ByVal Button As Long, ByVal _Shift As Long, ByVal x As Long, ByVal y As Long) If Button = 1 Then ActiveChart.Axes(xlValue).MaximumScale = _ ActiveChart.Axes(xlValue).MaximumScale - 50 End If If Button = 2 Then ActiveChart.Axes(xlValue).MaximumScale = _ ActiveChart.Axes(xlValue).MaximumScale + 50 End IfEnd Sub

Событие Chart_MouseMove(ByVal Button As Long,ByVal Shift As Long, ByVal x As Long, ByVal y As Long)

Событие Chart_MouseMove срабатывает при перемещении указателя

мыши над диаграммой. Параметр Button определяет кнопку мыши, которая

могла быть при этом нажата; параметр Shift — были ли нажаты кнопки

<Shift>, <Ctrl> и <Alt>; параметр x — координату указателя мыши по гориY

зонтали; параметр y — координату указателя мыши по вертикали.

Событие Chart_MouseUp(ByVal Button As Long, ByVal ShiftAs Long, ByVal x As Long, ByVal y As Long)

Событие Chart_MouseUp срабатывает в результате отпускания нажатой

кнопки мыши при условии, что указатель мыши находится над диаграммой.

Параметр Button определяет кнопку мыши, которая была нажата, а затем отY

пущена; параметр Shift — были ли нажаты при этом кнопки <Shift>, <Ctrl> и

<Alt>; параметр x — координату указателя мыши по горизонтали; параметр y —

координату указателя мыши по вертикали.

Событие Chart_Resize()

Событие Chart_Resize срабатывает при изменении размера диаграммы.

Если диаграмма находится на отдельном листе, событие Chart_Resize сраY

батывает при условии установки параметра Вид По размеру окна (View

Sized with Window) в главном меню Excel.

Событие Chart_Select(ByVal ElementID As Long, ByValArg1 As Long, ByVal Arg2 As Long)

Событие Chart_Select срабатывает при выделении элемента диаграмY

мы. ElementID — это объект, представляющий выделенный элемент диаY

Page 208: ? Применение VBA и макросов в Microsoft® Excel

208 Часть I Первые шаги

граммы (например, легенда). Параметры Arg1 и Arg2 зависят от значения

параметра ElementID.

В соответствии со следующим кодом выделение элемента диаграммы приY

водит к выделению соответствующего этому элементу набора данных:

Private Sub myChartClass_Select(ByVal ElementID As Long, _ByVal Arg1 As Long, ByVal Arg2 As Long)

If Arg1 = 0 Then Exit Sub

Sheets("Встроенная диаграмма").Cells.Interior.ColorIndex = xlNone

If ElementID = 3 Then If Arg2 = -1 Then' Выделить всю последовательность данных. Sheets("Встроенная диаграмма").Range("A2:A22").Offset(0, _Arg1).Interior.ColorIndex = 19 Else' Выделить значение, соответствующее указанному маркеру. Sheets("Встроенная диаграмма").Range("A1").Offset(Arg2, _Arg1).Interior.ColorIndex = 19 End If End IfEnd Sub

Событие Chart_SeriesChange(ByVal SeriesIndex As Long,ByVal PointIndex As Long)

Событие Chart_SeriesChange срабатывает при обновлении ряда данY

ных на диаграмме. SeriesIndex — это смещение в коллекции Seriesобновленного ряда данных, PointIndex — смещение в коллекции Pointsобновленной точки данных.

События приложенияСобытия приложения охватывают все рабочие книги, открытые в рамках

текущего сеанса работы с Excel. Для доступа к событиям приложения необхоY

димо использовать модуль класса (в этом смысле события приложения имеют

много общего с событиями встроенной диаграммы).

1. Добавьте к проекту модуль класса.

2. Переименуйте его в cl_AppEvents.

3. Разместите в модуле класса следующую строку кода:

Public WithEvents AppEvent As Application

Это сделает события приложения доступными через модуль класса, как

показано на рис. 8.7.

4. Добавьте к проекту стандартный модуль.

Page 209: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 209

Рис. 8.7. События приложения доступны посредством модуля класса

5. Разместите в стандартном модуле следующие строки кода:

Dim myAppEvent As New cl_AppEventsSub InitializeAppEvent() Set myAppEvent.AppEvent = ApplicationEnd Sub

Приведенный выше код делает объект AppEvent доступным как объект

приложения. Процедуру InitializeAppEvent необходимо выполY

нить один раз при открытии рабочей книги (воспользуйтесь событием

Workbook_Open).

Внимание Первая часть имени события приложения будет совпадать с именем объекта при&ложения, заданном в модуле класса (в данном случае — AppEvent).

Ниже приведен список событий, существующих на уровне приложения Excel:

NewWorkbook;

SheetActivate;

SheetBeforeDoubleClick;

SheetBeforeRightClick;

SheetCalculate;

SheetChange;

SheetDeactivate;

SheetFollowHyperlink;

SheetSelectionChange;

WindowActivate;

WindowDeactivate;

WindowResize;

WorkbookActivate;

Page 210: ? Применение VBA и макросов в Microsoft® Excel

210 Часть I Первые шаги

WorkbookAddinInstall;

WorkbookAddinUninstall;

WorkbookBeforeClose;

WorkbookBeforePrint;

WorkbookBeforeSave;

WorkbookDeactivate;

WorkbookNewSheet;

WorkbookOpen.

Событие AppEvent_NewWorkbook(ByVal Wb As Workbook)

Событие AppEvent_NewWorkbook срабатывает при создании новой рабоY

чей книги. Wb — это объект созданной рабочей книги. Следующий код упоряY

дочивает на экране окна открытых рабочих книг:

Private Sub AppEvent_NewWorkbook(ByVal Wb As Workbook) Application.Windows.Arrange xlArrangeStyleTiledEnd Sub

Событие AppEvent_SheetActivate(ByVal Sh As Object)

Событие AppEvent_SheetActivate срабатывает при активизации люY

бого рабочего листа или листа диаграммы. Sh — это объект активизированY

ного рабочего листа или листа диаграммы.

Событие AppEvent_SheetBeforeDoubleClick(ByVal ShAs Object, ByVal Target As Range, Cancel As Boolean)

Событие AppEvent_SheetBeforeDoubleClick срабатывает в результаY

те двойного щелчка на любом рабочем листе. Sh — это объект активного рабоY

чего листа, Target — объект выделенного диапазона ячеек. Чтобы запретить

выполнение стандартного действия, предпринимаемого при обработке двойY

ного щелчка, установите значение параметра Cancel равным True (по умолY

чанию значение параметра Cancel равно False).

Событие AppEvent_SheetBeforeRightClick(ByVal ShAs Object, ByVal Target As Range, Cancel As Boolean)

Событие AppEvent_SheetBeforeRightClick срабатывает в результате

щелчка правой кнопкой мыши на любом рабочем листе. Sh — это объект акY

тивного рабочего листа, Target — объект, на котором был выполнен щелчок

правой кнопкой мыши. Чтобы запретить выполнение стандартного действия,

предпринимаемого при обработке щелчка правой кнопкой мыши, установите

значение параметра Cancel равным True.

Page 211: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 211

Событие AppEvent_SheetCalculate(ByVal Sh As Object)

Событие AppEvent_SheetCalculate срабатывает при пересчете любого

рабочего листа или изменении данных любой диаграммы. Sh — это объект акY

тивного листа.

Событие AppEvent_SheetChange(ByVal Sh As Object,ByVal Target As Range)

Событие AppEvent_SheetChange срабатывает при изменении содержиY

мого любой ячейки. Sh — это объект рабочего листа, Target — объект измеY

ненного диапазона ячеек.

Событие AppEvent_SheetDeactivate(ByVal Sh As Object)

Событие AppEvent_SheetDeactivate срабатывает при деактивизации

любого рабочего листа или листа диаграммы. Sh — это объект деактивизироY

ванного листа.

Событие AppEvent_SheetFollowHyperlink(ByVal ShAs Object, ByVal Target As Hyperlink)

Событие AppEvent_SheetFollowHyperlink срабатывает при щелчке

на любой гиперссылке. Sh — это объект активного рабочего листа, Target —

объект гиперссылки.

Событие AppEvent_SheetSelectionChange(ByVal ShAs Object, ByVal Target As Range)

Событие AppEvent_SheetSelectionChange срабатывает при выделеY

нии нового диапазона ячеек на любом листе. Sh — это объект активного лисY

та, Target — объект выделенного диапазона ячеек.

Событие AppEvent_WindowActivate(ByVal WbAs Workbook, ByVal Wn As Window)

Событие AppEvent_WindowActivate срабатывает при активизации окY

на любой рабочей книги. Wb — это объект рабочей книги, отображаемой в акY

тивизированном окне, Wn — объект окна.

Событие AppEvent_WindowDeactivate(ByVal WbAs Workbook, ByVal Wn As Window)

Событие AppEvent_WindowDeactivate срабатывает при деактивизации

окна любой рабочей книги. Wb — это объект рабочей книги, отображаемой в

деактивизированном окне, Wn — объект окна.

Page 212: ? Применение VBA и макросов в Microsoft® Excel

212 Часть I Первые шаги

Событие AppEvent_WindowResize(ByVal Wb As Workbook,ByVal Wn As Window)

Событие AppEvent_WindowResize срабатывает при изменении размеров

окна активной рабочей книги. Wb — это объект активной рабочей книги, Wn —

объект окна.

Внимание Запрет изменения размера окна рабочей книги (EnableResize = False) при&водит к удалению кнопок окна Свернуть (Minimize) и Развернуть (Maximize). Что&бы вернуть кнопки на место, выполните в окне Immediate (Быстрое выполнение)строку ActiveWindow.EnableResize = True.

Событие AppEvent_WorkbookActivate(ByVal WbAs Workbook)

Событие AppEvent_WorkbookActivate срабатывает при активизации

любой рабочей книги. Wb — это объект активизированной рабочей книги.

Следующий код указывает на необходимость развернуть окно рабочей книги

при ее активизации:

Private Sub AppEvent_WorkbookActivate(ByVal Wb As Workbook) Wb.WindowState = xlMaximizedEnd Sub

Событие AppEvent_WorkbookAddinInstall(ByVal WbAs Workbook)

Событие AppEvent_WorkbookAddinInstall срабатывает при установке

рабочей книги в качестве надстройки (чтобы установить надстройку, выбериY

те команду меню Excel Сервис Надстройки (Tools AddYIns)). Обратите

внимание, что событие AppEvent_WorkbookAddinInstall не срабатывает

при двойном щелчке на значке файла надстройки (файл с расширением

.xla). Wb — это объект рабочей книги, установленной в качестве надстройки.

Событие AppEvent_WorkbookAddinUninstall(ByVal WbAs Workbook)

Событие AppEvent_WorkbookAddinUninstall срабатывает при удалеY

нии рабочей книги, используемой в качестве надстройки. Обратите внимание,

что надстройка не закрывается автоматически. Wb YYYY это объект удаляемой

рабочей книги, использовавшейся в качестве надстройки.

Page 213: ? Применение VBA и макросов в Microsoft® Excel

События Глава 8 213

Событие AppEvent_WorkbookBeforeClose(ByVal Wb AsWorkbook, Cancel As Boolean)

Событие AppEvent_WorkbookBeforeClose срабатывает при закрытии

рабочей книги. Wb — это объект рабочей книги. Чтобы запретить закрытие раY

бочей книги, установите значение параметра Cancel равным True.

Событие AppEvent_WorkbookBeforePrint(ByVal Wb AsWorkbook, Cancel As Boolean)

Событие AppEvent_WorkbookBeforePrint срабатывает при попытке

печати рабочей книги (способ инициирования процесса печати YYYY с помощью

команды меню, кнопки панели инструментов, комбинации клавиш или проY

граммного кода YYYY не играет роли). Wb — это объект рабочей книги. Чтобы заY

претить печать, установите значение параметра Cancel равным True.

Следующий код помещает имя пользователя в нижний колонтитул печаY

таемых страниц:

Private Sub AppEvent_WorkbookBeforePrint(ByVal Wb As Workbook, _Cancel As Boolean) Wb.ActiveSheet.PageSetup.LeftFooter = Application.UserNameEnd Sub

Событие AppEvent_WorkbookBeforeSave(ByVal Wb AsWorkbook, ByVal SaveAsUI As Boolean, Cancel As Boolean)

Событие AppEvent_WorkbookBeforeSave срабатывает при попытке соY

хранения рабочей книги. Wb — это объект рабочей книги. Чтобы отобразить

диалоговое окно Сохранение документа (Save As), установите значение параY

метра SaveAsUI равным True. Чтобы запретить сохранение рабочей книги,

установите значение параметра Cancel равным True.

Событие AppEvent_WorkbookDeactivate(ByVal Wb AsWorkbook)

Событие AppEvent_WorkbookDeactivate срабатывает при деактивизаY

ции любой рабочей книги. Wb — это объект деактивизированной рабочей

книги.

Событие AppEvent_WorkbookNewSheet(ByVal Wb AsWorkbook, By Val Sh As Object)

Событие AppEvent_WorkbookNewSheet срабатывает при добавлении в

активную рабочую книгу нового листа. Wb — это объект активной рабочей

книги, Sh — объект нового рабочего листа или листа диаграммы.

Page 214: ? Применение VBA и макросов в Microsoft® Excel

214 Часть I Первые шаги

Событие AppEvent_WorkbookOpen(ByVal Wb As Workbook)

Событие AppEvent_WorkbookOpen срабатывает при открытии рабочей

книги. Wb — это объект только что открытой рабочей книги.

Следующий шагВ этой главе были рассмотрены события, которые позволяют реагировать

на всевозможные действия, происходящие в пределах текущего сеанса рабоY

ты с Excel. Следующая глава посвящена взаимодействию Excel с пользоватеY

лем. В частности, в ней будут рассмотрены такие вопросы, как запрос инY

формации у пользователя, вывод предупреждающих сообщений, а также

предоставление графического интерфейса для реализации дополнительных

способов взаимодействия.

Page 215: ? Применение VBA и макросов в Microsoft® Excel

9Способы взаимодействияс пользователем ........................... 215Создание пользовательскойформы ............................................ 216Вызов и скрытиепользовательской формы..........218Основные элементыуправления формы..................... 220Использование вкладок дляобъединения форм......................225Следующий шаг........................... 226

Глава 9

Ââåäåíèå âïîëüçîâàòåëüñêèåôîðìû

Способывзаимодействияс пользователем

В отличие от окна ввода и окна соY

общения, формы Excel выводят взаиY

модействие с пользователем на соверY

шенно иной качественный уровень.

В этой главе будут рассмотрены

базовые интерфейсы взаимодействия

с пользователем, такие как окно ввоY

да и окно сообщения, а также основы

создания пользовательских форм.

Более подробно пользовательские

формы рассматриваются в главе 21,

‘‘Пользовательские формы YYYY проY

фессиональный подход’’.

Окно ввода Окно ввода данных представляет

собой один из основных интерфейсов

взаимодействия с пользователем. НаY

страиваемым является текст сообщеY

ния, заголовок окна, значение по

умолчанию, положение окна на экраY

не, а также файл справки. Окно ввода

имеет две кнопки YYYY OK и Отмена(Cancel). Функция InputBox возвраY

щает значение типа String. В резульY

тате выполнения приведенного ниже

кода пользователю будет предложено

ввести количество месяцев, для котоY

рого необходимо подсчитать некотоY

рые статистические данные:

Page 216: ? Применение VBA и макросов в Microsoft® Excel

216 Часть I Первые шаги

AveMonths = InputBox(Prompt:="Введите количество месяцев", _ Title:="Введите количество месяцев", Default:="3")

Соответствующее окно ввода показано на рис. 9.1.

Рис. 9.1. Простейшее окно ввода данных

Окно сообщения Не менее важным интерфейсом взаимодействия с пользователем является

окно сообщения. В отличие от окна ввода, окно сообщения может иметь люY

бую комбинацию из кнопок Да (Yes), Нет (No), OK и Отмена (Cancel). НаY

страиваемым также является текст сообщения, заголовок окна и файл справY

ки. В результате выполнения приведенного ниже кода пользователю будет

предложено закрыть рабочую книгу и сохранить внесенные в нее изменения:

MyMsg = "Сохранить изменения?"MyTitle = "Закрытие рабочей книги"Response = MsgBox(MyMsg, vbExclamation + vbYesNoCancel, MyTitle)Select Case Response Case Is = vbYes ActiveWorkbook.Close SaveChanges:=False Case Is = vbNo ActiveWorkbook.Close SaveChanges:=True Case Is = vbCancel Exit SubEnd Select

Выражение Select Case используется для принятия решения относительY

но хода выполнения программного кода в зависимости от сделанного пользоваY

телем выбора. Соответствующее окно сообщения показано на рис. 9.2.

Рис. 9.2. Окно сообщения — это один изспособов базового взаимодействия спользователем

Создание пользовательской формы По сравнению с окном ввода и окном сообщения пользовательская форма

имеет гораздо более широкие возможности. К примеру, ее можно применять

для ввода пользователем личной информации, как показано на рис. 9.3.

Page 217: ? Применение VBA и макросов в Microsoft® Excel

Введение в пользовательские формы Глава 9 217

Чтобы добавить к проекту пользовательскую форму, выберите команду меY

ню редактора Visual Basic Insert UserForm (Вставить Пользовательская

форма). В результате этого к проекту будет добавлен модуль новой формы,

на месте области ввода программного кода будет отображена пустая форма и

на экране появится окно панели инструментов, как показано на рис. 9.4.

Рис. 9.3. Пример пользо&вательской формы

Рис. 9.4. Пустая пользовательская формаи панель инструментов

Изменить размер формы можно с помощью маркеров, расположенных по

бокам и в углах окна формы. Чтобы добавить на форму элемент управления,

щелкните на соответствующей ему кнопке на панели инструментов и нариY

суйте его на форме. Помещенные на форму элементы управления можно пеY

ремещать, а также изменять их размер.

На заметку По умолчанию на панели инструментов находятся только наиболее часто используе&мые элементы управления. Чтобы получить доступ к остальным элементам управления,щелкните на панели инструментов правой кнопкой мыши и выберите команду контек&стного меню Additional Controls (Дополнительные элементы управления).

После добавления элемента управления на форму его свойства становятся досY

тупны посредством окна свойств редактора Visual Basic. Свойства элемента управY

ления можно настроить как вручную, так и с помощью программного кода.

Совет Пользовательской форме, а также элементам управления рекомендуется назна&чать описательные имена. Примером стандартного имени пользовательскойформы является имя UserForm1. Измените его на что&нибудь более значащее,например, frm_AddEmp.

Page 218: ? Применение VBA и макросов в Microsoft® Excel

218 Часть I Первые шаги

Вызов и скрытие пользовательской формы Пользовательскую форму можно вызвать из любого модуля. Следующий

код выводит на экран форму frm_AddEmp:

frm_AddEmp.Show

Для вызова формы может применяться также метод Load, однако в этом

случае форма будет лишь загружена, но не выведена на экран.

Для скрытия формы применяется метод Hide. Форма будет поYпрежнему

активна, однако не видна на экране. Все элементы управления формы доступY

ны посредством программного кода.

Метод Unload выгружает форму из памяти и убирает ее с экрана. В резульY

тате выполнения приведенного ниже кода форма Me становится недоступной

как посредством пользовательского интерфейса, так и посредством проY

граммного кода:

Unload Me

Программирование пользовательской формы

Код обработки событий элементов управления формы помещается в моY

дуль этой формы. В отличие от других модулей, двойной щелчок на модуле

формы приводит к ее открытию в режиме конструктора. Чтобы просмотреть

код формы, щелкните правой кнопкой мыши на названии модуля формы или

на самой форме в режиме конструктора и выберите команду контекстного меY

ню View Code (Просмотр кода).

Чтобы ввести код обработки стандартного события элемента управления

формы, выделите требуемый элемент управления и выберите команду меню

View Code (Вид Код). Редактор Visual Basic автоматически сгенерирует заY

головки процедуры обработки стандартного события. Чтобы отобразить спиY

сок других событий данного элемента управления, выберите соответствуюY

щий ему объект из раскрывающегося списка Object (Объект) и откройте расY

крывающийся список Properties (Свойства), как показано на рис. 9.5.

Рис. 9.5. Раскрывающийся список Properties содержит все события, доступные для элементауправления формы, выбранного из списка Object

Page 219: ? Применение VBA и макросов в Microsoft® Excel

Введение в пользовательские формы Глава 9 219

Все элементы управления являются объектами с соответствующими свойY

ствами и методами. Обычно весь код, относящийся к элементу управления,

размещается в модуле формы. При обращении к элементу управления извне

этого модуля имя соответствующего объекта необходимо предварить именем

объекта формы.

Private Sub btn_EmpCancel_Click() Unload MeEnd Sub

Рассмотрим некоторые из составляющих элементов приведенного выше кода:

btn_EmpCancel — имя элемента управления;

Click — событие элемента управления;

Unload Me — код обработки события элемента управления (в данном

случае форма будет убрана с экрана и выгружена из памяти).

Практикум

Добавление элемента управленияк существующей формеДобавление элемента управления к существующей форме представляет собойвесьма непростую задачу. Щелкнув на новом элементе управления правой кноп&кой мыши и выбрав команду контекстного меню View Code (Просмотр кода), выобнаружите, что редактор Visual Basic даже не подозревает о существовании та&кого элемента. Имени объекта элемента управления нет и в раскрывающемся спи&ске Object (Объект).Чтобы добавить элемент управления к существующей форме, выполните следую&щие действия.

1. Добавьте к существующей форме все необходимые элементы управления.

2. Щелкните на названии модуля формы в диспетчере проектов правой кнопкоймыши и выберите команду контекстного меню Export File (Экспорт в файл).В открывшемся диалоговом окне Export File (Экспорт в файл) щелкните накнопке Сохранить (Save), чтобы сохранить файл формы в стандартном разме&щении.

3. Снова щелкните на названии модуля формы в диспетчере проектов правой кноп&кой мыши и выберите команду контекстного меню Remove (Удалить). В ответ напредложение экспортировать файл формы щелкните на кнопке Нет (No).

4. Щелкните правой кнопкой мыши на незанятом участке окна диспетчера про&ектов и выберите из контекстного меню команду Import File (Импорт из файла).Выберите созданный выше файл формы и щелкните на кнопке Открыть (Open).

В результате выполнения приведенной выше последовательности действий ре&дактор Visual Basic распознает все элементы управления, добавленные к сущест&вующей форме.

Page 220: ? Применение VBA и макросов в Microsoft® Excel

220 Часть I Первые шаги

Основные элементы управления формы

Форма, показанная на рис. 9.6, состоит из надписей, полей ввода и

командных кнопок.

После ввода требуемой информации пользователь щелкает на кнопке OK,

что приводит к заполнению соответствующих ячеек на рабочем листе, как поY

казано на рис. 9.7.

Рис. 9.6. Простая форма, пред&назначенная для ввода пользо&вательских данных

Рис. 9.7. Информация, введенная в форму, помещает&ся на рабочий лист Excel

Private Sub btn_EmpOK_Click() Dim LastRow As Long LastRow = Worksheets("Лист2").Range("A65536").End(xlUp).Row + 1 Cells(LastRow, 1).Value = tb_EmpName.Value Cells(LastRow, 2).Value = tb_EmpPosition.Value Cells(LastRow, 3).Value = tb_EmpHireDate.ValueEnd Sub

Примечательно, что одна и та же форма может использоваться как для ввода,

так и для извлечения информации. Чтобы приспособить показанную на рис. 9.6

форму для извлечения сведений о должности служащего и дате приема на рабоY

ту, измените код обработки события btn_EmpOK_Click, как показано ниже:

Private Sub btn_EmpOK_Click() Dim EmpFound As Range With Range("EmpList") Set EmpFound = .Find(tb_EmpName.Value) If EmpFound Is Nothing Then MsgBox("Служащий не найден!") tb_EmpName.Value = "" Exit Sub Else With Range(EmpFound.Address) tb_EmpPosition = .Offset(0, 1) tb_HireDate = .Offset(0, 2) End With End If End WithEnd Sub

Page 221: ? Применение VBA и макросов в Microsoft® Excel

Введение в пользовательские формы Глава 9 221

Использование списков и комбинированных списков

При вводе имени служащего можно допустить ошибку. Чтобы этого не

произошло, предложите пользователю выбрать имя служащего из списка или

комбинированного списка.

Список позволяет выбрать одно или несколько значений.

Комбинированный список позволяет выбрать одно значение или

ввести новое.

Заменим поле ввода имени служащего списком, как показано на рис. 9.8.

Элементы списка определяются значением свойства RowSource объекта

списка. Поскольку список служащих может меняться, для обращения к нему

рекомендуется использовать динамический именованный диапазон ячеек.

Private Sub btn_EmpOK_Click() Dim EmpFound As Range With Range("EmpList") Set EmpFound = .Find(lb_EmpName.Value) If EmpFound Is Nothing Then MsgBox("Служащий не найден!") lb_EmpName.Value = "" Exit Sub Else With Range(EmpFound.Address) tb_EmpPosition = .Offset(0, 1) tb_HireDate = .Offset(0, 2) End With End If End WithEnd Sub

Выбор нескольких значений из списка

Объект списка имеет свойство MultiSelect, позволяющее выбирать из

списка несколько значений одновременно (рис. 9.9).

Рис. 9.8. Список позволяет избе&жать ошибок ввода

Рис. 9.9. Список поддерживаетвозможность выбора несколькихзначений одновременно

Page 222: ? Применение VBA и макросов в Microsoft® Excel

222 Часть I Первые шаги

Ниже перечислены возможные значения этого свойства:

fmMultiSelectSingle — значение по умолчанию, разрешающее выY

бор из списка только одного элемента;

fmMultiSelectMulti — разрешает выбор из списка нескольких элеY

ментов одновременно, а также отмену выбора элемента путем повторY

ного щелчка на нем;

fmMultiSelectExtended — разрешает выбор из списка нескольких

элементов одновременно с применением клавиш <Ctrl> и <Shift>,

а также отмену выбора элемента путем повторного щелчка на нем.

Следующий код демонстрирует способ обращения к элементам списка,

поддерживающего множественный выбор:

Private Sub btn_EmpOK_Click() Dim LastRow As Long, i As Integer LastRow = Worksheets("Лист2").Range("A65536").End(xlUp).Row + 1 Cells(LastRow, 1).Value = tb_EmpName.Value'Какие элементы из списка выбраны? For i = 0 To lb_EmpPosition.ListCount - 1'Если элемент выбран, добавить его на рабочий лист. If lb_EmpPosition.Selected(i) = True Then Cells(LastRow, 2).Value = Cells(LastRow, 2).Value & _lb_EmpPosition.List(i) & "," End If Next i Cells(LastRow, 3).Value = tb_HireDate.ValueEnd Sub

Поскольку первый элемент списка имеет порядковый номер 0, при опреY

делении верхней границы значения переменнойYсчетчика от значения свойY

ства ListCount необходимо отнять 1:

For i = 0 To lb_EmpPosition.ListCount - 1

Использование переключателей

Переключатели должны быть отделены от остальных элеменY

тов пользовательской формы с помощью панели, как показано

на рис. 9.10.

Все переключатели одной группы должны иметь одинаковое значение

свойства GroupName, чтобы гарантировать возможность выбора только одY

ного переключателя в группе.

Совет Некоторые пользователи предпочитают выбирать переключатель путем щелчка насоответствующей ему надписи (рис. 9.11). Ниже приведен пример кода, реали&зующего такую возможность: Private Sub Lbl_Bldg1_Click() Obtn_Bldg1.Value = TrueEnd Sub

Page 223: ? Применение VBA и макросов в Microsoft® Excel

Введение в пользовательские формы Глава 9 223

Рис. 9.10. Для группирования пере&ключателей используется панель

Рис. 9.11. Некоторые пользователипредпочитают выбирать переклю&чатель путем щелчка на соответст&вующей надписи

Использование изображений

Изображения позволяют придать списку более наглядный вид, как

показано на рис. 9.12.

Рис. 9.12. Изображения придают списку более на&глядный вид

Согласно приведенному ниже коду, выбор имени служащего из списка буY

дет сопровождаться выводом фотографии этого служащего:

Private Sub lb_EmpName_Change() Dim EmpFound As Range With Range("EmpList") Set EmpFound = .Find(lb_EmpName.Value) If EmpFound Is Nothing Then MsgBox("Служащий не найден!") lb_EmpName.Value = "" Exit Sub Else

Page 224: ? Применение VBA и макросов в Microsoft® Excel

224 Часть I Первые шаги

With Range(EmpFound.Address) tb_EmpPosition = .Offset(0, 1) tb_HireDate = .Offset(0, 2) On Error Resume Next Img_Employee.Picture = LoadPicture _(ThisWorkbook.Path & Application.PathSeparator & EmpFound & ".jpg") On Error GoTo 0 End With End If End WithEnd Sub

Использование счетчиков

Как показано на рис. 9.12, поле Дата приема на работу позволяет вводить

данные в произвольном формате, например, 1/1/1 или 1 января 2001 года.

Чтобы унифицировать ввод даты приема служащего на работу, следует восY

пользоваться счетчиками.

Счетчик ограничивает пользователя вводом численного значения и

содержит кнопки увеличения и уменьшения последнего.

Рассмотрим создание счетчика для ввода месяца. Поместите счетчик

на форму. Установите свойство объекта счетчика Min равным 1 (январь),

свойство Max YYYY 12 (декабрь), свойство Value YYYY 1 (начальное значение).

Разместите рядом со счетчиком поле ввода, которое будет использоваться для

отображения текущего значения счетчика (вместо поля ввода можно примеY

нить надпись). Ниже приведен код обработки события, срабатывающего при

изменении значения счетчика:

Private Sub SpBtn_Month_Change() tb_Month.Value = SpBtn_Month.ValueEnd Sub

Добавьте на форму еще два счетчика и два поля ввода, как показано на

рис. 9.13.

Private Sub btn_EmpOK_Click() Dim LastRow As Long, i As Integer LastRow = Worksheets("Лист2").Range("A65536").End(xlUp).Row + 1 Cells(LastRow, 1).Value = tb_EmpName.Value For i = 0 To lb_EmpPosition.ListCount - 1 If lb_EmpPosition.Selected(i) = True Then Cells(LastRow, 2).Value = Cells(LastRow, 2).Value & _lb_EmpPosition.List(i) & "," End If Next i'Создание даты путем конкатенации значений полей ввода. Cells(LastRow, 3).Value = tb_Month.Value & "/" & _tb_Day.Value & "/" & tb_Year.ValueEnd Sub

Page 225: ? Применение VBA и макросов в Microsoft® Excel

Введение в пользовательские формы Глава 9 225

Использование вкладок для объединения формВкладки позволяют объединить воедино несколько различных форм.

На рис. 9.14 показан пример объединения форм для ввода служебной

и личной информации о сотруднике.

Рис. 9.13. Чтобы унифициро&вать ввод даты приема слу&жащего на работу, восполь&зуйтесь счетчиками

Рис. 9.14. Используйте вкладки для объединения несколь&ких различных форм

Совет Старайтесь планировать формы с вкладками заранее. Чтобы создать форму свкладками на основе уже существующих форм, необходимо создать новую фор&му, добавить в нее требуемое число вкладок и скопировать на них элементыуправления с имеющихся форм.

Проверка ввода обязательных данных Одним из преимуществ электронной формы является возможность проY

верки ввода обязательных данных:

If tb_EmpName.Value = "" Then frm_AddEmp.Hide MsgBox("Пожалуйста, введите имя служащего") frm_AddEmp.Show Exit SubEnd If

Закрытие формы Как и большинство окон Windows, окно пользовательской формы имеет

кнопку Закрыть (Close) (кнопка с изображением крестика), расположенную в

его правом верхнем углу. В зависимости от предназначения формы ее закрыY

тие путем щелчка на этой кнопке может оказаться весьма нежелательным.

Определить способ закрытия окна формы и, при необходимости, соответстY

вующим образом среагировать на него поможет событие QueryClose:

Page 226: ? Применение VBA и макросов в Microsoft® Excel

226 Часть I Первые шаги

Private Sub UserForm_QueryClose(Cancel As Integer, _CloseMode As Integer) If CloseMode = vbFormControlMenu Then MsgBox "Для закрытия формы щелкните на кнопке OK _или Отмена", vbCritical Cancel = True End IfEnd Sub

Согласно приведенному выше коду попытка закрытия формы с помощью

недозволенного способа приведет к выводу окна сообщения, показанного на

рис. 9.15.

Рис. 9.15. Событие QueryClose позволяет опре&делить способ закрытия окна формы и соответ&ствующим образом среагировать на него

Ниже перечислены оставшиеся способы закрытия окна формы:

vbFormCode — форма была закрыта с помощью метода Unload;

vbAppWindows — форма была закрыта в результате завершения рабоY

ты Windows;

vbTaskManager — форма была закрыта с помощью диспетчера задач.

Следующий шагВ этой главе были рассмотрены базовые интерфейсы взаимодействия с пользоY

вателем, такие как окно ввода и окно сообщения, а также основы создания польY

зовательских форм Excel. Следующая глава посвящена диаграммам YYYY одному из

наиболее эффективных средств наглядного представления данных.

Page 227: ? Применение VBA и макросов в Microsoft® Excel

IIЧасть II

Автоматизация Excel

10. Диаграммы .......................................................................... 229

11. Анализ данных с помощью расширенного фильтра ..... 267

12. Сводные таблицы............................................................... 299

13. Excel всемогущий................................................................ 363

14. Взаимодействие с Internet ............................................... 407

15. Поддержка XML в профессиональномвыпуске Excel 2003.............................................................. 427

16. Автоматизация Word ........................................................439

Page 228: ? Применение VBA и макросов в Microsoft® Excel
Page 229: ? Применение VBA и макросов в Microsoft® Excel

10Встроенные диаграммы идиаграммы, расположенныена отдельном листе .................... 229Создание диаграмм спомощью VBA ...............................232Использование объектныхпеременных для упрощениякода ................................................ 236“Анатомия” диаграммы ............237Типы диаграмм ............................ 251Параметры трехмерных икруговых диаграмм.................... 256Интерактивные диаграммы..... 260Экспорт диаграммы в файлизображения................................. 261Удивительные возможноститочечных диаграмм ................... 262Создание нестандартныхдиаграмм ...................................... 262Следующий шаг........................... 266

Глава 10

Äèàãðàììû

Говорят, лучше один раз увидеть,

чем сто раз услышать. Наглядное предY

ставление данных имеет неоспоримое

преимущество перед сухими цифрами.

Именно поэтому диаграммы являются

неотъемлемой частью всех программ

для работы с электронными таблицаY

ми, пройдя вместе с ними долгий эвоY

люционный путь развития.

В этой главе рассматривается исY

пользование VBA при выполнении

следующих базовых задач:

создание встроенных диаграмм

и диаграмм, расположенных на

отдельном листе;

выбор типа диаграммы;

изменение типа диаграммы;

форматирование, перемещение

и удаление диаграммы и ее элеY

ментов;

создание нестандартных диаY

грамм.

Одной из особенностей програмY

мирования диаграмм в Excel является

наличие двух объектных моделей,

каждая из которых соответствует разY

личному типу диаграмм.

Встроенные диаграммыи диаграммы,расположенныена отдельном листе

Изначально все диаграммы создаY

вались на отдельном листе. В середиY

Page 230: ? Применение VBA и макросов в Microsoft® Excel

230 Часть II Автоматизация Excel

не 1990Yх годов в Excel была добавлена возможность встраивать диаграмму в

существующий рабочий лист.

Наличие двух различных типов диаграмм вызвало необходимость создания

двух объектных моделей. Диаграмме, расположенной на отдельном листе, соY

ответствует объект Chart, в то время как для работы со встроенной диаграмY

мой следует использовать объект ChartObject.

Встроенные диаграммы и контейнер ChartObject

Объект ChartObject является своеобразным ‘‘контейнером’’ встроенной

диаграммы. Его основное предназначение заключается в обеспечении способа

определения размера встроенной диаграммы и ее положения на рабочем лисY

те. Эти параметры распространяются на все внедренные в диаграмму объекты,

такие как автофигуры и изображения.

Откройте любой рабочий лист, содержащий встроенную диаграмму.

Щелкните на диаграмме, удерживая нажатой клавишу <Ctrl> или <Shift>.

По бокам и в углах области диаграммы появятся круглые маркеры управления

размером белого цвета, как показано на рис. 10.1.

Рис. 10.1. Чтобы выделить контейнер ChartObject, щелкните на встроен&ной диаграмме, удерживая нажатой клавишу <Ctrl> или <Shift>. Имя кон&тейнера диаграммы появится в поле Имя слева от поля ввода формулы

В поле Имя (Name Box) слева от поля ввода формулы появится имя контейY

нера встроенной диаграммы. Это имя используется для обращения к объекту

ChartObject, как показано ниже:

ActiveSheet.ChartObjects("Диаграмма 1").Select

Page 231: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 231

Чтобы определить смещение контейнера встроенной диаграммы от верхY

ней границы рабочего листа, выделите объект ChartObject и введите в окне

Immediate (Быстрое выполнение) редактора Visual Basic строку Print Se-lection.Top.

Отмените выделение контейнера диаграммы, после чего щелкните на неY

занятом пространстве между границей диаграммы и областью ее построения.

По бокам и в углах области диаграммы появятся квадратные маркеры управY

ления размером черного цвета (рис. 10.2), что свидетельствует о выделении

области диаграммы.

Рис. 10.2. Чтобы выделить область диаграммы, щелкните на незанятомпространстве между границей диаграммы и областью ее построения. В по&ле Имя появится стандартное имя области всех диаграмм — Областьдиаграммы

Области всех диаграмм имеют стандартное имя Область диаграммы(Chart Area), которое выводится в поле Имя слева от поля ввода формулы.

Ниже приведен код VBA, соответствующий выделению области диаграммы:

ActiveSheet.ChartObjects("Диаграмма 1").ActivateActiveChart.ChartArea.Select

Чтобы узнать смещение области диаграммы от верхней границы контейнеY

ра, выделите область диаграммы и введите в окне Immediate редактора Visual

Basic строку Print Selection.Top.

Ниже приведен пример изменения цвета области диаграммы, встроенной в

рабочий лист Excel:

Worksheets("Лист3").ChartObjects("Диаграмма 2").Chart.ChartArea. _Interior.ColorIndex = 2

Page 232: ? Применение VBA и макросов в Microsoft® Excel

232 Часть II Автоматизация Excel

Диаграммы, расположенные на отдельном листе При работе с диаграммами, расположенными на отдельном листе, примеY

няется объектная модель, отличная от той, что применялась при работе со

встроенными диаграммами. В частности, объект диаграммы принадлежит не

объекту контейнера, а объекту листа. Ниже приведен пример изменения цвета

области диаграммы, расположенной на отдельном листе:

Sheets("Диаграмма 2").ChartArea.Interior.ColorIndex = 2

Создание диаграмм с помощью VBAНаиболее простой способ создания диаграммы с

помощью пользовательского интерфейса Excel заY

ключается в выделении исходных данных и нажаY

тии клавиши <F11>. Рассмотрим код, сгенерироY

ванный средством записи макросов при построеY

нии диаграммы на основе исходных данных,

показанных на рис. 10.3.

На рис. 10.4 показана диаграмма, созданная Excel

в результате нажатия клавиши <F11>.

Рис. 10.4. В результате нажатия клавиши <F11> Excel создаст новую диаграмму, расположеннуюна отдельном листе

Рис. 10.3. Чтобы создатьдиаграмму, выделите ис&ходные данные и нажмитеклавишу <F11>

Page 233: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 233

Ниже приведен код, сгенерированный средством записи макросов:

Charts.AddActiveChart.SetSourceData Source:=Sheets("Лист1").Range("A1:B5")ActiveChart.Location Where:=xlLocationAsNewSheet

Проанализируем первую строку кода:

Charts.Add

Коллекция Charts представляет собой коллекцию всех листов диаграмм в раY

бочей книге. Каждая коллекция имеет метод добавления нового элемента YYYY Add.

Таким образом, в результате выполнения строки Charts.Add в коллекцию

Charts будет добавлен новый лист диаграммы (пока еще пустой).

Добавив новый лист диаграммы, Excel автоматически делает его активным.

Для обращения к текущей активной диаграмме можно использовать как

объект Chart (например, Charts("Диаграмма 1")), так и объект VBA Ac-tiveChart.

Внимание Если текущим активным объектом является объект, отличный от диаграммы, по&пытка использования объекта ActiveChart приведет к возникновению ошибки.

ActiveChart.SetSourceData Source:=Sheets("Лист4").Range("A1:B5")

Вторая строка автоматически сгенерированного кода определяет диапазон

исходных данных для диаграммы с помощью метода SetSourceData. СледуY

ет отметить, что VBA содержит соответствующие методы для всех действий,

которые можно выполнить посредством пользовательского интерфейса. Так,

для того чтобы задать диапазон исходных данных диаграммы, необходимо

щелкнуть на ней правой кнопкой мыши и выбрать команду контекстного меY

ню Исходные данные (Source Data). На экране появится диалоговое окно

Исходные данные (Source Data) (рис. 10.5), вкладка Диапазон данных (Data

Range) которого позволяет указать диапазон исходных данных.

Ниже приведен полный синтаксис метода SetSourceData:

SetSourceData(Source, PlotBy)

Здесь Source YYYY это ссылка на диапазон ячеек, а PlotBy YYYY константа,

принимающая значение xlColumns или xlRows.

Ниже приведен пример вызова метода SetSourceData с указанием всех

аргументов:

ActiveChart.SetSourceData Source:=Sheets("Лист4").Range("A1:B5"), _PlotBy:=xlColumns

Обратите внимание, что автоматически сгенерированный код не содержит арY

гумент PlotBy. Вероятно, средство записи макросов сочло возможным опустить

его, поскольку структура исходных данных (имена заголовков столбцов в ячейках

A1 и B1) предполагает, что ряды данных расположены в столбцах. К сожалению,

подобная эффективность является скорее исключением, чем правилом.

ActiveChart.Location Where:=xlLocationAsNewSheet

Page 234: ? Применение VBA и макросов в Microsoft® Excel

234 Часть II Автоматизация Excel

Рис. 10.5. Для определения исходных данных диаграммы можно восполь&зоваться диалоговым окном Исходные данные или методом VBA Set-SourceData

Приведенная выше строка соответствует последнему шагу мастера создаY

ния диаграмм (рис. 10.6).

Рис. 10.6. Выбор размещения диаграммы

Ниже приведен полный синтаксис метода Location:

Location(Where, Name)

Page 235: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 235

Константа Where может принимать значения xlLocationAsNewSheet,

xlLocationAsNewObject и xlLocationAutomatic.

Name — это строка, которая определяет

имя нового листа, на котором будет размещена диаграмма (параметр

Where принимает значение xlLocationAsNewSheet);

имя рабочего листа, на котором будет размещена встроенная диаграмY

ма (параметр Where принимает значение xlLocationAsNewObject).

Как уже отмечалось, средство записи макросов генерирует много избыточY

ного кода. Поскольку использование метода Charts.Add подразумевает, что

новая диаграмма будет размещаться на отдельном листе, последняя строка

сгенерированного кода является лишней и ее можно удалить.

Изменение размещения диаграммы

Метод Location позволяет изменить тип диаграммы, преобразовав ее из

встроенной на размещенную на отдельном листе и наоборот. (Чтобы изменить

размещение диаграммы с помощью пользовательского интерфейса, щелкните

на диаграмме правой кнопкой мыши и выберите команды контекстного меню

Размещение (Location).)

Рассмотрим следующий код:

Worksheets("Лист1").ChartObjects("Диаграмма 1").ActivateActiveChart.Location Where:=xlLocationAsNewSheet,Name:="МояДиаграмма"

Его выполнение приведет к преобразованию диаграммы Диаграмма 1,

встроенной в рабочий лист Лист1, в диаграмму, размещенную на отдельном

листе МояДиаграмма.

Стандартный тип диаграмм

Обратите внимание, что в автоматически сгенерированном коде не был

указан тип создаваемой диаграммы. Одна из особенностей Excel VBA заклюY

чается в возможности неявного использования стандартных значений параY

метров Excel (в данном случае параметра, определяющего тип диаграммы). По

умолчанию стандартной диаграммой Excel является обычная гистограмма.

Эта особенность Excel может сыграть весьма неоднозначную роль. С одной

стороны, вы можете изменить стандартную диаграмму, чтобы создать неY

сколько однотипных диаграмм. С другой стороны, нельзя быть на 100% увеY

ренным в том, что один и тот же тип диаграммы используется в качестве станY

дартного на всех компьютерах, куда может попасть данная рабочая книга.

Переопределить стандартное значение параметра можно с помощью кода

VBA. Следующая строка кода изменяет цвет заливки области построения

диаграммы с серого на белый:

ActiveChart.PlotArea.Interior.ColorIndex = xlNone

Page 236: ? Применение VBA и макросов в Microsoft® Excel

236 Часть II Автоматизация Excel

Совет Чтобы изменить стандартный тип диаграммы с помощью пользовательского ин&терфейса, щелкните на диаграмме правой кнопкой мыши и выберите командуконтекстного меню Тип диаграммы (Chart Type). Выберите требуемый тип диа&граммы и щелкните на кнопке Сделать стандартной (Set As Default Chart).

Использование объектных переменныхдля упрощения кода

Объектные переменные позволяют упростить код и сделать его более эфY

фективным. В частности, использование объектной переменной делает возY

можным обращение к диаграмме без активизации последней. Ниже приведен

пример создания объектной переменной типа Chart:

Dim Cht As ChartSet Cht = Charts.AddCht.SourceData = Source:=Sheets("Лист4").Range("A1:B5")

Объектные переменные будут использоваться на протяжении оставшейся

части этой главы.

Еще одним преимуществом объектных переменных является поддержка

редактором Visual Basic автозаполнения. Чтобы включить автозаполнение,

выберите команду меню редактора Visual Basic Tools Options (Сервис

Параметры) и установите флажок Auto List Members (Автозаполнение) на

вкладке Editor (Редактор), как показано на рис. 10.7.

Рис. 10.7. Автозаполнение позволяет редактору Vi&sual Basic автоматически предлагать подходящийспособ продолжения ввода программного кода

Автозаполнение позволяет редактору Visual Basic автоматически предY

лагать подходящий способ продолжения ввода программного кода. Все,

Page 237: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 237

что требуется от пользователя YYYY это выбрать нужный элемент из списка,

как показано на рис. 10.8.

Рис. 10.8. Автозаполнение в действии — после вводавыражения Cht.ChartType = редактор Visual Basicпредлагает выбрать требуемую константу из списка

Внимание Сбой в работе средства автозаполнения может быть вызван наличием ошибкикомпилирования в программном коде. Чтобы обнаружить ошибку, выберите ко&манду меню редактора Visual Basic Debug Compile VBA Project (ОтладкаКомпилировать проект VBA). Устранение ошибки компилирования должно при&вести к восстановлению работы средства автозаполнения.

“Анатомия” диаграммы В этом разделе рассматриваются VBAYэквиваленты различных элементов

диаграммы, их свойства и методы.

Все элементы диаграмм можно разделить на две категории: элементы,

общие для всех диаграмм (например, область диаграммы, область поY

строения диаграммы, название диаграммы и легенда), и элементы, харакY

терные только для диаграмм определенного типа (например, угол повороY

та круговой диаграммы и параметры проекции трехмерных диаграмм).

График, точечная диаграмма и диаграмма с областями имеют по две оси

данных; лепестковая диаграмма YYYY одну ось для каждой категории данных;

круговая и кольцевая диаграммы не имеют осей как таковых.

Область диаграммы (ChartArea)

Объект ChartArea представляет собой контейнер для всех остальных элеY

ментов диаграммы, таких как область построения диаграммы, оси, легенда,

ряды данных, подписи данных и т.д. Наиболее распространенными изменеY

ниями, вносимыми в область диаграммы, являются определение формата обY

ласти диаграммы (выбор границы, цвета заливки и текстуры) и выбор параY

метров шрифта.

Рассмотрим пример форматирования области диаграммы, для чего запишем

небольшой макрос. Щелкните правой кнопкой мыши на области диаграммы и

Page 238: ? Применение VBA и макросов в Microsoft® Excel

238 Часть II Автоматизация Excel

выберите команду контекстного меню Формат области диаграммы (Format

Chart Area). На вкладке Вид (Patterns) диалогового окна Формат областидиаграммы (Format Chart Area) выберите светлоYбирюзовый цвет заливки,

красный цвет рамки, третью по толщине линию и установите флажок С тенью(Shadow). На вкладке Шрифт (Font) выберите размер шрифта 14 и снимите

флажок Автомасштабирование (Auto scale). Ниже приведен код, сгенерированY

ный средством записи макроса в результате выполнения указанных действий:

Sub Macro2AsRecorded() Sheets("Диаграмма 1").Activate ActiveChart.ChartArea.Select With Selection.Border .ColorIndex = 3 .Weight = xlMedium .LineStyle = xlContinuous End With Selection.Shadow = True With Selection.Interior .ColorIndex = 34 .PatternColorIndex = 1 .Pattern = xlSolid End With Selection.AutoScaleFont = False With Selection.Font .Name = "Arial" .FontStyle = "Regular" .Size = 14 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleNone .ColorIndex = xlAutomatic .Background = xlAutomatic End WithEnd Sub

Средство записи макросов зафиксировало все действия, выполненные поY

средством пользовательского интерфейса (и даже больше). Следующий шаг

состоит в оптимизации полученного кода. Строки, набранные полужирным

шрифтом, являются избыточными:

Sub Macro2AsRecorded() Sheets("Диаграмма 1").Activate ActiveChart.ChartArea.Select With Selection.Border .ColorIndex = 3 .Weight = xlMedium' Значение по умолчанию. .LineStyle = xlContinuous End With Selection.Shadow = True With Selection.Interior' Светло-бирюзовый цвет заливки. .ColorIndex = 34

Page 239: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 239

' Значение по умолчанию. .PatternColorIndex = 1' Значение по умолчанию. .Pattern = xlSolid End With Selection.AutoScaleFont = False With Selection.Font' Значение не изменилось. .Name = "Arial"' Значение не изменилось. .FontStyle = "Regular" .Size = 14' Значение не изменилось. .Strikethrough = False' Значение не изменилось. .Superscript = False' Значение не изменилось. .Subscript = False' Значение не изменилось. .OutlineFont = False' Значение не изменилось. .Shadow = False' Значение не изменилось. .Underline = xlUnderlineStyleNone' Значение не изменилось. .ColorIndex = xlAutomatic' Значение не изменилось. .Background = xlAutomatic End WithEnd Sub

Ниже приведен оптимизированный код макроса:

Sub Macro2Shortened() Sheets("Диаграмма 1").Activate ActiveChart.ChartArea.Select With Selection.Border .ColorIndex = 3 .Weight = xlMedium End With Selection.Shadow = True With Selection.Interior .ColorIndex = 34 End With Selection.AutoScaleFont = False With Selection.Font .Size = 14 End WithEnd Sub

С целью дальнейшего упрощения кода создадим объектную переменную,

представляющую область диаграммы. Обратите внимание, что при использоY

вании объектной переменной к области диаграммы можно обращаться без ее

предварительного выделения. Более того, следующий код будет выполняться

корректно даже в том случае, когда лист диаграммы не будет активным:

Page 240: ? Применение VBA и макросов в Microsoft® Excel

240 Часть II Автоматизация Excel

Sub ChartArDemo() Dim ChtArea As ChartArea Set ChtArea = Charts("Диаграмма 1").ChartArea With ChtArea .Shadow = True With .Border .ColorIndex = 3 .Weight = xlMedium End With .Interior.ColorIndex = 34 .AutoScaleFont = False .Font.Size = 14 End WithEnd Sub

Поговорим о цвете

При выборе цвета линии, заливки или шрифта Excel предлагает использовать

стандартную палитру, состоящую из 56 цветов. Чтобы изменить любой цвет станY

дартной палитры, выберите команду меню Excel Сервис Параметры(Tools Options), перейдите во вкладку Цвет (Color) и, указав требуемый цвет,

щелкните на кнопке Изменить (Modify). Измененная палитра сохраняется

вместе с рабочей книгой. Для доступа к цветам палитры можно использовать

свойство рабочей книги Colors.

Следующие строки кода полностью эквивалентны:

.Border.ColorIndex = 3.Border.Color = ThisWorkbook.Colors(3)

Обратите внимание, что порядок цветов в палитре не соответствует их инY

дексу, т.е. значению свойства ColorIndex. Например, в стандартной палитре

красный цвет (1Yй столбец 3Yй строки) имеет индекс 3, а бирюзовый (5Yй

столбец 4Yй строки) YYYY 8. Наиболее простой способ определения индекса цвеY

та заключается в записи простого макроса, устанавливающего требуемый цвет

для произвольного элемента интерфейса.

Любой цвет на экране может быть получен путем смешивания трех основY

ных цветов YYYY красного, зеленого и синего. В VBA есть функция RGB, позвоY

ляющая создать практически любой цвет путем указания интенсивности его

составляющих. Ниже приведен синтаксис функции RGB:

RGB(red, green, blue)

Каждый из аргументов принимает значения в диапазоне от 0 до 255. СлеY

дующие строки кода полностью эквивалентны и используются для установки

красного цвета границы:

.Border.ColorIndex = 3.Border.Color = RGB(255, 0, 0)

Область построения диаграммы (PlotArea)

Область построения диаграммы содержит визуализированные ряды данY

ных, оси и подписи осей. К ней применимы те же операции форматирования,

Page 241: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 241

что и к области диаграммы. Вдобавок, вы можете изменять размеры области

построения диаграммы и ее размещение в пределах области диаграммы с поY

мощью свойств Top, Left, Height и Width объекта PlotArea.

Изменение размера и размещения объекта

Каждый объект рисунка или диаграммы имеет контейнер. К примеру, конY

тейнером автофигуры является рабочий лист, на котором она размещена. ПоY

добным образом, контейнером области построения диаграммы является область

самой диаграммы. Объект, заключенный в контейнер, имеет ограничивающийпрямоугольник YYYY наименьший прямоугольник, в который полностью вписываY

ется данный объект.

За единицу измерения в Excel VBA принята точка, составляющая 1/72

дюйма.

Размещение объекта полностью определяется расстоянием по вертикали и

горизонтали от верхнего левого угла объекта до верхнего левого угла его контейY

нера. Расстоянию по вертикали соответствует свойство объекта Top, а расстояY

нию по горизонтали YYYY свойство объекта Left. Высота и ширина объекта совY

падают с высотой и шириной его ограничивающего прямоугольника (рис. 10.9).

Рис. 10.9. Размещение объекта полностью опреде&ляется расстоянием по вертикали и горизонтали отверхнего левого угла объекта до верхнего левогоугла его контейнера. Высота и ширина объектасовпадают с высотой и шириной его ограничи&вающего прямоугольника

Свойства Top, Left, Height и Width поддерживают как считывание, так

и установку значения. Ниже приведен пример определения высоты объекта:

ObjHt = obj.Height

и изменения его размещения:

obj.Top = 75obj.Left = 80

Рассмотрим следующий код:

Sub PlotArDemo() Dim PltArea As PlotArea

Page 242: ? Применение VBA и макросов в Microsoft® Excel

242 Часть II Автоматизация Excel

Set PltArea = Charts("Диаграмма 3").PlotArea With PltArea .Top = 100 .Left = 100 .Height = 300 .Width = 400 End WithEnd Sub

Результат его выполнения представлен на рис. 10.10.

Рис. 10.10. Свойства объекта Top, Left, Height и Width позволяют изменить его размери размещение

Наличие свойств Top, Left, Height и Width позволяет задать размер

и размещение объекта с большей точностью, чем это можно было бы сделать

с помощью пользовательского интерфейса. Изменяя значения этих свойств,

следует помнить об их естественных ограничениях. К примеру, сумма значеY

ний свойств объекта Left и Width не может превысить значение свойства

Width контейнера объекта.

Ряды данных (Series)

Ряды данных диаграммы входят в коллекцию SeriesCollection. РасY

сматриваемая в качестве примера диаграмма имеет два ряда данных YYYY Xdataи Ydata. Ниже приведен синтаксис обращения к ряду данных:

Cht.SeriesCollection(Index)

Page 243: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 243

Index — это номер (начиная с 1) или имя ряда данных. Щелкнув на точке

данных (столбце) из ряда Xdata, вы увидите в строке формул следующее выY

ражение:

=РЯД(Лист1!$A$1;;Лист1!$A$2:$A$5;1)

(В англоязычной версии Excel: =SERIES(Лист1!$A$1,,Лист1!$A$2:$A$5,1).)

Лист1!$A$1 YYYY это имя ряда данных (Xdata).

По умолчанию второй параметр пропущен, так как ось категорий гистоY

граммы содержит последовательность порядковых чисел (начиная с 1), соотY

ветствующих точкам данных. При необходимости этот параметр может содерY

жать ссылку на диапазон ячеек, определяющий подписи оси категорий.

Лист1!$A$2:$A$5 YYYY это диапазон ячеек, в котором находится ряд данных.

Наконец, 1 YYYY это индекс ряда данных в коллекции. Чтобы изменить инY

декс ряда данных с помощью пользовательского интерфейса, щелкните на

точке данных правой кнопкой мыши, выберите команду контекстного меню

Формат рядов данных (Format Data Series) и перейдите во вкладку Порядокрядов (Series Order).

Ниже приведены два эквивалентных способа обращения к ряду данных

Xdata:

Charts("Диаграмма 1").SeriesCollection("Xdata")Charts("Диаграмма 1").SeriesCollection(1)

Следующий макрос позволяет создать комбинированную диаграмму, в коY

торой ряд данных Xdata будет представлен в виде графика:

Sub SeriesDemo() Dim Ser As Series Set Ser = Charts("Диаграмма 3").SeriesCollection("Xdata") With Ser .ChartType = xlLine .Border.Weight = xlThick .MarkerStyle = xlMarkerStyleCircle .MarkerBackgroundColorIndex = xlAutomatic .MarkerForegroundColorIndex = xlAutomatic .MarkerSize = 10 End WithEnd Sub

Результат выполнения макроса представлен на рис. 10.11.

Оси диаграммы (Axis)

Оси диаграммы входят в коллекцию Axes. Рассматриваемая в качестве

примера диаграмма имеет две оси YYYY ось категорий (X) и ось значений (Y).

Ниже приведен сокращенный синтаксис обращения к оси диаграммы:

Cht.Axes(Type)

Type — это константа Excel VBA, определяющая тип оси. Ось категорий (X)

имеет тип xlCategory, а ось значений (Y) YYYY тип xlValue.

Page 244: ? Применение VBA и макросов в Microsoft® Excel

244 Часть II Автоматизация Excel

Рис. 10.11. Пример создания комбинированной диаграммы путем изменения спосо&ба представления (ChartType) ряда данных

Чтобы обратиться ко всей коллекции осей диаграммы, пропустите параY

метр Type, как показано ниже:

Cht.Axes

Следующий макрос добавляет к диаграмме подписи осей и изменяет форY

мат данных оси Y (оси значений):

Sub AxisDemo() Dim Axs As Axis Set Axs = Charts("Диаграмма 3").Axes(xlValue) With Axs .HasTitle = True .AxisTitle.Caption = "Эффективность производства" .TickLabels.NumberFormat = "0.00" End With Set Axs = Charts("Диаграмма 3").Axes(xlCategory) With Axs .HasTitle = True .AxisTitle.Caption = "Год" End WithEnd Sub

Результат выполнения макроса представлен на рис. 10.12.

Обратите внимание, что добавление подписей осей привело к автоматичеY

скому изменению размера области построения диаграммы. Чтобы задать подY

пись диаграммы, необходимо установить значение свойства оси HasTitleравным True.

Page 245: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 245

Рис. 10.12. Пример добавления к диаграмме подписей осей и измененияформата данных оси значений

Добавление вспомогательных осей

Если масштаб рядов данных сильно отличается, может возникнуть необхоY

димость добавления вспомогательной оси (горизонтальной или вертикальY

ной). Ниже приведен полный синтаксис обращения к оси диаграммы:

Cht.Axes(Type, AxisGroup)

AxisGroup — это константа Excel VBA, определяющая группу оси. ОсновY

ные оси входят в группу xlPrimary, а вспомогательные YYYY в группу xlSe-condary.

Следующий макрос определяет вспомогательную ось значений (Y) для ряда

данных Xdata.

Sub SecondaryAxisDemo() Dim Cht As Chart Set Cht = Charts("Диаграмма 3") Cht.SeriesCollection("Xdata").AxisGroup = 2End Sub

Результат выполнения макроса представлен на рис. 10.13.

Линии сетки (HasMajorGridlines и HasMinorGridlines)

Линии сетки являются расширением меток делений оси и предназначены

для улучшения восприятия и оценки отображаемых данных. Основным

и промежуточным меткам делений оси соответствуют основные и промежуY

точные линии сетки, которые можно скрыть или отобразить независимо друг

Page 246: ? Применение VBA и макросов в Microsoft® Excel

246 Часть II Автоматизация Excel

от друга. Линия сетки имеет настраиваемые параметры, такие как тип, цвет

и толщина.

Рис. 10.13. Если масштаб рядов данных сильно отличается, добавьте вспомо&гательную ось

Следующий макрос удаляет все линии сетки диаграммы:

Sub GridlineDemo() Dim Cht As Chart Set Cht = Charts("Диаграмма 3") With Cht With .Axes(xlValue) .HasMajorGridlines = False .HasMinorGridlines = False End With With Cht.Axes(xlValue) .HasMajorGridlines = False .HasMinorGridlines = False End With End WithEnd Sub

Подписи данных (DataLabels и DataLabel)

Ряд состоит из точек данных. Каждая точка может иметь свою собственную

подпись, включающую значение по оси X (категорий), оси Y (значений) или

значение, определенное пользователем (строковая константа или ссылка на

ячейку). Ниже перечислены различные способы создания подписи данных с

помощью VBA.

Все точки данных диаграммы имеют подписи одного и того же типа:

ActiveChart.ApplyDataLabels Type:=xlDataLabelsShowNone

Page 247: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 247

Точки данных определенного ряда имеют подписи одного и того же типа:

With ActiveChart.SeriesCollection("Xdata") .HasDataLabels = True .ApplyDataLabels Type:=xlDataLabelsShowValueEnd With

Определенная точка в ряде данных имеет подпись в виде строковой

константы:

With ActiveChart.SeriesCollection("Xdata").Points(1) .HasDataLabel = True .DataLabel.Text="Подпись точки данных"End With

Определенная точка в ряде данных имеет подпись в виде R1C1Y

формулы (ссылки на ячейку):

With ActiveChart.SeriesCollection("Xdata").Points(1) .HasDataLabel = True .DataLabel.Text="=Лист1!R1C1"End With

Подпись данных имеет настраиваемые параметры, такие как положение,

ориентация и т.п.

Следующий макрос создает подписи для точек данных ряда Xdata.

Sub DataLabelDemo() With Charts("Диаграмма 3").SeriesCollection("Xdata") .HasDataLabels = True .ApplyDataLabels Type:=xlDataLabelsShowValue With .DataLabels .HorizontalAlignment = xlCenter .VerticalAlignment = xlCenter .Position = xlLabelPositionAbove .Orientation = xlUpward End With End WithEnd Sub

Название диаграммы, легенда и таблица данных(ChartTitle, HasLegend и HasDataTable)

Название диаграммы и легенда имеют такие настраиваемые параметры,

как шрифт и размещение. Кроме того, рядом с каждой диаграммой можно

отобразить таблицу ее исходных данных. Следующий макрос добавляет к

диаграмме ее название (отформатированное полужирным шрифтом 16Yго

размера и размещенное в верхнем левом углу), легенду (расположенную внизу

и посередине диаграммы) и таблицу данных.

Обратите внимание, что установка параметров названия диаграммы, леY

генды и таблицы данных становится возможной только после присвоения

значения True свойствам HasTitle, HasLegend и HasDataTable, соответY

ственно.

Sub DemoMisc() With Charts("Диаграмма 3")

Page 248: ? Применение VBA и макросов в Microsoft® Excel

248 Часть II Автоматизация Excel

.HasTitle = True With .ChartTitle .Text = "Эффективность работы компании" .Font.Size = 16 .Top = 0 .Left = 0 End With .HasLegend = True .Legend.Position = xlBottom .HasDataTable = True End WithEnd Sub

Линии тренда и полосы погрешности (Trendlines и ErrorBar)

Линия тренда дает наглядное представление о направлении изменения ряY

да данных. Excel содержит несколько типов линий тренда: линейная, логаY

рифмическая, полиномиальная, степенная, экспоненциальная и линейная

фильтрация. Полосы погрешности позволяют оценить отклонение фактичеY

ских данных от тренда.

На рис. 10.14 показана точечная диаграмма годовых продаж.

Следующий макрос добавляет к диаграмме линию тренда с прогнозом на

5 периодов (лет) вперед, выводит уравнение линии тренда и величину достоY

верности аппроксимации (R2):

Sub AddTrendLine() Dim Ser As Series Dim Trnd As Trendline Dim Cht As Chart Set Cht = Worksheets("Тренд и погрешности").ChartObjects(" _Диаграмма 1").Chart Set Ser = Cht.SeriesCollection(1) Set Trnd = Ser.Trendlines.Add(Type:=xlLinear, Forward:=5, _Backward:=0, DisplayEquation:=True, DisplayRSquared:=True) Trnd.Border.LineStyle = xlDot With Cht .HasTitle = True .ChartTitle.Characters.Text = "Прогнозируемые продажи" End WithEnd Sub

Результат выполнения макроса показан на рис. 10.15. Величина достоверY

ности аппроксимации (R2), близкая к 1, означает, что линия тренда соответстY

вует фактическим данным.

Следующий макрос добавляет к диаграмме полосы погрешности по обе

стороны точек данных с фиксированным значением величины погрешности,

равным 25 единицам.

Sub AddErrorBars() Dim Ser As Series Dim Trnd As Trendline Dim Cht As Chart Set Cht = Worksheets("Тренд и погрешности").ChartObjects(" _Диаграмма 1").Chart

Page 249: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 249

Set Ser = Cht.SeriesCollection(1) Ser.ErrorBar Direction:=xlY, Include:=xlBoth, _Type:=xlFixedValue, Amount:=25End Sub

Рис. 10.14. Чтобы добавить линию тренда, щелкните на любой точке данных диаграммыгодовых продаж правой кнопкой мыши и выберите команду контекстного менюДобавить линию тренда (Add Trendline)

Полосы погрешности могут размещаться по обе стороны точки данных,

выше или ниже ее. Погрешность может определяться как фиксированное знаY

чение, относительное значение, заданное число стандартных отклонений,

стандартная погрешность, а также с помощью пользовательской формулы.

Как показано на рис. 10.16, прогнозируемый уровень продаж выходит за рамY

ки допустимой погрешности только в 1987 году.

Page 250: ? Применение VBA и макросов в Microsoft® Excel

250 Часть II Автоматизация Excel

Рис. 10.15. Добавление линии тренда с прогнозом на 5 периодов (лет) вперед

Рис. 10.16. Добавление полос погрешности

Page 251: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 251

Типы диаграмм В состав Excel входит множество встроенных диаграмм различных типов.

Типы и виды стандартных диаграмм Excel перечислены в табл. 10.1.

Таблица 10.1. Стандартные диаграммы Excel

Типдиаграммы

Вид диаграммы Константа VBA

Гистограмма Обычная гистограмма xlColumnClustered

Объемный вариант обычной

гистограммы

xl3DColumnClustered

Гистограмма с накоплением xlColumnStacked

Объемный вариант гистограммы

с накоплением

xl3DColumnStacked

Нормированная гистограмма с

накоплением

xlColumnStacked100

Объемный вариант нормироY

ванной гистограммы с накоплеY

нием

xl3DColumnStacked100

Трехмерная гистограмма xl3DColumn

Линейчатая

диаграмма

Обычная линейчатая диаграмма xlBarClustered

Объемный вариант обычной лиY

нейчатой диаграммы

xl3DBarClustered

Линейчатая диаграмма с накопY

лением

xlBarStacked

Объемный вариант линейчатой

диаграммы с накоплением

xl3DBarStacked

Нормированная линейчатая

диаграмма с накоплением

xlBarStacked100

Объемный вариант нормироY

ванной линейчатой диаграммы с

накоплением

xl3DBarStacked100

График Обычный график xlLine

Обычный график с маркерами xlLineMarkers

График с накоплением

xlLineStacked

Page 252: ? Применение VBA и макросов в Microsoft® Excel

252 Часть II Автоматизация Excel

Продолжение табл. 10.1

Типдиаграммы

Вид диаграммы Константа VBA

График с накоплением, на котоY

ром отдельные значения помеY

чены маркерами

xlLineMarkersStacked

Нормированный график с накоY

плением

xlLineStacked100

Нормированный график с накоY

плением, на котором отдельные

значения помечены маркерами

xlLineMarkersStacked100

Трехмерный график xl3DLine

Круговая

диаграмма

Обычная круговая диаграмма xlPie

Разрезанная круговая диаграмма xlPieExploded

Объемный вариант обычной

круговой диаграммы

xl3DPie

Объемный вариант разрезанной

круговой диаграммы

xl3DPieExploded

Вторичная круговая диаграмма

(обычная круговая диаграмма с

частью значений, вынесенными

во вторую круговую диаграмму)

xlPieOfPie

Вторичная гистограмма с накопY

лением (обычная круговая диаY

грамма с частью значений, выY

несенными в гистограмму с наY

коплением)

xlBarOfPie

Точечная

диаграмма

Обычная точечная диаграмма xlXYScatter

Точечная диаграмма со значеY

ниями, соединенными сглажиY

вающими линиями

xlXYScatterSmooth

Точечная диаграмма со значеY

ниями, соединенными сглажиY

вающими линиями без маркеров

xlXYScatterSmoothNoMarkers

Точечная диаграмма со значеY

ниями, соединенными отрезY

ками

xlXYScatterLines

Page 253: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 253

Продолжение табл. 10.1

Типдиаграммы

Вид диаграммы Константа VBA

Точечная диаграмма со значеY

ниями, соединенными отрезкаY

ми без маркеров

xlXYScatterLinesNoMarkers

Пузырьковая

диаграмма

Обычная пузырьковая диаграмма xlBubble

Объемный вариант обычной пуY

зырьковой диаграммы

xlBubble3DEffect

Диаграмма с

областями

Обычная диаграмма с областями xlArea

Объемный вариант обычной

диаграммы с областями

xl3DArea

Диаграмма с областями с накопY

лением

xlAreaStacked

Объемный вариант диаграммы с

областями с накоплением

xl3DAreaStacked

Нормированная диаграмма с обY

ластями с накоплением

xlAreaStacked100

Объемный вариант нормироY

ванной диаграммы с областями с

накоплением

xl3DAreaStacked100

Кольцевая

диаграмма

Обычная кольцевая диаграмма xlDoughnut

Разрезанная кольцевая диаY

грамма

xlDoughnutExploded

Лепестковая

диаграмма

Обычная лепестковая диаграмма xlRadar

Лепестковая диаграмма с маркеY

рами, которыми помечены знаY

чения данных

xlRadarMarkers

Заполненная лепестковая диаY

грамма

xlRadarFilled

Поверхностная

диаграмма

Обычная поверхностная диаY

грамма

xlSurface

Контурная диаграмма (вид сверY

ху на обычную поверхностную

диаграмму)

xlSurfaceTopView

Page 254: ? Применение VBA и макросов в Microsoft® Excel

254 Часть II Автоматизация Excel

Продолжение табл. 10.1

Типдиаграммы

Вид диаграммы Константа VBA

Проволочная (прозрачная) поY

верхностная диаграмма

xlSurfaceWireframe

Проволочная (прозрачная) конY

турная диаграмма (вид сверху на

проволочную (прозрачную) поY

верхностную диаграмму)

xlSurfaceTopViewWireframe

Биржевая

диаграмма

Биржевая диаграмма для набоY

ров из трех значений (самый выY

сокий курс, самый низкий курс,

курс закрытия)

xlStockHLC

Биржевая диаграмма для набоY

ров из четырех значений (объем,

самый высокий курс, самый

низкий курс, курс закрытия)

xlStockVHLC

Биржевая диаграмма для набоY

ров из четырех значений (курс

открытия, самый высокий курс,

самый низкий курс, курс закрыY

тия)

xlStockOHLC

Биржевая диаграмма для набоY

ров из пяти значений (объем,

курс открытия, самый высокий

курс, самый низкий курс, курс

закрытия)

xlStockVOHLC

ЦилиндриY

ческая диаY

грамма

Обычная гистограмма со столбY

цами в виде цилиндров

xlCylinderColClustered

Обычная линейчатая диаграмма

со столбцами в виде цилиндров

xlCylinderBarClustered

Гистограмма с накоплением со

столбцами в виде цилиндров

xlCylinderColStacked

Линейчатая диаграмма с накопY

лением со столбцами в виде циY

линдров

xlCylinderBarStacked

Нормированная гистограмма с

накоплением со столбцами в виY

де цилиндров

xlCylinderColStacked100

Page 255: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 255

Окончание табл. 10.1

Типдиаграммы

Вид диаграммы Константа VBA

Нормированная линейчатая диаY

грамма с накоплением со столбY

цами в виде цилиндров

xlCylinderBarStacked100

Трехмерная гистограмма со

столбцами в виде цилиндров

xlCylinderCol

Коническая

диаграмма

Обычная гистограмма со столбY

цами в виде конусов

xlConeColClustered

Обычная линейчатая диаграмма

со столбцами в виде конусов

xlConeBarClustered

Гистограмма с накоплением со

столбцами в виде конусов

xlConeColStacked

Линейчатая диаграмма с накоплеY

нием со столбцами в виде конусов

xlConeBarStacked

Нормированная гистограмма с

накоплением со столбцами в виде

конусов

xlConeColStacked100

Нормированная линейчатая диаY

грамма с накоплением со столбY

цами в виде конусов

xlConeBarStacked100

Трехмерная гистограмма со

столбцами в виде конусов

xlConeCol

ПирамидальY

ная диаграмма

Обычная гистограмма со столбY

цами в виде пирамид

xlPyramidColClustered

Обычная линейчатая диаграмма

со столбцами в виде пирамид

xlPyramidBarClustered

Гистограмма с накоплением со

столбцами в виде пирамид

xlPyramidColStacked

Линейчатая диаграмма с накоплеY

нием со столбцами в виде пирамид

xlPyramidBarStacked

Нормированная гистограмма с

накоплением со столбцами в виY

де пирамид

xlPyramidColStacked100

Нормированная линейчатая

диаграмма с накоплением со

столбцами в виде пирамид

xlPyramidBarStacked100

Трехмерная гистограмма со

столбцами в виде пирамид

xlPyramidCol

Page 256: ? Применение VBA и макросов в Microsoft® Excel

256 Часть II Автоматизация Excel

Не отчаивайтесь, взглянув на размеры этой таблицы. С практической точY

ки зрения цилиндрические, конические и пирамидальные диаграммы аналоY

гичны гистограммам, а линейчатые диаграммы YYYY это гистограммы, повернуY

тые на 90° по часовой стрелке.

В большинстве случаев разные виды диаграмм в пределах одного типа

отличаются значениями нескольких параметров. К примеру, единственное

отличие обычной точечной диаграммы (xlXYScatter) от точечной диаграмY

мы со значениями, соединенными отрезками (xlXYScatterLines), заклюY

чается в том, что параметр SeriesCollection(1).Border.LineStyleпоследней имеет значение xlAutomatic.

Параметры трехмерных и круговых диаграмм В этом разделе рассматриваются параметры, применимые только к трехY

мерным или круговым диаграммам.

Параметры трехмерных диаграмм

Все трехмерные диаграммы имеют параметры объемного вида, являющиеY

ся свойствами объекта Chart.

Elevation. Возвышение, с которого наблюдатель смотрит на диаY

грамму. Если значение параметра Elevation равно 0, наблюдатель не

видит верхнюю поверхность фигур. Если значение параметра Eleva-tion равно 90, наблюдатель смотрит на диаграмму сверху вниз.

Rotation. Этот параметр принимает значения в диапазоне от 0 до 359.

При небольшом значении угла поворота наблюдатель смотрит на диаY

грамму так, как если бы он находился справа от нее, а при значении угY

ла поворота, равном 330YY350, YYYY так, как если бы он находился слева от

нее. Чтобы развернуть диаграмму и посмотреть на нее сзади, испольY

зуйте значения параметра Rotation в диапазоне от 150 до 210.

Perspective. Этот параметр принимает значения в диапазоне от 0

до 100. Установка больших значений параметра Perspective привоY

дит к искривлению основания диаграммы.

DepthPercent. Глубина диаграммы в процентах от стандартной

глубины.

HeightPercent. Высота диаграммы в процентах от стандартной

высоты.

RightAngleAxes. Установка значения этого параметра равным Trueисключает возможность изменения перспективы диаграммы, что хаY

рактерно для линейчатых диаграмм.

Page 257: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 257

Объекты Walls (стенки) и Floor (основание) доступны только для трехY

мерных диаграмм. Эти объекты имеют одинаковые наборы настраиваемых

параметров, таких как цвет заливки, тип рамки и т.п.

Ниже перечислены параметры ряда данных трехмерной диаграммы.

GapWidth. Если ширина зазора равна 0, фигуры, представляющие на

диаграмме один ряд данных, соприкасаются друг с другом. Чем выше

ширина зазора, тем больше расстояние между фигурами. GapWidth —

это свойство объекта ChartGroup, представляющего все ряды данных

одинакового типа. Если один ряд данных на диаграмме представлен

трехмерными столбцами, а другой YYYY трехмерным графиком, то шириY

на зазора между столбцами будет определяться значением свойства

GapWidth объекта Columns3DGroup.

GapDepth. Если глубина зазора равна 0, фигуры, представляющие на

диаграмме соседние ряды данных, соприкасаются друг с другом. Чем

выше глубина зазора, тем больше расстояние между фигурами. НеY

смотря на то что глубину зазора можно определить посредством диаY

логового окна Формат ряда данных (Format Data Series), GapDepthявляется свойством объекта Chart.

ChartDepth. Если значение параметра ChartDepth равно 20, диаY

грамма выглядит очень плоской. Чем больше значение этого параметY

ра, тем больше глубина диаграммы. ChartDepth является свойством

объекта Chart.

Следующий макрос оперирует всеми рассмотренными выше параметрами.

Sub Format3D() Dim Cht As Chart Set Cht = Worksheets("Трехмерная _диаграмма").ChartObjects(1).Chart With Cht .Elevation = 30 .Perspective = 25 .Rotation = 30 .RightAngleAxes = False .HeightPercent = 150 .AutoScaling = True .DepthPercent = 280 .GapDepth = 160 End With Cht.Column3DGroup.GapWidth = 0 With Cht.Walls.Fill .TwoColorGradient Style:=msoGradientHorizontal, Variant:=1 .Visible = True .ForeColor.SchemeColor = 2 .BackColor.SchemeColor = 1 End With With Cht.Floor.Fill .PresetGradient Style:=msoGradientHorizontal, _Variant:=1, PresetGradientType:=msoGradientCalmWater .Visible = True

Page 258: ? Применение VBA и макросов в Microsoft® Excel

258 Часть II Автоматизация Excel

End WithEnd Sub

Результат выполнения макроса показан на рис. 10.17.

Рис. 10.17. Пример изменения параметров трехмерной диаграммы

Параметры круговых диаграмм

Один из недостатков круговых диаграмм состоит в возможности перекрыY

вания подписей данных, как показано на рис. 10.18.

К счастью, уникальные свойства круговой диаграммы могут помочь в реY

шении этой проблемы.

Если друг друга перекрывают всего две подписи данных, попробуйте измеY

нить угол поворота первой доли круговой диаграммы с помощью свойства

FirstSliceAngle. При этом становится очевидным фундаментальный неY

достаток создания диаграмм с помощью VBA. В VBA нет метода или свойства,

позволяющего судить о внешней привлекательности диаграммы. Выяснить

это можно, только взглянув на нее. Следующий макрос поворачивает диаY

грамму на 60° по часовой стрелке, в результате чего взаимное расположение

подписей данных становится вполне приемлемым.

Sub RotateFirstSlice() Dim Cht As Chart Set Cht = Worksheets("Круговая диаграмма").ChartObjects(1).Chart Cht.PieGroups(1).FirstSliceAngle = 60End Sub

Page 259: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 259

Рис. 10.18. Подписи данных круговой диаграммы могут перекрывать друг друга

Если же друг друга перекрывает много подписей данных, вынесите все доY

ли, не превышающие 5%, во вторичную гистограмму с накоплением:

Sub CreateBarOfPie() Dim Cht As Chart Dim CG As ChartGroup Set Cht = Worksheets("Круговая диаграмма").ChartObjects(1).Chart Cht.ChartType = xlBarOfPie Set CG = Cht.PieGroups(1) With CG .SplitType = xlSplitByPercentValue' Доли менее 5%. .SplitValue = 5' Зазор между основной и вторичной диаграммой. .GapWidth = 200' Размер вторичной диаграммы в % от основной. .SecondPlotSize = 55 End WithEnd Sub

Результат выполнения приведенного выше кода показан на рис. 10.19.

Совет Линии выносок, показанные на рис. 10.19, автоматически добавляются Excel, еслирасстояние между подписью данных и соответствующей ей долей на диаграммепревышает некоторую заданную величину. Чтобы запретить добавление линий выно&сок, установите значение свойства диаграммы HasLeaderLines равным False.

Page 260: ? Применение VBA и макросов в Microsoft® Excel

260 Часть II Автоматизация Excel

Рис. 10.19. Вторичная гистограмма с накоплением используется для выне&сения из круговой диаграммы долей, не превышающих 5%. В большинствеслучаев это позволяет избежать перекрывания подписей данных

Интерактивные диаграммы Рассмотрим использование VBA для создания интерактивных диаграмм.

События диаграмм

Одним из недостатков диаграмм является автоматическое изменение

внешнего вида диаграммы при обновлении исходных данных. Управлять изY

менением внешнего вида диаграммы помогут события. (Более подробно соY

бытия рассматривались в главе 8, ‘‘События’’.) Код обработки событий диаY

граммы, расположенной на отдельном рабочем листе, помещается в модуль

этого листа. Для обработки событий встроенной диаграммы необходимо созY

дать модуль класса. Ниже перечислены некоторые из наиболее часто испольY

зуемых событий диаграммы:

SeriesChange — срабатывает при обновлении ряда данных на диаY

грамме;

Calculate — срабатывает при изменении исходных данных диаграммы;

Activate — срабатывает при активизации диаграммы;

Deactivate — срабатывает при деактивизации диаграммы.

Page 261: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 261

Следующий макрос выполняется при каждом пересчете диаграммы

(например, при обновлении ряда данных). Если количество точек в ряде данY

ных с индексом 1 больше 5, отрезки, соединяющие точки данных, окрашиваY

ются в красный цвет, в противном случае YYYY в синий.

Private Sub Chart_Calculate() Dim Ser As Series Set Ser = Me.SeriesCollection(1) If Ser.Points.Count > 5 Then Ser.Border.ColorIndex = 5 Else Ser.Border.ColorIndex = 3 End IfEnd Sub

Экспорт диаграммы в файл изображения Экспортировать диаграмму в файл изображения формата GIF не составляY

ет никакого труда:

Sub SaveChart() Dim Cht As Chart Set Cht = Worksheets("Круговая диаграмма").ChartObjects(1).Chart Cht.Export Filename:=ThisWorkbook.Path & _Application.PathSeparator & "pie.gif", FilterName:="GIF"End Sub

Подобный шаг может иметь следующие мотивы.

Необходимость помещения диаграммы на Web/страницу. Создайте диаY

грамму, экспортируйте ее в файл и сошлитесь на него в тексте WebY

страницы, например, <Img src="MyChart.gif">.

Экономия системных ресурсов. Диаграммы занимают много места в

оперативной памяти компьютера. Если вам нужно отобразить 100 или

больше диаграмм, воспользуйтесь средствами VBA для создания кажY

дой отдельной диаграммы, ее сохранения в файле формата GIF и заY

грузки полученного файла в рабочую книгу. Ниже приведен код загрузY

ки файла изображения в рабочую книгу:

ActiveSheet.Pictures.Insert (ThisWorkbook.Path & _Application.PathSeparator & "pie.gif")

Необходимость помещения диаграммы на пользовательскую форму.Единственный способ помещения диаграммы на пользовательскую

форму заключается в ее загрузке из файла изображения. Ниже привеY

ден код загрузки файла изображения в элемент управления Image:

Me.Image1.Picture = LoadPicture(ThisWorkbook.Path & _Application.PathSeparator & "pie.gif")

Page 262: ? Применение VBA и макросов в Microsoft® Excel

262 Часть II Автоматизация Excel

Удивительные возможности точечных диаграммНесмотря на то, что по части построения чертежей Excel существенно усY

тупает таким ‘‘монстрам’’, как AutoCAD, вы будете приятно поражены, отY

крыв для себя удивительные возможности точечных диаграмм. На рис. 10.20

показан пример использования точечной диаграммы для построения логотипа

компании MrExcel Consulting.

Рис. 10.20. Для построения логотипа компании MrExcel Consulting с помощью точечнойдиаграммы понадобилось 15 точек данных

Идея использования точечных диаграмм для построения чертежей была

доведена до совершенства Малой Сингхом (Mala Singh) из компании XLSoft

Consulting (Индия). На рис. 10.21 показан один из его шедевров.

Создание нестандартных диаграммК сожалению, создание нестандартных диаграмм Excel с помощью VBA

выходит за рамки этой книги. Все диаграммы, приведенные в этом разделе,

были созданы с помощью VBA и используются с разрешения компании

XLSoft Consulting.

Круговая пузырьковая диаграмма

Внешний вид круговой пузырьковой диаграммы представлен на рис. 10.22.

Page 263: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 263

Рис. 10.21. Этот чертеж на самом деле является точечной диаграммойExcel. На его построение уходит около 25 с

Рис. 10.22. Круговая пузырьковая диаграмма

Пузырьковая диаграмма похожа на точечную диаграмму с добавлением

третьего ряда данных в виде диаметра пузырька. В свою очередь диаграмма,

показанная на рис. 10.22, является расширением пузырьковой диаграммы с

добавлением четвертого ряда данных, представленного в виде обычной кругоY

вой диаграммы. Круговая пузырьковая диаграмма строится с помощью цикла

Page 264: ? Применение VBA и макросов в Microsoft® Excel

264 Часть II Автоматизация Excel

по всем точкам четвертого ряда данных. Для каждой точки создается скрытая

круговая диаграмма, которая затем используется в качестве изображения соY

ответствующего пузырька.

Диаграмма с точками данных в виде спидометров

На рис. 10.23 показана диаграмма с точками данных в виде спидометров.

Рис. 10.23. Диаграмма с точками данных в виде спидометров

Диаграмма с точками данных в виде спидометров представляет собой изY

мененную точечную диаграмму с двумя автофигурами YYYY кругом для установY

ки внешнего периметра и циферблатом. Оставшаяся часть диаграммы предY

ставлена точкой и подписями данных. Шкала циферблата и цветовые зоны

являются полностью настраиваемыми. Несколько размещенных рядом спиY

дометров создают эффект приборной доски.

Каждый из спидометров, показанных на рис. 10.23, на самом деле является

изображением отдельной диаграммы. Макрос, создающий приборную доску,

генерирует диаграмму на основе данных таблицы Excel (одной строке данных

соответствует одна приборная доска), а затем использует ее для создания стаY

тического изображения. Наконец, полученные изображения спидометров

упорядочиваются на рабочем листе.

Диаграмма кривой предложения

Excel не позволяет создавать гистограммы со столбцами разной ширины.

В диаграмме, показанной на рис. 10.24, высота столбца определяет стоимость

товара, а ширина YYYY предлагаемое количество.

Диаграмма кривой предложения представляет собой точечную диаY

грамму с помещенными на область построения диаграммы цветными пряY

моугольниками, имитирующими столбцы данных. Ширина и размещение

прямоугольников подобраны так, чтобы они корректно отражали исходY

ные данные диаграммы.

Page 265: ? Применение VBA и макросов в Microsoft® Excel

Диаграммы Глава 10 265

Рис. 10.24. Диаграмма кривой предложения

Иерархическая кольцевая диаграмма

Иерархическая кольцевая диаграмма представляет собой комбинацию

круговой и кольцевой диаграммы. Отличительная особенность иерархической

кольцевой диаграммы заключается в том, что каждый ее уровень хранит инY

формацию о пропорции вложенного уровня. Подписи данных содержат знаY

чение и, при необходимости, его вклад (в процентах) в соответствующую долю

предыдущего уровня (рис. 10.25).

Рис. 10.25. Иерархическая кольцевая диаграмма

Page 266: ? Применение VBA и макросов в Microsoft® Excel

266 Часть II Автоматизация Excel

Следующий шагДиаграммы являются неотъемлемой частью всех программ для работы с

электронными таблицами, поскольку они позволяют получить наглядное

представление об исходных данных. Следующая глава посвящена анализу

данных с помощью расширенного фильтра.

Page 267: ? Применение VBA и макросов в Microsoft® Excel

Преимущества VBA передпользовательскиминтерфейсом Excel.......................267Использование расширенногофильтра для отборауникальных значений иззаданного диапазона................. 268Использование расширенногофильтра с указанием условияотбора данных..............................276Фильтрация диапазонаисходных данных “на месте” ...287Использование расширенногофильтра для копированиявсех записей,удовлетворяющих заданномуусловию ......................................... 289Автофильтр ...................................297Следующий шаг........................... 298

11Глава 11

Àíàëèç äàííûõñ ïîìîùüþðàñøèðåííîãîôèëüòðà

Преимущества VBAпередпользовательскиминтерфейсом Excel

Диалоговое окно Excel Расши-ренный фильтр (Advanced Filter) наY

столько неинтуитивно, что большинY

ство пользователей предпочитают

вообще не связываться с ним. ВероY

ятно, Microsoft полностью изменит

интерфейс расширенного фильтра в

следующей версии Excel.

С другой стороны, работа с расY

ширенным фильтром посредством

VBA может доставить истинное наY

слаждение. Всего одной строки кода

достаточно для извлечения подмноY

жества строк исходных данных или

отбора уникальных значений из заY

данного столбца!

При рассмотрении расширенных

фильтров в этой главе внимание буY

дет уделено как первому, так и втоY

рому способу их создания.

Одна из причин излишней сложноY

сти диалогового окна Расширенныйфильтр (рис. 11.1) обусловлена налиY

чием параметров фильтра.

Page 268: ? Применение VBA и макросов в Microsoft® Excel

268 Часть II Автоматизация Excel

Рис. 11.1. Диалоговое окно Расширенныйфильтр излишне сложно в использова&нии. К счастью, у нас есть VBA!

Способ обработки исходных данных. Чтобы показать результат фильтраY

ции, скрыв ненужные строки, установите переключатель Фильтроватьсписок на месте (Filter the list, inYplace). Чтобы скопировать отфильтY

рованные строки в другую область листа, установите переключатель

Скопировать результат в другое место (Copy to another location).

Условие отбора. Фильтрация с условием позволяет отобрать подмножеY

ство строк, а фильтрация без условия YYYY подмножество столбцов исY

ходного диапазона. Фильтрация без условия применяется также при

отборе только уникальных записей.

Отбор только уникальных записей. Установите флажок Толькоуникальные записи (Unique records only), для того чтобы отобрать только

уникальные значения из заданного диапазона.

Использование расширенного фильтра дляотбора уникальных значений из заданногодиапазона

Классический пример использования расширенного фильтра заключается

в отборе уникальных значений из заданного диапазона. Предположим, что наY

звания компанийYзаказчиков расположены в столбце D исходных данных.

Общее число записей неизвестно, однако известно, что данные начинаются с

ячейки A2 (1Yя строка используется в качестве строки заголовка). Справа от

исходных данных на рабочем листе находится пустое пространство.

Отбор уникальных значений из заданного столбца спомощью пользовательского интерфейса

Установите указатель ячейки в любом месте исходного диапазона и выберите

команду меню Данные Фильтр Расширенный фильтр (Data Filter Advanced

Page 269: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 269

Filter). При первом вызове этой команды Excel автоматически подставляет в поле

Исходный диапазон (List range) адрес исходного диапазона данных. При послеY

дующих вызовах команды Данные Фильтр Расширенный фильтр Excel подY

ставляет в поле Исходный диапазон его предыдущее значение.

Установите флажок Только уникальные записи (Unique records only), расY

положенный внизу диалогового окна Расширенный фильтр (Advanced Filter).

Установите переключатель Скопировать результат в другое место (Copy

to another location) и введите $J$1 в поле Поместить результат в диапазон(Copy to).

По умолчанию Excel копирует все столбцы исходного диапазона. Чтобы

ограничиться только столбцом D, можно сузить до него исходный диапазон

данных или скопировать заголовок столбца D в первую строку области вставки

результата. Каждый из способов имеет свои недостатки.

Сужение диапазона исходных данных до одного столбца

Введите в поле Исходный диапазон (List range) адрес диапазона исходных

данных, ограниченного столбцом D. В рассматриваемом случае это означает

замену адреса $A$1:$H$1127 адресом $D$1:$D$1127, как показано на

рис. 11.2.

Рис. 11.2. Сузьте диапазон исходных дан&ных до столбца D

Недостаток этого метода заключается в том, что Excel запоминает значение поY

ля Исходный диапазон и автоматически подставляет его при следующем вызове

команды Данные Фильтр Расширенный фильтр (Data Filter Advanced

Filter). Если позже вам понадобится отобрать уникальные значения из столбца C,

вам придется изменить адрес исходного диапазона.

Копирование заголовка столбца исходных данных в первую строкуобласти вставки результатов

Не спешите менять адрес исходного диапазона с $A$1:$H$1127 на

$D$1:$D$1127. Вместо этого введите в ячейке J1 заголовок столбца D, в данY

ном случае YYYY Заказчик (рис. 11.3).

Page 270: ? Применение VBA и макросов в Microsoft® Excel

270 Часть II Автоматизация Excel

Рис. 11.3. Чтобы не менять адрес исходного диапазона, скопируйте заголовок столбца D в ячейку J1

Обнаружив в первой строке области вставки результатов заголовок столбY

ца D, Excel скопирует исходные данные только из этого столбца. Этот способ

ограничения результата фильтрации рекомендуется применять при многоY

кратном использовании фильтра. Поскольку Excel запоминает значение поля

Исходный диапазон (List range) и автоматически подставляет его при слеY

дующем вызове команды Данные Фильтр Расширенный фильтр (Data

Filter Advanced Filter), вам не придется каждый раз изменять значение исY

ходного диапазона.

Результат отбора уникальных значений из столбца D показан на рис. 11.4.

Рис. 11.4. Отбор уникальных значений из заданного столбца — классический пример использо&вания расширенного фильтра

Page 271: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 271

Отбор уникальных значений из заданного столбцас помощью VBA

Команде Данные Фильтр Расширенный фильтр (Data Filter Advanced

Filter) соответствует метод VBA .AdvancedFilter. Этот метод имеет

3 параметра.

Способ обработки исходных данных. Чтобы показать результат фильтраY

ции, скрыв ненужные строки, установите значение параметра Actionравным xlFilterInPlace. Чтобы скопировать отфильтрованные строY

ки в другую область листа, установите значение параметра Action равY

ным xlFilterCopy. В последнем случае установите также значение паY

раметра CopyToRange, например, CopyToRange:=Range("J1").

Условие отбора. Чтобы задать условие фильтрации, установите значение

параметра CriteriaRange, например, CriteriaRange:=Range("L1:L2"). Для фильтрации без условия не указывайте значение

этого параметра.

Отбор только уникальных записей. Чтобы отобрать только уникальные

значения из заданного диапазона, установите значение параметра

Unique равным True.

Следующий код находит результат отбора уникальных значений из столбY

ца D и помещает его на два столбца правее последнего столбца исходного диаY

пазона данных.

Sub GetUniqueCustomers()

' Выделить рабочий лист. Worksheets("Данные").Select' Очистить результат предыдущего выполнения макроса. Range("J1:AZ1").EntireColumn.Delete

Dim IRange As Range Dim ORange As Range

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Копирование заголовка столбца D в 1-ю строку 1-го столбца' области вставки результатов.' Определение целевого диапазона данных. Range("D1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора

' уникальных значений из столбца D. IRange.AdvancedFilter Action:=xlFilterCopy, _

Page 272: ? Применение VBA и макросов в Microsoft® Excel

272 Часть II Автоматизация Excel

CopyToRange:=ORange, Unique:=True

End Sub

По умолчанию расширенный фильтр копирует все столбцы исходного

диапазона. Чтобы ограничиться только столбцом D, скопируйте его заголовок

в первую строку области вставки результата.

В первой части кода определяется размер исходного диапазона данных,

точнее YYYY последняя строка исходной области и первый столбец области

вставки результата. Несмотря на то, что в этом нет прямой необходимости,

адрес исходного и целевого диапазона сохраняется в объектных переменных

IRange и ORange, соответственно.

Макрос GetUniqueCustomers не требует внесения изменений в свой код

при добавлении к исходному диапазону данных новых столбцов. Основное

предназначение объектных переменных IRange и Orange состоит в повышеY

нии читабельности программного кода. Ниже приведен код макроса, не исY

пользующего объектные переменные и не обладающего универсальностью:

Sub UniqueCustomerRedux()' Копирование заголовка столбца D в ячейку J1. Range("J1").Value = Range("D1").Value' Применение расширенного фильтра для отбора' уникальных значений из столбца D. Range("A1").CurrentRegion.AdvancedFilter xlFilterCopy, _CopyToRange:=Range("J1"), Unique:=TrueEnd Sub

Результат выполнения обоих макросов одинаков YYYY справа от исходных

данных размещается список уникальных значений из столбца D (см. рис. 11.4).

Отсортируем полученный список и подсчитаем объем выручки, приходяY

щейся на каждого заказчика. Для этого воспользуемся формулой массива, как

показано ниже:

Sub RevenueByCustomers() Dim IRange As Range Dim ORange As Range

' Выделить рабочий лист. Worksheets("Данные").Select' Очистить результат предыдущего выполнения макроса. Range("J1:AZ1").EntireColumn.Delete

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Копирование заголовка столбца D в 1-ю строку 1-го столбца' области вставки результатов.' Определение целевого диапазона данных. Range("D1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора' уникальных значений из столбца D.

Page 273: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 273

IRange.AdvancedFilter Action:=xlFilterCopy, _CopyToRange:=ORange, Unique:=True

' Определение размера списка заказчиков. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка списка заказчиков. Cells(1, NextCol).Resize(LastRow, 1).Sort Key1:=Cells(1, _NextCol), Order1:=xlAscending, Header:=xlYes

' Подсчет выручки, приходящейся на каждого заказчика,' с помощью формулы массива. Cells(1, NextCol + 1).Value = "Выручка" Cells(2, NextCol + 1).FormulaArray = "=SUM((R2C4:R" & _FinalRow & "C4=RC[-1])*R2C6:R" & FinalRow & "C6)" If LastRow > 2 Then Cells(2, NextCol + 1).Copy Cells(3, _NextCol + 1).Resize(LastRow - 2, 1) End If

End Sub

Результат выполнения макроса представлен на рис. 11.5.

Список заказчиков может служить источником данY

ных для списка или комбинированного списка, располоY

женного на пользовательской форме. Создадим макрос,

позволяющий генерировать отчет о сделках для выбранY

ных заказчиков. Добавьте к проекту форму (назовем ее

frmReport), разместите на ней список (установите знаY

чение свойства списка MultiSelect равным frmMul-tiSelectMulti) и 4 кнопки YYYY OK, Отмена, Выбратьвсе и Очистить. Процедура UserForm_Initialize исY

пользуется для заполнения списка на форме данными,

полученными в результате отбора уникальных значений

из столбца D и их последующей сортировки.

Private Sub CancelButton_Click() Unload MeEnd Sub

Private Sub cbSubAll_Click() For i = 0 To lbCust.ListCount - 1 Me.lbCust.Selected(i) = True Next iEnd Sub

Private Sub cbSubClear_Click() For i = 0 To lbCust.ListCount - 1 Me.lbCust.Selected(i) = False Next iEnd Sub

Private Sub OKButton_Click() For i = 0 To lbCust.ListCount - 1 If Me.lbCust.Selected(i) = True Then' Создание отчета. RunCustReport WhichCust:=Me.lbCust.List(i)

Рис. 11.5. Подсчет вы&ручки, приходящейсяна каждого заказчика

Page 274: ? Применение VBA и макросов в Microsoft® Excel

274 Часть II Автоматизация Excel

End If Next i Unload MeEnd Sub

Private Sub UserForm_Initialize()

Dim IRange As Range Dim ORange As Range

' Выделить рабочий лист. Worksheets("Данные").Select' Очистить результат предыдущего выполнения макроса. Range("J1:AZ1").EntireColumn.Delete

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Копирование заголовка столбца D в 1-ю строку 1-го столбца' области вставки результатов.' Определение целевого диапазона данных. Range("D1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора' уникальных значений из столбца D. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:="", CopyToRange:=ORange, Unique:=True

' Определение размера списка заказчиков. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка списка заказчиков. Cells(1, NextCol).Resize(LastRow, 1).Sort _Key1:=Cells(1, NextCol), Order1:=xlAscending, Header:=xlYes

With Me.lbCust .RowSource = "" FinalRow = Range("J65536").End(xlUp).Row For Each cell In Cells(2, NextCol).Resize(LastRow - 1, 1) .AddItem cell.Value Next cell End With

' Удаление списка заказчиков. Cells(1, NextCol).Resize(LastRow, 1).ClearEnd Sub

Ниже приведен код вывода формы frmReport на экран:

Sub ShowCustForm() frmReport.ShowEnd Sub

Как показано на рис. 11.6, список заказчиков поддерживает множественY

ный выбор.

Page 275: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 275

Рис. 11.6. Использование расширенного фильтра —один из наиболее эффективных способов запол&нения списка на форме

Отбор уникальных значений из комбинации несколькихстолбцов с помощью VBA

Чтобы отобрать уникальные значения из комбинации нескольких столбY

цов, скопируйте заголовки этих столбцов в первую строку области вставки реY

зультата. Ниже приведен пример отбора уникальных значений из комбинации

столбцов B и D.

Sub UniqueCustomerProduct() Dim IRange As Range Dim ORange As Range

' Выделить рабочий лист. Worksheets("Данные").Select' Очистить результат предыдущего выполнения макроса. Range("J1:AZ1").EntireColumn.Delete

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Копирование заголовков столбцов B и D во 2-й и 1-й столбец' 1-й строки области вставки результатов, соответственно.' Определение целевого диапазона данных. Range("D1").Copy Destination:=Cells(1, NextCol) Range("B1").Copy Destination:=Cells(1, NextCol + 1)

Page 276: ? Применение VBA и макросов в Microsoft® Excel

276 Часть II Автоматизация Excel

Set ORange = Cells(1, NextCol).Resize(1, 2)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора уникальных' значений из комбинации столбцов B и D. IRange.AdvancedFilter Action:=xlFilterCopy, _CopyToRange:=ORange, Unique:=True

' Определение количества уникальных значений. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка полученного результата. Cells(1, NextCol).Resize(LastRow, 2).Sort Key1:=Cells(1, _NextCol), Order1:=xlAscending, Key2:=Cells(1, NextCol + 1), _Order2:=xlAscending, Header:=xlYes

End Sub

Как показано на рис. 11.7, компания BCD LTD приY

обрела всего один товар, зато компания CDE INC —

целых три.

На заметку Отбор уникальных значений из заданного диапазона —единственный пример использования расширенногофильтра без указания критерия фильтрации данных.

Использование расширенногофильтра с указанием условия отбораданных

Основное предназначение расширенного фильтра заY

ключается в фильтрации, т.е. отборе подмножества исY

ходных данных. Это достигается путем задания

диапазона условий.

Диапазон условий всегда включает в себя нескольY

ко строк. Первая строка содержит заголовки столбцов

исходного диапазона данных, вторая YYYY значения этих

столбцов, удовлетворяющие критерию отбора. На

рис. 11.8 показан диапазон условий J1:J2 и диапазон

вставки результата L1.

Рис. 11.7. Результат от&бора всех уникальныхкомбинаций значенийстолбцов B и D

Page 277: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 277

Рис. 11.8. Пример задания параметров расширенного фильтра, сортирующеготовары, приобретенные заказчиком CDE INC.

Чтобы отобрать товары, приобретенные заказчиком CDE INC., с помоY

щью пользовательского интерфейса Excel, выберите команду меню ДанныеФильтр Расширенный фильтр (Data Filter Advanced Filter) и заполните

поля открывшегося диалогового окна так, как показано на рис. 11.8. Результат

отбора представлен на рис. 11.9.

Рис. 11.9. Результат применения расширенного фильтра, сортирующего товары, приобретен&ные заказчиком CDE INC.

Аналогичных результатов можно достичь с помощью следующего макроса.

Sub UniqueProductsOneCustomer() Dim IRange As Range Dim ORange As Range Dim CRange As Range

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Определение столбца, по которому будет проводиться фильтрация. Cells(1, NextCol).Value = Range("D1").Value' В действительности, значение CDE INC. должно' вводиться посредством пользовательской формы.

Page 278: ? Применение VBA и макросов в Microsoft® Excel

278 Часть II Автоматизация Excel

Cells(2, NextCol).Value = "CDE INC." Set CRange = Cells(1, NextCol).Resize(2, 1)

' Определение целевого диапазона данных.' Копирование заголовка столбца B1 в столбец L1. Range("B1").Copy Destination:=Cells(1, NextCol + 2) Set ORange = Cells(1, NextCol + 2)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора уникальных' комбинаций товаров и заданного заказчика. IRange.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:= _CRange, CopyToRange:=ORange, Unique:=True' Приведенная выше строка может быть записана так:'IRange.AdvancedFilter xlFilterCopy, CRange, ORange, True

' Определение количества уникальных значений. LastRow = Cells(65536, NextCol + 2).End(xlUp).Row

' Сортировка полученного результата. Cells(1, NextCol + 2).Resize(LastRow, 1).Sort Key1:=Cells(1, _NextCol + 2), Order1:=xlAscending, Header:=xlYes

End Sub

Объединение нескольких условий с помощьюлогической операции “ИЛИ”

Расширенный фильтр позволяет отбирать значения, удовлетворяющие одY

ному из двух условий, с помощью логической операции ИЛИ. Примером поY

добного объединения условий является отбор заказчиков, которые приобрели

товар ABC или товар XYZ.

Чтобы объединить условия с помощью операции ‘‘ИЛИ’’, разместите их в

последовательных строках диапазона условий, как показано на рис. 11.10.

Объединение нескольких условий с помощью логическойоперации “И”

Расширенный фильтр позволяет отбирать значения, удовлетворяющие одY

новременно двум условиям, с помощью логической операции И. Примером

подобного объединения условий является отбор заказчиков, которые приобY

рели товар XYZ в западном регионе.

Чтобы объединить условия с помощью операции ‘‘И’’, разместите их в одY

ной строке диапазона условий, как показано на рис. 11.11.

Page 279: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 279

Рис. 11.10. Диапазон условий J1:J3 ис&пользуется для отбора заказчиков, ко&торые приобрели товар ABC или XYZ

Рис. 11.11. Диапазон условий J1:K2 использу&ется для отбора заказчиков, которые приоб&рели товар XYZ в западном регионе

Дополнительные аспекты объединения условийс помощью логической операции “ИЛИ”

Диапазон условий, показанный на рис. 11.12, основан на значении двух

различных полей, объединенных с помощью логической операции ‘‘ИЛИ’’.

Рис. 11.12. Диапазон условий J1:K3 использует&ся для отбора заказчиков из западного региона изаказчиков, которые приобрели товар XYZ

В результате применения расширенного фильтра будут отобраны заказчиY

ки из западного региона и заказчики, которые приобрели товар XYZ.

Задание условия отбора с помощью формулы

Диапазон условий может состоять из множества критериев, объединенных

с помощью логических операций. Неэффективность такого подхода становитY

ся все более очевидной при увеличении числа критериев. Однако Excel позвоY

ляет задавать условие отбора с помощью формулы.

Практикум

Задание сложного условия отбораСоздадим усовершенствованный вариант формы создания отчета на базе формыfrmReport. Новая форма позволяет создавать отчет о сделках для выбранногозаказчика, товара, региона или их комбинации, как показано на рис. 11.13.Предположим, что пользователь выбрал двух заказчиков и два товара. Соответст&вующий диапазон условий состоит из 5 строк, что вполне приемлемо (рис. 11.14).А теперь представьте, что на некотором диапазоне исходных данных пользова&тель выбрал 10 товаров, 9 регионов и 499 заказчиков. Поскольку диапазон ус&ловий должен содержать все возможные комбинации значений полей, по кото&рым проводится отбор, его размер превысит 44 000 строк. Попробуйте создать

Page 280: ? Применение VBA и макросов в Microsoft® Excel

280 Часть II Автоматизация Excel

подобный фильтр, и вы вскоре поймете, что на его применение может уйти це&лая вечность.Чтобы не ждать так долго, задайте условие отбора с помощью формулы.

Рис. 11.13. Создание диапазона условий для такой формы может превратить&

ся в настоящий кошмар

Рис. 11.14. Диапазон условий J1:K5 исполь&

зуется для отбора заказчиков, которые при&обрели либо товар DEF, либо товар XYZ

Использование формул в качестве условия отборарасширенного фильтра

Существует альтернативная форма диапазона условий, в соответствии

с которой его первая строка (строка заголовка) остается пустой, а во второй

строке размещается булева формула. Если последняя содержит относительные

ссылки на вторую строку диапазона исходных данных, Excel автоматически

применяет формулу ко всем строкам диапазона.

Page 281: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 281

Рассмотрим задачу отбора всех записей, для которых процент валовой приY

были не превышает 53%. Оставим ячейку J1 пустой, а в ячейку J2 поместим

булеву формулу =(H2/F2)<0.53. Диапазон условий расширенного фильтра

при этом нужно задать как J1:J2.

Применяя фильтр, Excel вычислит формулу для каждой строки исходного диаY

пазона и отберет те из них, для которых значение формулы будет равным True.

Использование формулы в качестве условия отбора расширенного

фильтра чрезвычайно эффективно. К тому же, формулы можно объединять

с помощью логических операций ‘‘И’’ и ‘‘ИЛИ’’ подобно объединению

обычных условий отбора.

Практикум

Задание диапазона условий на основе формулс помощью пользовательского интерфейсаПродемонстрируем создание диапазона условий на основе формул для задачи,рассмотренной в предыдущем практикуме.Скопируйте несколько названий фирм&заказчиков в столбец, расположенныйсправа от диапазона условий (например, в столбец O). Выделите полученный спи&сок и присвойте ему имя (например, MyCust). Введите в ячейку J2, принадлежа&щую диапазону условий, следующую формулу:=НЕ(ЕНД(ПОИСКПОЗ(D2;MyCust;ЛОЖЬ)))(В англоязычной версии Excel следует использовать формулу =NOT(ISNA(Match(D2,MyCust,False))).)Скопируйте несколько названий товаров в столбец, расположенный справа отдиапазона MyCust (например, в столбец P). Выделите полученный список и при&свойте ему имя (например, MyProd). Введите в ячейку K2, принадлежащую диа&пазону условий, следующую формулу:=НЕ(ЕНД(ПОИСКПОЗ(B2;MyProd;ЛОЖЬ)))(В англоязычной версии Excel следует использовать формулу =NOT(ISNA(Match(B2,MyProd,False))).)Наконец, скопируйте несколько названий регионов в столбец, расположенныйсправа от диапазона MyProd (например, в столбец Q). Выделите полученный спи&сок и присвойте ему имя (например, MyRegion). Введите в ячейку L2, принадле&жащую диапазону условий, следующую формулу:=НЕ(ЕНД(ПОИСКПОЗ(A2;MyRegion;ЛОЖЬ)))(В англоязычной версии Excel следует использовать формулу =NOT(ISNA(Match(A2,MyRegion,False))).)Задав диапазон условий расширенного фильтра как J1:L2, вы сможете отобратьстроки исходного диапазона, соответствующие любой комбинации значений диа&пазонов MyCust, MyProd и MyRegion.

Page 282: ? Применение VBA и макросов в Microsoft® Excel

282 Часть II Автоматизация Excel

Задание диапазона условий на основе формул с помощью VBA

Ниже приведен код усовершенствованного варианта формы для создания

отчета. Обратите внимание на метод OKButton_Click, создающий диапазон

условий на основе формул.

Private Sub CancelButton_Click() Unload MeEnd Sub

Private Sub cbSubAll_Click()' Выделить всех заказчиков. For i = 0 To lbCust.ListCount - 1 Me.lbCust.Selected(i) = True Next iEnd Sub

Private Sub cbSubClear_Click()' Отменить выделение заказчиков. For i = 0 To lbCust.ListCount - 1 Me.lbCust.Selected(i) = False Next iEnd Sub

Private Sub CommandButton1_Click()' Отменить выделение товаров. For i = 0 To lbProduct.ListCount - 1 Me.lbProduct.Selected(i) = False Next iEnd Sub

Private Sub CommandButton2_Click()' Выделить все товары. For i = 0 To lbProduct.ListCount - 1 Me.lbProduct.Selected(i) = True Next iEnd Sub

Private Sub CommandButton3_Click()' Отменить выделение регионов. For i = 0 To lbRegion.ListCount - 1 Me.lbRegion.Selected(i) = False Next iEnd Sub

Private Sub CommandButton4_Click()' Выделить все регионы. For i = 0 To lbRegion.ListCount - 1 Me.lbRegion.Selected(i) = True Next iEnd Sub

Private Sub OKButton_Click() Dim CRange As Range, IRange As Range, ORange As Range' Создание сложного условия, состоящего из нескольких' условий, объединенных с помощью логического И. NextCCol = 10 NextTCol = 15

Page 283: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 283

For j = 1 To 3 Select Case j Case 1 MyControl = "lbCust" MyColumn = 4 Case 2 MyControl = "lbProduct" MyColumn = 2 Case 3 MyControl = "lbRegion" MyColumn = 1 End Select NextRow = 2' Проверка выбора пользователя. For i = 0 To Me.Controls(MyControl).ListCount - 1 If Me.Controls(MyControl).Selected(i) = True Then Cells(NextRow, NextTCol).Value = _Me.Controls(MyControl).List(i) NextRow = NextRow + 1 End If Next i' Создание новой формулы условия. If NextRow > 2 Then' Использование относительных ссылок на строку R2 обязательно.' В англоязычной версии Excel:' MyFormula = "=NOT(ISNA(MATCH(RC" & MyColumn & ",R2C" & _' NextTCol & ":R" & NextRow - 1 & "C" & NextTCol & ",False)))"' Cells(2, NextCCol).FormulaR1C1 = MyFormula MyFormula = "=НЕ(ЕНД(ПОИСКПОЗ(RC" & _MyColumn & ";R2C" & NextTCol & ":R" & NextRow - 1 & "C" & _NextTCol & ";Ложь)))" Cells(2, NextCCol).FormulaR1C1Local = MyFormula NextTCol = NextTCol + 1 NextCCol = NextCCol + 1 End If Next j Unload Me

' На рис. 11.15 показано текущее содержимое рабочего листа.' Закрыть форму и создать расширенный фильтр с диапазоном' условий на основе построенных выше формул. If NextCCol > 10 Then Set CRange = Range(Cells(1, 10), Cells(2, NextCCol - 1)) Set IRange = Range("A1").CurrentRegion Set ORange = Cells(1, 20) IRange.AdvancedFilter xlFilterCopy, CRange, ORange

' Очистить диапазон условий. Cells(1, 10).Resize(1, 10).EntireColumn.Clear End If

' Вывести сообщение. MsgBox "Область вставки результата применения фильтра _начинается с ячейки T1"

End Sub

Page 284: ? Применение VBA и макросов в Microsoft® Excel

284 Часть II Автоматизация Excel

Private Sub UserForm_Initialize() Dim IRange As Range Dim ORange As Range

' Определение размера диапазона исходных данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Определение целевого диапазона данных.' Копирование заголовка столбца D1 в столбец J1. Range("D1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Применение расширенного фильтра для отбора' уникальных значений из столбца D. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:="", CopyToRange:=ORange, Unique:=True

' Определение размера списка заказчиков. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка списка заказчиков. Cells(1, NextCol).Resize(LastRow, 1).Sort Key1:=Cells(1, _NextCol), Order1:=xlAscending, Header:=xlYes

With Me.lbCust .RowSource = "" FinalRow = Range("J65536").End(xlUp).Row For Each cell In Cells(2, NextCol).Resize(LastRow - 1, 1) .AddItem cell.Value Next cell End With

' Удаление списка заказчиков. Cells(1, NextCol).Resize(LastRow, 1).Clear

' Определение целевого диапазона данных.' Копирование заголовка столбца B1 в столбец J1. Range("B1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Применение расширенного фильтра для отбора' уникальных значений из столбца B. IRange.AdvancedFilter Action:=xlFilterCopy, _CopyToRange:=ORange, Unique:=True

' Определение размера списка товаров. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка списка товаров. Cells(1, NextCol).Resize(LastRow, 1).Sort Key1:=Cells(1, _NextCol), Order1:=xlAscending, Header:=xlYes

With Me.lbProduct .RowSource = ""

Page 285: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 285

FinalRow = Range("J65536").End(xlUp).Row For Each cell In Cells(2, NextCol).Resize(LastRow - 1, 1) .AddItem cell.Value Next cell End With

' Удаление списка товаров. Cells(1, NextCol).Resize(LastRow, 1).Clear

' Определение целевого диапазона данных.' Копирование заголовка столбца A1 в столбец J1. Range("A1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Применение расширенного фильтра для отбора' уникальных значений из столбца A. IRange.AdvancedFilter Action:=xlFilterCopy, _CopyToRange:=ORange, Unique:=True

' Определение размера списка регионов. LastRow = Cells(65536, NextCol).End(xlUp).Row

' Сортировка списка регионов. Cells(1, NextCol).Resize(LastRow, 1).Sort Key1:=Cells(1, _NextCol), Order1:=xlAscending, Header:=xlYes

With Me.lbRegion .RowSource = "" FinalRow = Range("J65536").End(xlUp).Row For Each cell In Cells(2, NextCol).Resize(LastRow - 1, 1) .AddItem cell.Value Next cell End With

' Удаление списка регионов. Cells(1, NextCol).Resize(LastRow, 1).Clear

End Sub

На рис. 11.15 показано содержимое рабочего листа перед выполнением меY

тода AdvancedFilter.

Макрос помещает выбранные пользователем данные (заказчиков, товары и

регионы) в столбцы O, P и Q, а затем определяет диапазон условий как J1:L2.

Формула в ячейке J2 проверяет, входит ли значение в ячейке $D2 в список заY

казчиков в столбце O. Формулы в ячейках K2 и L2 осуществляют аналогичную

проверку для ячеек $B2, $A2 и столбцов P, Q, соответственно.

Внимание В справочной системе Excel VBA сказано, что для отбора данных без примененияусловия достаточно не задать диапазон условий. В Excel 2003 это не так — если выне определите диапазон условий, метод AdvancedFilter будет использоватьзначение CriteriaRange, заданное при предыдущем вызове этого метода. Что&бы избежать недоразумений, очистите значение CriteriaRange, например,укажите CriteriaRange="" при вызове метода AdvancedFilter.

Page 286: ? Применение VBA и макросов в Microsoft® Excel

286 Часть II Автоматизация Excel

Рис. 11.15. Содержимое рабочего листа перед применением расширенного фильтра

Использование условия на основе формулы при решенииэкономических задач

Следует признать, что задание диапазона условий расширенного фильтра

с помощью формулы YYYY эффективное, но редко используемое решение.

В свете этого необходимо упомянуть об одном его весьма интересном приY

менении. Ниже приведена формула, позволяющая отобрать строки, значеY

ние в столбце A которых больше среднего значения по этому столбцу на всем

диапазоне исходных данных:

=$A2>СРЗНАЧ($A$2:$A$60000)

(В англоязычной версии Excel следует использовать формулу =$A2>AVERAGE($A$2:$A$60000).)

Отбор пустого множества записей

Условие расширенного фильтра может быть задано таким образом, что в

результате применения последнего будет отобрано пустое множество записей.

Чтобы определить данную ситуацию, достаточно найти номер последней

строки области вставки результата YYYY если он равен 1 (другими словами, обY

ласть вставки результата содержит только строку заголовков столбцов), сообY

щите пользователю о том, что его запрос оказался безуспешным и выйдите из

процедуры.

Page 287: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 287

Фильтрация диапазона исходных данных“на месте”

При фильтрации диапазона исходных данных ‘‘на месте’’ нет нужды укаY

зывать область вставки результата применения фильтра. А вот задание диапаY

зона условий является обязательным YYYY в противном случае фильтр отберет

100% исходных строк.

Обычно фильтрация ‘‘на месте’’ выполняется с помощью пользовательY

ского интерфейса Excel. Чтобы выделить строки, отобранные в результате

фильтрации ‘‘на месте’’, необходимо использовать метод VBA SpecialCellsс параметром xlCellTypeVisible. Аналогичное действие в пользовательY

ском интерфейсе Excel заключается в выборе команды Правка Перейти(Edit Go To), щелчке на кнопке Выделить (Special) в диалоговом окне

Переход (Go To) и установке переключателя Только видимые ячейки (Visible

cells only) в диалоговом окне Выделение группы ячеек (Go To Special)

(рис. 11.16).

Рис. 11.16. Фильтрация “на месте” позволяет скрыть строки, не удовлетворяю&щие заданному условию. Чтобы выделить строки, отобранные в результатефильтрации “на месте”, необходимо использовать метод VBA SpecialCells спараметром xlCellTypeVisible

Чтобы применить фильтр ‘‘на месте’’, вызовите метод AdvancedFilter,

установив значение параметра Action равным xlFilterInPlace и опустив

параметр CopyToRange, как показано ниже:

IRange.AdvancedFilter Action:=xlFilterInPlace, _CriteriaRange:=CRange, Unique:=False

Page 288: ? Применение VBA и макросов в Microsoft® Excel

288 Часть II Автоматизация Excel

Следующий код подсчитывает количество видимых строк в исходном диаY

пазоне данных после применения фильтрации ‘‘на месте’’:

For Each cell In Range("A2:A" & FinalRow).SpecialCells( _xlCellTypeVisible) Ctr = Ctr + 1Next cellMsgBox Ctr & " строк удовлетворяют заданному критерию"

Отбор пустого множества записей

Условие расширенного фильтра может быть задано таким образом, что в реY

зультате применения последнего будет отобрано пустое множество записей.

Чтобы определить данную ситуацию при фильтрации ‘‘на месте’’, следует проY

верить, возвращает ли метод SpecialCells ошибку времени выполнения 1004

(не найдено ни одной ячейки, удовлетворяющей заданным условиям).

Для этого воспользуемся универсальной ловушкой ошибок, как показано

ниже. (Более подробно обработка ошибок рассматривается в главе 23,

‘‘Обработка ошибок’’.)

On Error GoTo NoRecs For Each cell In Range("A2:A" & FinalRow).SpecialCells( _xlCellTypeVisible) Ctr = Ctr + 1 Next cell On Error GoTo 0 MsgBox Ctr & " строк удовлетворяют заданному критерию" Range("A1").Select Exit SubNoRecs: MsgBox "Нет строк, удовлетворяющих заданному критерию"

Чтобы подобная ловушка сработала, следует исключить строку заголовка

из диапазона ячеек, передаваемого методу SpecialCells. В противном слуY

чае метод SpecialCells не сгенерирует ошибку 1004, поскольку строка заY

головка остается видимой и после применения расширенного фильтра.

Отображение записей, скрытых в результатефильтрации “на месте”

Чтобы отобразить все строки исходного диапазона, скрытые в результате

применения расширенного фильтра ‘‘на месте’’, воспользуйтесь методом

ShowAllData, как показано ниже:

ActiveSheet.ShowAllData

Отбор только уникальных записейпри фильтрации “на месте”

В результате отбора только уникальных записей при фильтрации ‘‘на месY

те’’ расширенный фильтр скроет строки, в которых одинаковыми являются

Page 289: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 289

значения всех столбцов исходного диапазона. Другими словами, фильтрация

‘‘на месте’’ не позволяет отобрать строки с уникальной комбинацией только

некоторого подмножества столбцов исходного диапазона, например, столбца

с названием фирмыYзаказчика и столбца с наименованием товара.

Использование расширенного фильтра длякопирования всех записей, удовлетворяющихзаданному условию

Ранее в этой главе рассматривался отбор уникальных значений из исходY

ного диапазона данных и их копирование в другую область рабочего листа.

В частности, составлялись списки заказчиков, регионов и товаров, которые

затем использовались при заполнении соответствующих списков на форме.

Тем не менее, в повседневной жизни расширенный фильтр обычно исY

пользуется для отбора всех записей, удовлетворяющих определенному услоY

вию. Например, при генерации отчета о сделках фильтр возвращает все запиY

си, соответствующие выбранным пользователем заказчикам.

Чтобы отобрать все записи, удовлетворяющие заданному критерию,

сбросьте флажок Только уникальные записи (Unique records only) в диалогоY

вом окне Расширенный фильтр (Advanced Filter) (если расширенный фильтр

создается с помощью пользовательского интерфейса Excel) или установите

значение параметра Unique метода AdvancedFilter равным False (если

расширенный фильтр создается с помощью VBA).

Если требуется отобрать только подмножество столбцов исходного диапаY

зона данных, скопируйте их заголовки в первую строку области вставки реY

зультата фильтрации, при необходимости изменив порядок их следования.

В следующих разделах рассматриваются различные примеры использоваY

ния расширенного фильтра.

Копирование всех столбцов исходного диапазона данных

Чтобы скопировать все столбцы строк, удовлетворяющих заданному услоY

вию, укажите в качестве области вставки результата пустую ячейку.

Sub AllColumnsOneCustomer() Dim IRange As Range Dim ORange As Range Dim CRange As Range

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Определение столбца, по которому будет проводиться фильтрация. Cells(1, NextCol).Value = Range("D1").Value' В действительности, значение CDE INC. должно' вводиться посредством пользовательской формы.

Page 290: ? Применение VBA и макросов в Microsoft® Excel

290 Часть II Автоматизация Excel

Cells(2, NextCol).Value = "CDE INC." Set CRange = Cells(1, NextCol).Resize(2, 1)

' Определение целевого диапазона данных (пустая ячейка). Set ORange = Cells(1, NextCol + 2)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора строк,' удовлетворяющих заданному условию. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:=CRange, CopyToRange:=ORange Range("L1").Select

End Sub

Результат выполнения приведенного выше макроса показан на рис. 11.17.

Рис. 11.17. Указав пустую ячейку в качестве области вставки результата приме&нения расширенного фильтра, вы получите все столбцы строк, удовлетворяю&щих заданному условию

Копирование и переупорядочивание подмножествастолбцов исходного диапазона данных

Применяя расширенный фильтр для создания отчета, вы, вероятно, захоY

тите включить в последний только некоторые столбцы исходного диапазона

данных.

Возвратимся к форме frmReport, рассматривавшейся ранее в этой главе.

Форма frmReport предназначается для создания отчета о сделках для выY

бранных пользователем заказчиков. Создание отчета осуществляется с помоY

щью процедуры RunCustReport, которая принимает в качестве параметра

имя заказчика.

Предположим, что по определенным соображениям в отчет нужно

включить только столбцы Дата, Количество, Товар и Выручка (в укаY

занном порядке).

Следующий код копирует соответствующие заголовки столбцов в первую

строку области вставки результата применения расширенного фильтра. Метод

AdvancedFilter отбирает строки, удовлетворяющие заданному условию,

как показано на рис. 11.18.

Page 291: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 291

Рис. 11.18. Содержимое рабочего листа после применения расширенного фильтра

После этого процедура RunCustReport копирует отобранные строки в

новую рабочую книгу, добавляет заголовок отчета, итоговую строку и сохраY

няет рабочую книгу в файле с именем, совпадающим с названием соответстY

вующей фирмыYзаказчика. Пример отчета о сделках для заказчика CDE INC.

показан на рис. 11.19.

Рис. 11.19. Отчет о сделках для заказчика CDE INC.

Sub RunCustReport(WhichCust As Variant) Dim IRange As Range Dim ORange As Range Dim CRange As Range Dim WBN As Workbook Dim WSN As Worksheet Dim WSO As Worksheet

Set WSO = ActiveSheet' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Определение условия отбора. Cells(1, NextCol).Value = Range("D1").Value Cells(2, NextCol).Value = WhichCust Set CRange = Cells(1, NextCol).Resize(2, 1)

Page 292: ? Применение VBA и макросов в Microsoft® Excel

292 Часть II Автоматизация Excel

' Определение целевого диапазона данных.' В целевой диапазон войдут столбцы C (Дата),' E (Количество), B (Товар) и F (Выручка). Cells(1, NextCol + 2).Resize(1, 4).Value = Array(Cells(1, _3), Cells(1, 5), Cells(1, 2), Cells(1, 6)) Set ORange = Cells(1, NextCol + 2).Resize(1, 4)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора строк,' удовлетворяющих заданному условию. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:=CRange, CopyToRange:=ORange

' Содержимое рабочего листа на текущий

' момент показано на рис. 11.18.

' Создание новой рабочей книги для размещения' результата применения расширенного фильтра. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSN = WBN.Worksheets(1)

' Определение заголовка отчета. WSN.Cells(1, 1).Value = "Отчет о сделках для заказчика " _& WhichCust

' Копирование данных с текущего активного' рабочего листа в новую рабочую книгу. WSO.Cells(1, NextCol + 2).CurrentRegion.Copy _Destination:=WSN.Cells(3, 1) TotalRow = WSN.Cells(65536, 1).End(xlUp).Row + 1 WSN.Cells(TotalRow, 1).Value = "Всего"' В англоязычной версии Excel: ' WSN.Cells(TotalRow, 2).FormulaR1C1 = "=SUM(R2C:R[-1]C)" ' WSN.Cells(TotalRow, 4).FormulaR1C1 = "=SUM(R2C:R[-1]C)" WSN.Cells(TotalRow, 2).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)" WSN.Cells(TotalRow, 4).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)"

' Стилевое форматирование отчета. WSN.Cells(3, 1).Resize(1, 4).Font.Bold = True WSN.Cells(TotalRow, 1).Resize(1, 4).Font.Bold = True WSN.Cells(1, 1).Font.Size = 18

WBN.SaveAs "C:\" & WhichCust & ".xls" WBN.Close SaveChanges:=False

WSO.Select

' Очистить область вставки результата' применения расширенного фильтра. Range("J1:Z1").EntireColumn.Clear

End Sub

Page 293: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 293

Процедура RunCustReport — это простой, однако весьма эффективный

способ создания отчетов, который может применить на практике любой польY

зователь Excel.

Практикум

Использование двух расширенных фильтровдля создания отчетов по каждому заказчикуРассмотрим итоговый макрос, применяющий два расширенных фильтра различ&ного типа для создания отчетов по каждому заказчику.1. Первый расширенный фильтр используется для создания списка заказчиков

в столбце J. Параметр Unique метода AdvancedFilter имеет значение True,а параметр CopyToRange содержит ссылку на ячейку J1, содержащую заголо&вок столбца D.' Первый расширенный фильтр - создание' списка заказчиков в столбце J.' Определение целевого диапазона.' Копирование заголовка столбца D в ячейку J1.Range("D1").Copy Destination:=Cells(1, NextCol)Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных.Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора' уникальных значений из столбца D.IRange.AdvancedFilter Action:=xlFilterCopy, CriteriaRange:="", _CopyToRange:=ORange, Unique:=True

2. Для каждого заказчика из списка выполняются действия, описанные в пп. 3–7.Приведенный ниже код определяет размер списка заказчиков и реализует со&ответствующий цикл.

' Цикл по списку заказчиков.FinalCust = Cells(65536, NextCol).End(xlUp).RowFor Each cell In Cells(2, NextCol).Resize(FinalCust - 1, 1) ThisCust = cell.Value' Выполнение действий, описанных в пп. 3-7.Next Cell

3. Условие отбора второго расширенного фильтра содержится в ячейках L1:L2(заголовок столбца D в ячейке L1, имя заказчика — в ячейке L2).

' Определение условия отбора.Cells(1, NextCol + 2).Value = Range("D1").ValueCells(2, NextCol + 2).Value = ThisCustSet CRange = Cells(1, NextCol + 2).Resize(2, 1)

4. Второй расширенный фильтр используется для копирования строк, удовлетво&ряющих заданному условию, в область, начинающуюся со столбца N. ПараметрUnique метода AdvancedFilter имеет значение False, а параметр CopyTo-Range представляет собой ссылку на диапазон ячеек N1:Q1, содержащий заго&ловки необходимых столбцов исходного диапазона данных.

Page 294: ? Применение VBA и макросов в Microsoft® Excel

294 Часть II Автоматизация Excel

' Определение целевого диапазона данных.' В целевой диапазон войдут столбцы C (Дата),' E (Количество), B (Товар) и F (Выручка).Cells(1, NextCol + 4).Resize(1, 4).Value = Array(Cells(1, 3), _Cells(1, 5), Cells(1, 2), Cells(1, 6))Set ORange = Cells(1, NextCol + 4).Resize(1, 4)

' Второй расширенный фильтр - отбор строк,' удовлетворяющих заданному условию.IRange.AdvancedFilter Action:=xlFilterCopy,CriteriaRange:=CRange, CopyToRange:=ORange

5. Результат применения второго расширенного фильтра копируется в новую ра&бочую книгу. Для создания рабочей книги используется метод Work-books.Add.

' Создание новой рабочей книги для размещения' результата применения расширенного фильтра.Set WBN = Workbooks.Add(xlWBATWorksheet)Set WSN = WBN.Worksheets(1)

' Определение заголовка отчета.WSN.Cells(1, 1).Value = "Отчет о сделках заказчика " & ThisCust

' Копирование данных с текущего активного' рабочего листа в новую рабочую книгу.WSO.Cells(1, NextCol + 4).CurrentRegion.Copy _Destination:=WSN.Cells(3, 1)

6. Последний штрих — добавление заголовка отчета и итоговой строки. Вдобавок,строка заголовков столбцов и итоговая строка выделяются полужирнымшрифтом.

' Определение заголовка отчета.WSN.Cells(1, 1).Value = "Отчет о сделках заказчика " & ThisCustTotalRow = WSN.Cells(65536, 1).End(xlUp).Row + 1WSN.Cells(TotalRow, 1).Value = "Всего"' В англоязычной версии Excel:' WSN.Cells(TotalRow, 2).FormulaR1C1 = "=SUM(R2C:R[-1]C)"' WSN.Cells(TotalRow, 4).FormulaR1C1 = "=SUM(R2C:R[-1]C)"WSN.Cells(TotalRow, 2).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)"WSN.Cells(TotalRow, 4).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)"

' Стилевое форматирование отчета.WSN.Cells(3, 1).Resize(1, 4).Font.Bold = TrueWSN.Cells(TotalRow, 1).Resize(1, 4).Font.Bold = TrueWSN.Cells(1, 1).Font.Size = 18

7. Новая рабочая книга сохраняется в файле с именем, совпадающим с названиемсоответствующей фирмы&заказчика, после чего эта книга закрывается. Передпереходом к следующей итерации цикла макрос очищает область вставки ре&зультата выполнения обоих расширенных фильтров.WBN.SaveAs "C:\" & ThisCust & ".xls"WBN.Close SaveChanges:=False

WSO.SelectSet WSN = NothingSet WBN = Nothing

Page 295: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 295

' Очистить область вставки результата' применения расширенных фильтров.Cells(1, NextCol + 2).Resize(1, 10).EntireColumn.Clear

Ниже приведен полный код макроса RunReportForEachCustomer.Sub RunReportForEachCustomer() Dim IRange As Range Dim ORange As Range Dim CRange As Range Dim WBN As Workbook Dim WSN As Worksheet Dim WSO As Worksheet

Set WSO = ActiveSheet' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Первый расширенный фильтр - создание' списка заказчиков в столбце J.' Определение целевого диапазона.' Копирование заголовка столбца D в ячейку J1. Range("D1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора' уникальных значений из столбца D. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:="", CopyToRange:=ORange, Unique:=True

FinalCust = Cells(65536, NextCol).End(xlUp).Row' Цикл по списку заказчиков. For Each cell In Cells(2, NextCol).Resize(FinalCust - 1, 1) ThisCust = cell.Value

' Определение условия отбора. Cells(1, NextCol + 2).Value = Range("D1").Value Cells(2, NextCol + 2).Value = ThisCust Set CRange = Cells(1, NextCol + 2).Resize(2, 1)

' Определение целевого диапазона данных.' В целевой диапазон войдут столбцы C (Дата),' E (Количество), B (Товар) и F (Выручка). Cells(1, NextCol + 4).Resize(1, 4).Value = _Array(Cells(1, 3), Cells(1, 5), Cells(1, 2), Cells(1, 6)) Set ORange = Cells(1, NextCol + 4).Resize(1, 4)

' Второй расширенный фильтр - отбор строк,' удовлетворяющих заданному условию. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:=CRange, CopyToRange:=ORange

' Создание новой рабочей книги для размещения

Page 296: ? Применение VBA и макросов в Microsoft® Excel

296 Часть II Автоматизация Excel

' результата применения расширенного фильтра. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSN = WBN.Worksheets(1)

' Определение заголовка отчета. WSN.Cells(1, 1).Value = "Отчет о сделках заказчика " _& ThisCust

' Копирование данных с текущего активного' рабочего листа в новую рабочую книгу. WSO.Cells(1, NextCol + 4).CurrentRegion.Copy _Destination:=WSN.Cells(3, 1) TotalRow = WSN.Cells(65536, 1).End(xlUp).Row + 1 WSN.Cells(TotalRow, 1).Value = "Всего"' В англоязычной версии Excel:' WSN.Cells(TotalRow, 2).FormulaR1C1 = "=SUM(R2C:R[-1]C)"' WSN.Cells(TotalRow, 4).FormulaR1C1 = "=SUM(R2C:R[-1]C)" WSN.Cells(TotalRow, 2).FormulaR1C1Local = _"=СУММ(R2C:R[-1]C)" WSN.Cells(TotalRow, 4).FormulaR1C1Local = _"=СУММ(R2C:R[-1]C)"

' Стилевое форматирование отчета. WSN.Cells(3, 1).Resize(1, 4).Font.Bold = True WSN.Cells(TotalRow, 1).Resize(1, 4).Font.Bold = True WSN.Cells(1, 1).Font.Size = 18

WBN.SaveAs "C:\" & ThisCust & ".xls" WBN.Close SaveChanges:=False

WSO.Select Set WSN = Nothing Set WBN = Nothing

' Очистить область вставки результата' применения расширенных фильтров. Cells(1, NextCol + 2).Resize(1, 10).EntireColumn.Clear Next cell

Cells(1, NextCol).EntireColumn.Clear MsgBox FinalCust - 1 & " отчетов были успешно созданы!"End Sub

Подведем итог. Комбинация двух расширенных фильтров позволила создать27 отчетов менее чем за 1 минуту (рис. 11.20).С учетом того, что опытные пользователи Excel создают один отчет в среднем за 2–3 минуты, макрос RunReportForEachCustomer позволяет сэкономить около1 часа рабочего времени.

Page 297: ? Применение VBA и макросов в Microsoft® Excel

Анализ данных с помощью расширенного фильтра Глава 11 297

Рис. 11.20. Создание 27 отчетов менее чем за одну минуту — весьма непло&

хой результат для комбинации двух расширенных фильтров!

АвтофильтрАвтофильтр является упрощенным вариантом расширенного фильтра и

обычно применяется посредством пользовательского интерфейса.

Тем не менее, существует один аспект автофильтра, доступный исключиY

тельно посредством VBA. При выборе команды Данные Фильтр Авто-фильтр (Data Filter AutoFilter) справа от названий столбцов в фильтруемом

диапазоне появляются кнопки с изображением указывающей вниз стрелки.

Чтобы скрыть кнопки для столбцов, по которым не нужно проводить фильтY

рацию, воспользуйтесь VBA. Ниже приведен пример скрытия кнопок раскрыY

вающегося списка для столбцов C (дата), E (количество), F (выручка),

G (себестоимость) и H (прибыль):

Sub AutoFilterCustom() Range("A1").AutoFilter Field:=3, VisibleDropDown:=False Range("A1").AutoFilter Field:=5, VisibleDropDown:=False Range("A1").AutoFilter Field:=6, VisibleDropDown:=False Range("A1").AutoFilter Field:=7, VisibleDropDown:=False Range("A1").AutoFilter Field:=8, VisibleDropDown:=FalseEnd Sub

Параметр VisibleDropDown уникален тем, что он доступен только через

программный код. Выполнить аналогичное действие посредством пользоваY

Page 298: ? Применение VBA и макросов в Microsoft® Excel

298 Часть II Автоматизация Excel

тельского интерфейса Excel не представляется возможным. ‘‘Модифицируйте’’

подобным образом автофильтр, и вы прославитесь как знаток своего дела в глаY

зах коллег, ничего не подозревающих об удивительных возможностях VBA. РеY

зультат выполнения макроса AutoFilterCustom показан на рис. 11.21.

Рис. 11.21. Скрыть кнопки раскрывающихся списков для столбцов, по которымне нужно проводить фильтрацию, возможно исключительно посредством VBA

Следующий шагРасширенный фильтр Excel предоставляет впечатляющие возможности по

манипулированию исходными данными и созданию отчетов. Следующая глаY

ва посвящена одному из краеугольных камней Excel — сводным таблицам.

Комбинация расширенного фильтра и сводной таблицы YYYY это настоящая

гремучая смесь, позволяющая делать с исходными данными все, что вам заY

благорассудится!

Page 299: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицыв различных версиях Excel ........ 299Создание сводных таблицс помощью пользовательскогоинтерфейса Excel......................... 300Создание сводных таблицс помощью VBA ........................... 303Создание отчета о структуреспроса на товары......................... 309Создание отчета о структуреспроса на товары:завершающая стадия.................. 317Создание отчетао прибыльности товаров ........... 326Суммирование значенийполей области данныхсводной таблицы путемгруппирования .............................332Дополнительные возможностисводных таблиц........................... 340Сумма, среднее, количество,минимум, максимум и др. .........355Дополнительные вычисленияв полях области данныхсводной таблицы ........................ 356Следующий шаг............................ 361

12Глава 12

Ñâîäíûå òàáëèöû

Впервые концепция сводных табY

лиц была представлена компанией

Lotus в продукте Improv.

Одна из ключевых особенностей

сводных таблиц состоит в возможноY

сти быстрого суммирования больших

объемов данных. Тем не менее, это

далеко не единственное их применеY

ние. В частности, сводные таблицы

можно использовать для создания

всевозможных отчетов.

Сводные таблицыв различныхверсиях Excel

Впервые сводные таблицы были

представлены в Excel 95. В Excel 97 реаY

лизация сводных таблиц была значиY

тельно улучшена, а в Excel 2000 —

кардинальным образом изменена.

В Excel 2002 к сводным таблицам

были добавлены несколько новых

параметров.

Создавая программный код в ExY

cel 2003, следует уделить особое вниY

мание его совместимости с Excel 2000

и Excel 97. И если совместимость с

Excel 2000 достигается за счет внесеY

ния в код нескольких небольших изY

менений, то совместимость с Excel 97

требует его полного пересмотра. УчиY

тывая, что Microsoft прекратила подY

держку Excel 97, а возраст самого

продукта превышает 7 лет, в этой

главе будет использоваться кэш

сводных таблиц, впервые представY

Page 300: ? Применение VBA и макросов в Microsoft® Excel

300 Часть II Автоматизация Excel

ленный в Excel 2000. Кроме того, в конце главы будет рассмотрен метод Pivot-TableWizard YYYY единственный способ создания кода, совместимого с Excel 97.

Создание сводных таблиц с помощьюпользовательского интерфейса Excel

По имеющейся у Microsoft информации, сводные таблицы применяют

около 7% пользователей Excel. В то же время, исследование компании MrExY

cel Consulting показало, что сводные таблицы применяют около 42% опытных

пользователей Excel. Как бы то ни было, о том, что такое сводная таблица,

знают далеко не все. Рассмотрим создание простой сводной таблицы с помоY

щью пользовательского интерфейса Excel.

Предположим, что исходные данные занимают на рабочем листе свыше

12 000 строк (рис. 12.1).

Рис. 12.1. Сводная таблица позволяет подсчитать суммарные значения длябольшого объема исходных данных

Задача заключается в подсчете суммарного дохода по регионам (строки цеY

левой таблицы) и товарам (столбцы целевой таблицы). Для ее решения создаY

дим сводную таблицу, выполнив следующие действия.

Page 301: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 301

1. Выделите ячейку, принадлежащую диапазону исходных данных, и выY

берите команду меню Excel Данные Сводная таблица (Data PivotY

Table and PivotChart Report).

2. В открывшемся диалоговом окне Мастер сводных таблиц идиаграмм — шаг 1 из 3 (PivotTable and PivotChart Wizard — Step 1 of 3)

установите переключатели В списке или базе данных Microsoft OfficeExcel (Microsoft Office Excel list or database) и Сводная таблица(PivotTable).

3. Убедитесь, что в поле Диапазон (Range) диалогового окна Мастерсводных таблиц и диаграмм — шаг 2 из 3 (PivotTable and PivotChart

Wizard YYYY Step 2 of 3) указан верный адрес диапазона исходных данных.

4. В диалоговом окне Мастер сводных таблиц и диаграмм — шаг 3 из 3(PivotTable and PivotChart Wizard — Step 3 of 3) установите переключаY

тель Существующий лист (Existing worksheet) и укажите адрес первой

ячейки диапазона, в который необходимо поместить сводную таблицу.

Щелкните на кнопке Макет (Layout) (рис. 12.2).

Рис. 12.2. Определите макет сводной таблицы

5. В диалоговом окне Мастер сводных таблиц и диаграмм — макет(PivotTable and PivotChart Wizard YYYY Layout) перетащите кнопку Региони отпустите ее над областью Строка (ROW). Аналогичным образом пеY

ретащите кнопку Товар и отпустите ее над областью Столбец(COLUMN). Наконец, перетащите кнопку Выручка и отпустите ее над

областью Данные (DATA). Если столбец Выручка содержит только чиY

словые сведения, при отпускании над областью Данные надпись на

кнопке Выручка изменится на Сумма по полю Выручка (Sum of ВыручY

ка), как показано на рис. 12.3. Щелкните на кнопке OK, для того чтобы

вернуться к диалоговому окну Мастер сводных таблиц и диаграмм —шаг 3 из 3.

6. Щелкните на кнопке Готово (Finish). Практически мгновенно Excel

сгенерирует сводную таблицу на основе исходных данных, как показано

на рис. 12.4.

Page 302: ? Применение VBA и макросов в Microsoft® Excel

302 Часть II Автоматизация Excel

Рис. 12.3. Чтобы определить макет сводной таблицы, перетащитекнопки, соответствующие требуемым столбцам исходных данных, иотпустите их над областями Строка, Столбец и Данные диалоговогоокна Мастер сводных таблиц и диаграмм — макет

Рис. 12.4. Сводная таблица предельно лаконична

Page 303: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 303

Внимание В Excel 97 мастер сводных таблиц предполагает выполнение четырех шагов вместотрех. Шаг 3 мастера сводных таблиц Excel 97 заключается в определении макетасводной таблицы. Чтобы определить макет сводной таблицы в Excel 2003, щелк&ните на кнопке Макет (Layout) диалогового окна Мастер сводных таблиц идиаграмм — шаг 3 из 3 (PivotTable and PivotChart Wizard — Step 3 of 3).

Поместив сводную таблицу на рабочий лист, вы можете изменять ее макет

путем перетаскивания полей из окна Список полей сводной таблицы(PivotTable Field List) в сводную таблицу, и наоборот. Например, на рис. 12.5

показана сводная таблица, полученная в результате перетаскивания поля Ре-гион в область столбцов, поля Товар YYYY в область строк, и добавления в обY

ласть строк поля Заказчик.

Рис. 12.5. Сводная таблица, полученная в результате перетаскивания поля Регион вобласть столбцов, поля Товар — в область строк, и добавления в область строк по&ля Заказчик

Создание сводных таблиц с помощью VBAЧтобы создать сводную таблицу с помощью VBA в Excel 2000 и более поздY

них версиях Excel, сперва необходимо создать объект кэша сводных таблиц,

как показано далее:

Page 304: ? Применение VBA и макросов в Microsoft® Excel

304 Часть II Автоматизация Excel

Dim WSD As WorksheetDim PTCache As PivotCacheDim PT As PivotTableDim PRange As RangeDim FinalRow As LongSet WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы.For Each PT In WSD.PivotTables PT.TableRange2.ClearNext PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц.FinalRow = WSD.Cells(65536, 1).End(xlUp).RowSet PRange = WSD.Cells(1, 1).Resize(FinalRow, 8)Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

После создания кэша сводных таблиц в него можно добавить новую сводY

ную таблицу с помощью метода CreatePivotTable:

Set PT = PTCache.CreatePivotTable(TableDestination:=WSD.Range( _"J2"), TableName:="PivotTable1")

Параметр TableDestination метода CreatePivotTable определяет

размещение сводной таблицы, а параметр TableName — ее имя. Результат

выполнения приведенной выше строки кода показан на рис. 12.6.

Рис. 12.6. В результате выполнения метода CreatePivotTable Excel создает пустую свод&ную таблицу, состоящую из четырех ячеек

Page 305: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 305

Excel не пересчитывает сводную таблицу при добавлении полей к ее макету

с помощью пользовательского интерфейса, однако по умолчанию пересчитыY

вает сводную таблицу на каждом шаге ее построения с помощью VBA. Чтобы

повысить эффективность программного кода, временно запретите пересчет

сводной таблицы с помощью свойства ManualUpdate:

PT.ManualUpdate = True

Теперь все готово для создания макета сводной таблицы с помощью VBA.

Воспользовавшись методом AddFields, добавьте поля к области строк, обY

ласти столбцов или области страницы сводной таблицы:

' Добавить поля к области строк и области столбцов сводной таблицы.PT.AddFields RowFields:=Array("Товар", "Заказчик"), _ColumnFields:="Регион"

Чтобы добавить поле Выручка к области данных сводной таблицы, устаY

новите значение свойства Orientation этого поля равным xlDataField(рассматривается в следующем разделе).

Подсчет суммы чисел вместо количества значенийПри добавлении поля Выручка к области данных сводной таблицы Excel

вполне логично предполагает, что вы хотите подсчитать сумму выручки. К соY

жалению, это справедливо только при условии, что все без исключения ячейY

ки столбца Выручка содержат числовые данные. Если хотя бы одна ячейка

будет содержать нечисловые данные (например, окажется пустой), вместо

суммы чисел Excel подсчитает количество значений.

Определяя макет сводной таблицы с помощью пользовательского интерY

фейса, убедитесь, что название кнопки Выручка изменилось в результате ее

перетаскивания в область Данные (DATA) на Сумма по полю Выручка (Sum

of Выручка), а не на Количество по полю Выручка (Count of Выручка). Чтобы

изменить функцию подсчета количества значений на функцию подсчета сумY

мы чисел, исправьте исходные данные или же дважды щелкните на кнопке

Количество по полю Выручка, после чего ее название изменится на Сумма пополю Выручка.

Для того чтобы указать на необходимость применения функции подсчета

суммы чисел в коде VBA, установите значение свойства Function поля Вы-ручка равным xlSum, как показано ниже:

' Определить область данных.With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1End With

Задав все необходимые параметры сводной таблицы, пересчитайте ее, усY

тановив значение свойства ManualUpdate равным False, а затем вновь заY

претите автоматический пересчет, установив значение свойства ManualUp-date равным True, как показано далее:

Page 306: ? Применение VBA и макросов в Microsoft® Excel

306 Часть II Автоматизация Excel

' Пересчитать сводную таблицу.PT.ManualUpdate = FalsePT.ManualUpdate = True

Ниже приведен полный код макроса, создающего сводную таблицу, анаY

логичную показанной на рис. 12.5:

Sub CreatePivot() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range Dim FinalRow As Long Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Добавить поля к области строк и области столбцов сводной таблицы. PT.AddFields RowFields:=Array("Товар", "Заказчик"), _ColumnFields:="Регион"

' Определить область данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 End With

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = TrueEnd Sub

Перемещение или изменение части сводной таблицы

Excel не разрешает перемещать или изменять часть сводной таблицы.

К примеру, создайте макрос, удаляющий столбец, который содержит общую

сумму по строкам сводной таблицы (в данном случае YYYY столбец O). В резульY

тате выполнения макроса будет сгенерирована ошибка времени выполнеY

ния 1004, как показано на рис. 12.7.

Page 307: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 307

Рис. 12.7. Excel не разрешает перемещать илиизменять часть сводной таблицы. Чтобыобойти это ограничение, скопируйте содер&жимое ячеек сводной таблицы в другое место

Определение размера сводной таблицы

Определить размер сводной таблицы заранее достаточно сложно. Например,

рассматриваемая сводная таблица может содержать как 5, так и 6 столбцов в заY

висимости от того, была ли заключена в западном регионе хотя бы одна сделка.

Чтобы обратиться ко всей сводной таблице, необходимо воспользоваться ее

свойством TableRange2.

Поскольку Excel не разрешает перемещать или изменять часть сводной

таблицы, рекомендуется скопировать содержимое ячеек сводной таблицы в

другое место и удалить исходную таблицу. Рассмотрим макрос CreateSum-maryReportUsingPivot, который создает небольшую сводную таблицу.

Чтобы запретить добавление к сводной таблице столбца Общий итог (Grand

Total) и одноименной строки, установите равными False значения свойств

ColumnGrand и RowGrand, соответственно.

Диапазон ячеек PT.TableRange2 охватывает всю сводную таблицу,

включая строку с кнопкой Сумма по полю Выручка (Sum of Выручка). Чтобы

избавиться от этой строки, необходимо сместить ссылку PT.TableRange2 на

одну строку вниз (Offset(1, 0)). Если сводная таблица содержит нескольY

ко строк с избыточной информацией, сместите ссылку PT.TableRange2 на

соответствующее число строк.

Для вставки содержимого ячеек диапазона PT.TableRange2.Offset(1, 0)в область, начинающуюся ячейкой J10, применяется метод PasteSpecial. На

рис. 12.8 показано содержимое рабочего листа после копирования ячеек сводY

ной таблицы.

Чтобы удалить сводную таблицу, ‘‘очистите’’ диапазон ячеек PT.Table-Range2 с помощью метода Clear. Если вы затем собираетесь форматировать

рабочий лист, удалите объект PivotCache из памяти, присвоив соответстY

вующей переменной (в данном случае PTCache) значение Nothing.

Page 308: ? Применение VBA и макросов в Microsoft® Excel

308 Часть II Автоматизация Excel

Рис. 12.8. Содержимое рабочего листа перед удалением свод&ной таблицы

Sub CreateSummaryReportUsingPivot()' Этот макрос создает статический отчет' на основе сводной таблицы.

Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить область строк и область столбцов сводной таблицы. PT.AddFields RowFields:="Регион", ColumnFields:="Товар"

' Определить область данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 End With

' Запретить создание итогового столбца и итоговой строки. With PT .ColumnGrand = False .RowGrand = False .NullString = "0" End With

Page 309: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 309

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Скопировать содержимое ячеек диапазона' PT.TableRange2.Offset(1, 0) в область,' начинающуюся ячейкой J10. PT.TableRange2.Offset(1, 0).Copy WSD.Range("J10").PasteSpecial xlPasteValues

' Содержимое рабочего листа на текущий' момент показано на рис. 12.8.

' Удалить сводную таблицу и объект кэша сводных таблиц. PT.TableRange2.Clear Set PTCache = NothingEnd Sub

Далее в этой главе рассматриваются более сложные примеры использоваY

ния сводных таблиц.

Создание отчета о структуре спроса на товарыОтчет о структуре спроса на товары может быть полезен менеджерам по проY

дажам, поскольку он позволяет получить наглядное представление об объеY

мах закупок товаров разными заказчиками. Отчет, показанный на рис. 12.9,

содержит список заказчиков в порядке убывания общего объема закупок в

трех регионах: центральном, восточном и западном.

Рис. 12.9. 90% этого отчета создано с помощью своднойтаблицы

Page 310: ? Применение VBA и макросов в Microsoft® Excel

310 Часть II Автоматизация Excel

Чтобы создать такой отчет, следует воспользоваться сводной таблицей.

К сожалению, конечный результат применения сводной таблицы вряд ли поY

нравится менеджерам по продажам. В частности, сводная таблица не предуY

сматривает вставку разрыва страницы между частями отчета, соответствуюY

щими разным товарам.

Тем не менее, первый шаг в подготовке отчета о структуре спроса на товаY

ры состоит в создании сводной таблицы с полями Товар и Заказчик в обласY

ти строк, полем Регион в области столбцов и полем Выручка в области данY

ных (рис. 12.10).

Рис. 12.10. В основе отчета о структуре спроса на товары лежит сводная таблица

Ниже перечислены очевидные недостатки стандартной сводной таблицы с

двумя полями в области строк.

Внешний вид стандартной сводной таблицы оставляет желать лучшего.

Как показано на рис. 12.10, значение ‘‘ABC’’ встречается в столбце То-вар всего один раз, а следующие за ним 26 ячеек и вовсе оставлены

пустыми. Это одна из наиболее серьезных недоработок сводных табY

лиц, устранить которую весьма непросто. Безусловно, большинство

пользователей догадаются, о каком товаре идет речь, однако если часть

отчета, посвященная товару ABC, будет занимать 2 и более страницы,

могут возникнуть определенные трудности. Кроме того, подобный

способ представления данных затрудняет их повторное использование.

Page 311: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 311

Область данных отчета содержит пустые ячейки вместо нулей. Как поY

казано на рис. 12.10, заказчик BCD LTD. приобрел товар ABC только

в западном регионе, что побудило Excel оставить пустыми ячейки, соY

ответствующие объемам закупок товара ABC заказчиком BCD LTD.

В восточном и центральном регионах. Это может не понравиться

опытным пользователям Excel, привыкшим перемещаться по блокам

данных с помощью последовательного нажатия клавиши <End> и одY

ной из клавиш со стрелками.

Название отчета заслуживает отдельного внимания. Вряд ли комуY

нибудь понравится, чтобы предоставленный ему отчет имел заголовок

Сумма по полю Выручка (Sum of Выручка).

Заголовки некоторых столбцов сводной таблицы избыточны. К примеY

ру, слово ‘‘Регион’’, помещенное в ячейку L2 (см. рис. 12.10), и вовсе

не относится к отчету.

Стандартный порядок сортировки (по алфавиту), применяемый в сводной

таблице, не всегда используется на практике. В частности, менеджеры по

продажам предпочитают, чтобы список заказчиков был отсортирован в поY

рядке убывания суммы закупок товара. Кроме того, последовательность

регионов ‘‘ВостокYYЗападYYЦентр’’ не соответствует их естественному геоY

графическому расположению (‘‘ЗападYYЦентрYYВосток’’).

Автоматически сгенерированные границы определенно не красят отчет.

При отображении числовых значений используется формат Общий(General), хотя для подобных отчетов больше подходит формат с раздеY

лителем групп разрядов и округлением чисел до тысяч или миллионов.

Сводные таблицы не поддерживают вставку разрыва страницы между

различными частями отчета. Если отчет предназначен для нескольких

менеджеров по продажам, каждый из которых курирует определенный

товар, разрывы страниц придется добавлять самостоятельно.

Ввиду невозможности вставки разрывов страниц между различными

частями отчета, целесообразно отказаться от автоматического создания

строк с промежуточными итогами сводной таблицы и добавить строки

с промежуточными итогами и разрывы страниц вручную с помощью

метода Subtotal. Excel генерирует строки с промежуточными итогами

при наличии в области строк сводной таблицы двух и более полей (на

рис. 12.10 показана строка с промежуточными итогами для поля То-вар). Например, при наличии в области строк 4Yх полей Excel сгенериY

рует 3 строки с промежуточными итогами для 3Yх первых полей.

К счастью, каждый из перечисленных выше недостатков можно устранить

либо путем изменения параметров сводной таблицы, либо с помощью проY

граммного кода. В последнем случае содержимое сводной таблицы следует

предварительно скопировать в другую область рабочего листа или на новый

рабочий лист.

Page 312: ? Применение VBA и макросов в Microsoft® Excel

312 Часть II Автоматизация Excel

Заполнение значениями пустых ячеек в области данных

Пустые ячейки начали досаждать пользователям со времен первой реалиY

зации сводных таблиц в Excel 95. Начиная с Excel 97, Microsoft предоставляет

возможность указать значение, которое будет отображаться в пустых ячейках.

Чтобы задать значение, которое будет отображаться в пустых ячейках, откройY

те диалоговое окно Параметры сводной таблицы (PivotTable Options). Для

этого щелкните на кнопке Параметры (Options) диалогового окна Мастерсводных таблиц и диаграмм — шаг 3 из 3 (PivotTable and PivotChart Wizard —

Step 3 of 3) или выберите команду Параметры таблицы (Table Options) из расY

крывающегося списка Сводная таблица (PivotTable) панели инструментов

Сводные таблицы (PivotTable). Установите флажок Для пустых ячеекотображать (For empty cells, show) и введите 0 в расположенном справа от

флажка текстовом поле (рис. 12.11).

Рис. 12.11. Установите флажок Для пустых ячеек отображатьи введите значение, которое будет отображаться в пустыхячейках области данных сводной таблицы, в расположенномсправа от флажка текстовом поле

Чтобы выполнить эквивалентное действие в VBA, установите значение

свойства объекта сводной таблицы NullString равным "0".

На заметку Несмотря на то что в коде VBA значение, которое будет отображаться в пустыхячейках, задается как текстовый нуль, Excel помещает в пустые ячейки число&вой нуль.

Page 313: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 313

Изменение порядка сортировки списка заказчиковСредства пользовательского интерфейса Excel позволяют отсортировать

список заказчиков в порядке убывания суммы закупок товара. Дважды щелкY

ните на кнопке сводной таблицы Заказчик, в результате чего откроется диаY

логовое окно Вычисление поля сводной таблицы (PivotTable Field), показанY

ное на рис. 12.12.

Рис. 12.12. Чтобы добраться до параметров сортировкисводной таблицы, щелкните на кнопке Дополнительно

Щелкните на кнопке Дополнительно (Advanced), в результате чего откроY

ется диалоговое окно Дополнительные параметры поля сводной таблицы(PivotTable Field Advanced Options). Установите переключатель По убыванию(Descending) и выберите из расположенного под переключателем раскрываюY

щегося списка значение Сумма по полю Выручка (Sum of Выручка), как покаY

зано на рис. 12.13.

Рис. 12.13. Диалоговое окно Дополнительные параметрыполя сводной таблицы позволяет выбрать порядок сорти&ровки содержимого поля сводной таблицы

Чтобы выполнить эквивалентное действие в VBA, воспользуйтесь методом

AutoSort:

PT.PivotFields("Заказчик").AutoSort Order:=xlDescending, _Field:="Сумма по полю Выручка"

Page 314: ? Применение VBA и макросов в Microsoft® Excel

314 Часть II Автоматизация Excel

Изменение порядка следования столбцовсводной таблицы вручную

Последовательность регионов YYYY столбцов сводной таблицы YYYY ‘‘ВостокYY

ЗападYYЦентр’’ не соответствует их естественному географическому распоY

ложению (‘‘ЗападYYЦентрYYВосток’’), что может смутить конечных пользоY

вателей отчета.

Microsoft предлагает весьма экстравагантный способ изменения порядка

следования столбцов сводной таблицы, получивший название ручной сортиY

ровки. Как показано на рис. 12.10, по умолчанию Excel выстраивает столбцы

сводной таблицы по алфавиту: Восток, Запад, Центр (заголовки столбцов

находятся в ячейках L3:N3, соответственно). Чтобы изменить порядок следоY

вания столбцов с помощью пользовательского интерфейса, введите в ячейке

N3 слово ‘‘Восток’’. Как по мановению волшебной палочки, Excel сместит

столбцы Запад и Центр на одну позицию влево и перенесет столбец Востокна место бывшего столбца Центр (рис. 12.14).

Рис. 12.14. Чтобы изменить стандартный порядок следования столб&цов сводной таблицы Восток, Запад, Центр с помощью пользова&тельского интерфейса, введите в ячейке N3 слово “Восток”

Чтобы выполнить эквивалентное действие в VBA, измените значение

свойства Position соответствующего столбца сводной таблицы. Поскольку

Page 315: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 315

гарантии того, что столбец с заданным заголовком будет присутствовать в исY

ходных данных, нет, отключите обработку ошибок, как показано ниже

(обработке ошибок посвящена глава 23, ‘‘Обработка ошибок’’):

On Error Resume NextPT.PivotFields("Регион").PivotItems("Восток").Position = 3On Error GoTo 0

Изменение формата отображения числовых значений

Чтобы изменить формат отображения числовых значений сводной таблиY

цы с помощью пользовательского интерфейса, дважды щелкните на кнопке

Сумма по полю Выручка (Sum of Выручка). В открывшемся диалоговом окне

Вычисление поля сводной таблицы (PivotTable Field) щелкните на кнопке

Формат (Number) и выберите требуемый формат с помощью диалогового окна

Формат ячеек (Format Cells).

При работе с большими числами рекомендуется использовать формат с

разделителем групп разрядов. Ниже приведен пример задания маски формата

с разделителем групп разрядов в VBA:

PT.PivotFields("Сумма по полю Выручка").NumberFormat = "#,##0"

Зачастую суммы заказов товаров исчисляются в тысячах, а то и в миллиоY

нах. Чтобы округлить числовое значение до тысяч, добавьте в конец маски

формата запятую и, при желании, аббревиатуру ‘‘K’’:

PT.PivotFields("Сумма по полю Выручка").NumberFormat = "#,##0,K"

Некоторые компании по старой привычке используют в качестве показатеY

ля тысяч аббревиатуру ‘‘M’’, а в качестве показателя миллионов YYYY аббревиаY

туру ‘‘MM’’. Чтобы использовать в качестве показателя тысяч аббревиатуру

‘‘M’’, предварите ее символом обратной косой черты:

PT.PivotFields("Сумма по полю Выручка").NumberFormat = "#,##0,\M"

Символ обратной косой черты можно заменить двойными кавычками.

Особенность употребления двойных кавычек внутри строки в кавычках в коде

VBA заключается в необходимости дублировать каждый символ двойной каY

вычки. Ниже приведен пример задания маски #,##0.0,,"MM", используюY

щейся для округления числовых значений до десятков миллионов с аббревиаY

турой ‘‘MM’’:

PT.PivotFields("Сумма по полю Выручка").NumberFormat = _"#,##0.0,,""MM"""

Запрет автоматического добавленияпромежуточных итогов

Excel автоматически генерирует промежуточные итоги при наличии в обY

ласти строк сводной таблицы двух и более полей. Строки с промежуточными

итогами создаются для всех полей, за исключением последнего. Ввиду невозY

можности вставки разрывов страниц между частями отчета, относящимися к

Page 316: ? Применение VBA и макросов в Microsoft® Excel

316 Часть II Автоматизация Excel

разным товарам, целесообразно отказаться от автоматического добавления

промежуточных итогов сводной таблицы и добавить промежуточные итоги и

разрывы страниц вручную с помощью метода Subtotal.

Чтобы запретить автоматическое добавление промежуточных итогов для

поля Товар с помощью пользовательского интерфейса Excel, дважды щелкY

ните на кнопке Товар и установите переключатель Нет (None) в открывшемся

диалоговом окне Вычисление поля сводной таблицы (PivotTable Field), как

показано на рис. 12.15.

Рис. 12.15. Строки с промежуточными итогами созда&ются автоматически при наличии в области строксводной таблицы двух и более полей. Чтобы запретитьдобавление промежуточных итогов для некоторогополя, дважды щелкните на кнопке, соответствующейэтому полю, и установите переключатель Нет в от&крывшемся диалоговом окне

Чтобы выполнить аналогичное действие в VBA, придется изрядно потрудитьY

ся, а именно установить значение свойства поля Subtotals равным массиву, соY

стоящему из 12 значений False. Первое значение False запрещает автоматичеY

ское добавление промежуточных итогов, второе значение False — подсчет сумY

мы, третье значение False — подсчет количества и т.д. (полный синтаксис

свойства Subtotals приводится в справочной системе VBA). Следующий код заY

прещает создание строки с промежуточными итогами для поля Товар:

PT.PivotFields("Товар").Subtotals = Array(False, False, False, _False, False, False, False, False, False, False, False, False)

Чтобы сделать код более удобочитаемым, можно создать переменную, храY

нящую массив из 12 значений False:

NoSubtotalArray = Array(False, False, False, False, False, _False, False, False, False, False, False, False)PT.PivotFields("Товар").Subtotals = NoSubtotalArrayPT.PivotFields("Дата").Subtotals = NoSubtotalArray

Запрет подсчета общей суммы по столбцам

Логичным продолжением запрета автоматического добавления промежуY

точных итогов сводной таблицы будет запрет подсчета общей суммы по

Page 317: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 317

столбцам, помещаемой в строку Общий итог (Grand Total). Откройте диалоY

говое окно Параметры сводной таблицы (PivotTable Options) (см. рис. 12.11).

Чтобы запретить создание строки Общий итог, снимите флажок Общаясумма по столбцам (Grand totals for columns) (чтобы запретить создание одY

ноименного столбца, сбросьте флажок Общая сумма по строкам (Grand totals

for rows)). Ниже приведен соответствующий код VBA:

PT.ColumnGrand = False

Создание отчета о структуре спроса на товары:завершающая стадия

В предыдущем разделе были рассмотрены изменения, которые можно вноY

сить непосредственно в сводную таблицу Excel. Все оставшиеся действия по

созданию отчета о структуре спроса на товары требуют копирования значений

сводной таблицы (но не саму таблицу!) в другое место.

На рис. 12.16 показана сводная таблица после выполнения всех действий,

описанных в предыдущем разделе.

Рис. 12.16. Менее 1 секунды и 30 строк программного кода понадобилосьдля того, чтобы преодолеть более 90% пути к отчету о структуре спроса натовары

Page 318: ? Применение VBA и макросов в Microsoft® Excel

318 Часть II Автоматизация Excel

Создание новой рабочей книги

Предположим, что отчет о структуре спроса на товары необходимо размесY

тить в новой рабочей книге, чтобы отправить ее затем по электронной почте.

С целью сделать код более универсальным, создадим объектные переменные

для текущей рабочей книги, новой рабочей книги и первого рабочего листа в

новой рабочей книге (см. практикум ‘‘Использование двух расширенных

фильтров для создания отчетов по каждому заказчику’’ на с. 293). Добавьте

следующий код в начало макроса:

Dim WSD As WorksheetDim WSR As WorksheetDim WBO As WorkbookDim WBN As WorkbookDim PTCache As PivotCacheDim PT As PivotTableDim PRange As Range

Set WBO = ActiveWorkbookSet WSD = Worksheets("Данные")

После построения и пересчета сводной таблицы создайте новую рабочую

книгу, как показано ниже:

' Создать новую рабочую книгу с одним листом.Set WBN = Workbooks.Add(xlWBATWorksheet)Set WSR = WBN.Worksheets(1)WSR.Name = "Отчет"' Создать заголовок отчета.With WSR.[A1] .Value = "Отчет о структуре спроса на товары" .Font.Size = 14End With

Копирование содержимого сводной таблицы

Среди недостатков сводной таблицы, показанной на рис. 12.16, следует отY

метить наличие границ, неудачный заголовок и совершенно ненужное слово

‘‘Регион’’ в ячейке L2. Все это можно устранить путем копирования содержиY

мого диапазона ячеек PT.TableRange2 (за исключением первой строки) и

его вставки в новый рабочий лист с помощью метода PasteSpecial со знаY

чением параметра Paste, равным xlPasteValuesAndNumberFormats.

Как уже отмечалось, диапазон ячеек PT.TableRange2 содержит одну изY

быточную строку — строку 2 (см. рис. 12.16). Более сложные сводные таблицы

с несколькими полями в области столбцов или области страницы будут соY

держать несколько таких строк (определить точное количество ненужных

строк поможет анализ макета сводной таблицы). Чтобы исключить избыточY

ные строки из копируемого диапазона ячеек, воспользуйтесь его свойством

Offset. Можно справедливо заметить, что смещение ссылки на диапазон

ячеек PT.TableRange2 приведет к захвату лишних строк под сводной таблиY

цей, однако это несущественно, так как эти строки пустые. После копироваY

Page 319: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 319

ния содержимого сводной таблицы ее можно удалить с рабочего листа, а соотY

ветствующий объект PivotCache — из памяти компьютера:

' Скопировать содержимое сводной таблицы и поместить' его на рабочий лист "Отчет". Свойство Offset используется' для исключения из копируемого диапазона ячеек строки с' заголовком сводной таблицы.PT.TableRange2.Offset(1, 0).CopyWSR.[A3].PasteSpecial Paste:=xlPasteValuesAndNumberFormatsPT.TableRange2.ClearSet PTCache = Nothing

Обратите внимание, что метод PasteSpecial копирует только значения и

форматы чисел, что позволяет избавиться как от границ, так и от самой струкY

туры сводной таблицы. Последнее необходимо для возможности вставки в

скопированные данные новых строк.

Улучшение внешнего вида отчета

Как показано на рис. 12.17, большинство ячеек в столбце A пусты.

Рис. 12.17. Пустые ячейки — это одна из наиболее сущест&венных недоработок сводных таблиц, устранить которуювесьма непросто

Чтобы заполнить пустые ячейки столбца A соответствующими значениями с

помощью пользовательского интерфейса Excel, выполните следующие действия.

Page 320: ? Применение VBA и макросов в Microsoft® Excel

320 Часть II Автоматизация Excel

1. Выделите все ячейки столбца A, в которых должно содержаться наимеY

нование товара.

2. Выберите команду меню Правка Перейти (Edit Go To), в результате

чего откроется диалоговое окно Переход (Go To). Щелкните на кнопке

Выделить (Special) и установите в открывшемся диалоговом окне

Выделение группы ячеек (Go To Special) переключатель Пустыеячейки (Blanks) (рис. 12.18).

Рис. 12.18. Выделите пустые ячейки и заполните их форму&лой, ссылающейся на ячейку выше

3. Заполните пустые ячейки R1C1Yформулой, ссылающейся на ячейку

выше (=R[-1]C). Чтобы сделать это с помощью пользовательского инY

терфейса, введите знак равенства, нажмите клавишу <↑>, а затем YYYY

комбинацию клавиш <Ctrl+Enter>.

4. Выделите все ячейки столбца A, в которых содержится наименование

товара. Необходимость этого шага обусловлена тем, что функция спеY

циальной вставки (см. следующий шаг) не поддерживает работу с неY

смежными диапазонами ячеек.

5. Скопируйте выделенные ячейки и вставьте их с помощью команды

Правка Специальная вставка (Edit Paste Special), установив в отY

крывшемся диалоговом окне Специальная вставка (Paste Special) переY

ключатель Значения (Values).

Page 321: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 321

Достижение аналогичного результата с помощью VBA можно разбить

на 3 этапа.

1. Вычисление номера последней строки отчета.

2. Вставка формулы =R[-1]C в пустые ячейки столбца A.

3. Замена формул значениями.

Ниже приведен соответствующий код VBA:

' Вычислить номер последней строки отчета по столбцу B.FinalReportRow = WSR.Range("B65536").End(xlUp).RowWith Range("A3").Resize(FinalReportRow - 2, 1) With .SpecialCells(xlCellTypeBlanks) .FormulaR1C1 = "=R[-1]C" End With .Value = .ValueEnd With

Стилевое форматирование отчета

Прежде чем добавить строки с промежуточными итогами, применим к отY

чету стилевое форматирование. Для этого выделим полужирным шрифтом

заголовки столбцов отчета (строка 3) и выровняем их по правому краю ячейки

(за исключением столбцов A и B, которые нужно выровнять по левому краю

ячейки). Последняя строка приведенного ниже кода указывает на необходиY

мость печати на каждой странице трех первых строк отчета:

' Стилевое форматирование отчета:' - выделение полужирным шрифтом заголовков столбцов;' - выравнивание заголовков столбцов по правому краю' (за исключением столбцов A-B, которые' выравниваются по правому краю).Selection.Columns.AutoFitRange("A3").EntireRow.Font.Bold = TrueRange("A3").EntireRow.HorizontalAlignment = xlRightRange("A3:B3").HorizontalAlignment = xlLeft

' Печатать на каждой странице строки 1-3 отчета.WSR.PageSetup.PrintTitleRows = "$1:$3"

Добавление промежуточных итогов

Чтобы добавить промежуточные итоги с помощью пользовательского инY

терфейса Excel, выделите область данных отчета (включая заголовки столбY

цов) и выберите команду меню Данные Итоги (Data Subtotals). Проверьте,

чтобы в открывшемся диалоговом окне Промежуточные итоги (Subtotals) был

установлен флажок Конец страницы между группами (Page breaks between

groups), как показано на рис. 12.19.

Page 322: ? Применение VBA и макросов в Microsoft® Excel

322 Часть II Автоматизация Excel

Рис. 12.19. При добавлении промежуточныхитогов с помощью команды Данные Итоги Excelпозволяет вставить разрыв страницы междугруппами данных

Если отчет о структуре спроса на товары всегда содержит столбцы Запад,

Центр и Восток, для добавления промежуточных итогов можно воспользоY

ваться следующим кодом:

' Добавление промежуточных итогов со вставкой' разрыва страницы между группами данных.Selection.Subtotal GroupBy:=1, Function:=xlSum, _TotalList:=Array(3, 4, 5, 6), Replace:=True, PageBreaks:=True, _SummaryBelowData:=True

К сожалению, выполнение этого кода приведет к ошибке при изменении

количества столбцов, соответствующих регионам. Решение этой проблемы

состоит в динамическом создании массива столбцов, по которым нужно подY

водить промежуточные итоги:

FinalCol = Cells(3, 255).End(xlToLeft).ColumnReDim Preserve TotColumns(1 To FinalCol - 2)For i = 3 To FinalCol TotColumns(i - 2) = iNext iSelection.Subtotal GroupBy:=1, Function:=xlSum, _TotalList:=TotColumns, Replace:=True, PageBreaks:=True, _SummaryBelowData:=True

Наконец, необходимо подобрать ширину столбцов отчета в соответствии с

добавленными в него строками:

' Автоподбор ширины столбцов отчета.GrandRow = Range("A65536").End(xlUp).RowCells(GrandRow, 3).Resize(1, 4).Columns.AutoFitCells(GrandRow, 3).Resize(1, 4).NumberFormat = "#,##0,K"' Добавить разрыв страницы перед' строкой "Общий итог" (Grand Total).WSR.HPageBreaks.Add Before:=Cells(GrandRow, 1)

Page 323: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 323

Результирующий код

Ниже приведен полный код макроса, создающего отчет о структуре спроса

на товары:

Sub ProductLineManagerReport() Dim WSD As Worksheet Dim WSR As Worksheet Dim WBO As Workbook Dim WBN As Workbook Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range Dim TotColumns() Dim FinalRow As Long Dim FinalReportRow As Long Dim FinalCol As Integer Dim i As Integer Dim GrandRow As Long Dim NoSubtotalArray As Variant

Set WBO = ActiveWorkbook Set WSD = Worksheets("Данные")

' Удалить все существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк. PT.AddFields RowFields:=Array("Товар", "Заказчик"), _ColumnFields:="Регион"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Запретить вставку строки "Общий итог" (Grand Total). PT.ColumnGrand = False

Page 324: ? Применение VBA и макросов в Microsoft® Excel

324 Часть II Автоматизация Excel

' Запретить Excel автоматически вставлять' строки с промежуточными итогами. NoSubtotalArray = Array(False, False, False, False, False, _False, False, False, False, False, False, False) PT.PivotFields("Товар").Subtotals = NoSubtotalArray

' Отсортировать список заказчиков' в порядке убывания суммы закупок товара. PT.PivotFields("Заказчик").AutoSort Order:=xlDescending, _Field:="Сумма по полю Выручка"

' Изменить порядок следования столбцов сводной таблицы так,' чтобы был соблюден естественный порядок следования регионов' "Запад"-"Центр"-"Восток". Отключить обработку ошибок' на случай, если столбец "Восток" не существует. On Error Resume Next PT.PivotFields("Регион").PivotItems("Восток").Position = 3 On Error GoTo 0

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Создать новую рабочую книгу с одним листом. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSR = WBN.Worksheets(1) WSR.Name = "Отчет"' Создать заголовок отчета. With WSR.[A1] .Value = "Отчет о структуре спроса на товары" .Font.Size = 14 End With

' Скопировать содержимое сводной таблицы и поместить' его на рабочий лист "Отчет". Свойство Offset используется' для исключения из копируемого диапазона ячеек строки с' заголовком сводной таблицы. PT.TableRange2.Offset(1, 0).Copy WSR.[A3].PasteSpecial Paste:=xlPasteValuesAndNumberFormats PT.TableRange2.Clear Set PTCache = Nothing

' Вычислить номер последней строки отчета по столбцу B. FinalReportRow = WSR.Range("B65536").End(xlUp).Row With Range("A3").Resize(FinalReportRow - 2, 1) With .SpecialCells(xlCellTypeBlanks) .FormulaR1C1 = "=R[-1]C" End With .Value = .Value End With

' Стилевое форматирование отчета:' - выделение полужирным шрифтом заголовков столбцов;' - выравнивание заголовков столбцов по правому краю' (за исключением столбцов A-B, которые' выравниваются по правому краю). Selection.Columns.AutoFit

Page 325: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 325

Range("A3").EntireRow.Font.Bold = True Range("A3").EntireRow.HorizontalAlignment = xlRight Range("A3:B3").HorizontalAlignment = xlLeft

' Печатать на каждой странице строки 1-3 отчета. WSR.PageSetup.PrintTitleRows = "$1:$3"

' Добавление промежуточных итогов со вставкой' разрыва страницы между группами данных. 'Selection.Subtotal GroupBy:=1, Function:=xlSum, _ ' TotalList:=Array(3, 4, 5, 6), Replace:=True, _ ' PageBreaks:=True, SummaryBelowData:=True

' Выполнение приведенного выше кода приведет к ошибке' при изменении количества столбцов, соответствующих регионам.' Решение этой проблемы состоит в динамическом создании массива' столбцов, по которым нужно подводить промежуточные итоги. FinalCol = Cells(3, 255).End(xlToLeft).Column ReDim Preserve TotColumns(1 To FinalCol - 2) For i = 3 To FinalCol TotColumns(i - 2) = i Next i Selection.Subtotal GroupBy:=1, Function:=xlSum, _TotalList:=TotColumns, Replace:=True, PageBreaks:=True, _SummaryBelowData:=True

' Автоподбор ширины столбцов отчета. GrandRow = Range("A65536").End(xlUp).Row Cells(GrandRow, 3).Resize(1, 4).Columns.AutoFit Cells(GrandRow, 3).Resize(1, 4).NumberFormat = "#,##0,K"' Добавить разрыв страницы' перед строкой "Общий итог" (Grand Total). WSR.HPageBreaks.Add Before:=Cells(GrandRow, 1)' Изменить заголовок последнего столбца' отчета с "Общий итог" (Grand Total) на "Всего". Cells(3, FinalCol).Value = "Всего"

MsgBox "Отчет о структуре спроса на товары успешно создан."End Sub

На рис. 12.20 показана первая страница отчета, созданного с помощью

макроса ProductLineManagerReport.

Рис. 12.20. Без применения сводных таблиц для создания подоб&ного отчета понадобилось бы разработать гораздо более сложныйкод VBA

Page 326: ? Применение VBA и макросов в Microsoft® Excel

326 Часть II Автоматизация Excel

Создание отчета о прибыльности товаровОтчет о структуре спроса на товары продемонстрировал лишь часть возY

можностей сводных таблиц. В частности, область данных рассмотренной выY

ше сводной таблицы содержала всего одно поле YYYY Выручка.

Область данных сводной таблицы, использующейся для создания отчета о

прибыльности товаров, содержит четыре поля YYYY Выручка, Количество, Се-бестоимость и Прибыль. В итоговом отчете должна быть отражена следуюY

щая информация: общее количество проданного товара, общая выручка от

продажи товара, средняя цена единицы товара, общая себестоимость проданY

ного товара, средняя себестоимость единицы товара, валовая прибыль и валоY

вая прибыль в процентах.

На рис. 12.21 показан макет сводной таблицы, созданный с помощью польY

зовательского интерфейса Excel.

Рис. 12.21. Область данных своднойтаблицы может включать несколькополей

По умолчанию Excel помещает поля области данных сводной таблицы в

последовательные ячейки столбца, как показано на рис. 12.22.

Рис. 12.22. Стандартный способ представления по&лей данных сводной таблицы не подходит для соз&дания отчета

Page 327: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 327

С помощью пользовательского интерфейса Excel перетащите кнопку

Данные на кнопку Товар и отпустите ее. К сожалению, сводная таблица, поY

казанная на рис. 12.23, все еще не пригодна для создания отчета.

Выходом из сложившейся ситуации является перенесение поля Данные в

область столбцов сводной таблицы. Начав перетаскивать кнопку Данные, обY

ратите внимание на форму курсора мыши. Область сводной таблицы, в котоY

рую будет перенесено поле, обозначена синим цветом (рис. 12.24).

Областьстрок

Областьданных

Удалитьполе

Областьстолбцов

Областьстраницы

Рис. 12.23. Перемена мест полейДанные и Товар не привела кжелаемому результату

Рис. 12.24. Область сводной таблицы,в которую будет перенесено поле, обо&значена синим цветом

Результат перенесения поля Данные в область столбцов сводной таблицы

показан на рис. 12.25.

Рис. 12.25. После перенесения поля Данные в область столбцов своднаятаблица стала напоминать вполне привычный финансовый отчет

Если в область данных сводной таблицы помещается несколько полей, ExY

cel автоматически объединяет их в виртуальное поле Данные. Чтобы опредеY

лить внешний вид сводной таблицы с помощью VBA, воспользуйтесь методом

AddFields.

Сводная таблица, показанная на рис. 12.22, может быть получена в резульY

тате выполнения следующей строки кода:

PT.AddFields RowFields:=Array("Товар", "Данные")

А вот как добиться результата, показанного на рис. 12.23:

PT.AddFields RowFields:=Array("Данные", "Товар")

Page 328: ? Применение VBA и макросов в Microsoft® Excel

328 Часть II Автоматизация Excel

Чтобы поместить поле Данные в область столбцов сводной таблицы, восY

пользуйтесь приведенным ниже кодом:

PT.AddFields RowFields:="Товар", ColumnFields:="Данные"

После добавления в область столбцов сводной таблицы поля Данные опреY

делите поля области данных:

' Определение полей области данных.With PT.PivotFields("Количество") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0" .Name = "Общее количество"End With

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0" .Name = "Общая выручка"End With

With PT.PivotFields("Себестоимость") .Orientation = xlDataField .Function = xlSum .Position = 4 .NumberFormat = "#,##0" .Name = "Общая себестоимость"End With

With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 6 .NumberFormat = "#,##0" .Name = "Валовая прибыль"End With

Определение вычисляемых полей области данных

Сводные таблицы поддерживают два типа формул. Наиболее часто испольY

зуемый тип формул предназначен для добавления к сводной таблице вычисY

ляемых полей. Подсчет значений вычисляемого поля осуществляется на осноY

ве итоговых значений полей, входящих в формулу вычисляемого поля. НаY

пример, при создании поля СредняяЦена с помощью формулы Выручка/Количество Excel вычислит общую сумму по полю Выручка, общую сумму

по полю Количество и поделит первое значение на второе. В большинстве

случаев это именно то, что нужно.

Чтобы добавить вычисляемое поле с помощью VBA, воспользуйтесь метоY

дом Add объекта CalculatedFields. Метод Add имеет два параметра: имя

вычисляемого поля (Name) и его формула (Formula). Обратите внимание, что

Page 329: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 329

при определении вычисляемого поля с именем СредняяЦена Excel автоматиY

чески создаст поле сводной таблицы Сумма по полю СредняяЦена (Sum of

СредняяЦена), что выглядит весьма нелепо. Устранить недоразумение позвоY

ляет свойство Name поля сводной таблицы. Также следует отметить, что имя

поля сводной таблицы должно отличаться от имени соответствующего вычисY

ляемого поля.

Ниже приведен полный код макроса, создающего отчет о прибыльности

товаров.

Sub AccountingReport() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

WSD.Range("J1:M1").EntireColumn.Clear

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Товар", ColumnFields:="Данные"

' Определить вычисляемые поля. PT.CalculatedFields.Add Name:="СредняяЦена", _Formula:="=Выручка/Количество" PT.CalculatedFields.Add Name:="СредняяСебестоимость", _Formula:="=Себестоимость/Количество" PT.CalculatedFields.Add Name:="ВаловаяПрибыль_%", _Formula:="=Прибыль/Выручка"

' Определить поля области данных. With PT.PivotFields("Количество") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0" .Name = "Общее количество" End With

With PT.PivotFields("Выручка")

Page 330: ? Применение VBA и макросов в Microsoft® Excel

330 Часть II Автоматизация Excel

.Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0" .Name = "Общая выручка" End With

With PT.PivotFields("СредняяЦена") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "#,##0.00" .Name = "Средняя цена" End With

With PT.PivotFields("Себестоимость") .Orientation = xlDataField .Function = xlSum .Position = 4 .NumberFormat = "#,##0" .Name = "Общая себестоимость" End With

With PT.PivotFields("СредняяСебестоимость") .Orientation = xlDataField .Function = xlSum .Position = 5 .NumberFormat = "#,##0.00" .Name = "Средняя себестоимость" End With

With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 6 .NumberFormat = "#,##0" .Name = "Валовая прибыль" End With

With PT.PivotFields("ВаловаяПрибыль_%") .Orientation = xlDataField .Function = xlSum .Position = 7 .NumberFormat = "#0.0%" .Name = "Валовая прибыль, %" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

End Sub

Результат выполнения макроса AccountingReport показан на рис. 12.26.

Page 331: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 331

Рис. 12.26. Полученный отчет позволяет составить мнение о прибыльности товаров

“Подводные камни” вычисляемых элементов

В отличие от вычисляемых полей, вычисляемые элементы сводной таблицы

редко используются на практике. Главная особенность вычисляемого элемента

состоит в возможности его добавления к существующему полю сводной таблицы.

Рассмотрим пример использования вычисляемых элементов. ПредполоY

жим, что одно подразделение компании занимается продажами товаров ABC

и DEF, а другое подразделение YYYY продажами товара XYZ. Добавим к полю

Товар элемент, вычисляющий сумму содержимого элементов ABC и DEF.

Sub CalculatedItemsAreEvil() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range Dim FinalRow As Long

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

WSD.Range("J1:M1").EntireColumn.Clear

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Товар", ColumnFields:="Данные"

' Создать вычисляемый элемент в поле "Товар". PT.PivotFields("Товар").CalculatedItems.Add _"Подразделение1", "=ABC+DEF"' Переместить вычисляемый элемент на 3-ю позицию. PT.PivotFields("Товар").PivotItems( _"Подразделение1").Position = 3

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0"

Page 332: ? Применение VBA и макросов в Microsoft® Excel

332 Часть II Автоматизация Excel

.Name = "Общая выручка" End With

With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0" .Name = "Валовая прибыль" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

End Sub

Результат выполнения макроса CalculatedItemsAreEvil показан на

рис. 12.27.

Проанализируем содержимое поля Общая выручка полученной сводной

таблицы. Подсчет значения вычисляемого элемента вполне корректен: 46 млн

(товар ABC) плюс 47 млн (товар DEF) примерно равняются 93 млн. Однако

итоговое значение общей выручки должно равняться 146 млн (93 млн плюс

53 млн), но никак не 241 млн! Очевидно, что при подсчете строки Общийитог (Grand Total) Excel не делает различие между обычными и вычисляемыY

ми элементами. Единственный способ исправить положение заключается в

сокрытии строк, соответствующих товарам ABC и DEF:

With PT.PivotFields("Товар") .PivotItems("ABC").Visible = False .PivotItems("DEF").Visible = FalseEnd With

Результат выполнения измененного макроса показан на рис. 12.28.

Рис. 12.27. Использование вычисляемых эле&ментов чревато весьма неприятными послед&ствиями

Рис. 12.28. После сокрытия строк, соответст&вующих товарам ABC и DEF, сводная таблицавновь содержит корректные сведения

Суммирование значений полей области данныхсводной таблицы путем группирования

Сводная таблица, показанная на рис. 12.29, содержит огромное число

строк — по одной на каждый день отгрузки товара.

Page 333: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 333

Рис. 12.29. До группирования сводная таблица со&держит огромное число строк — по одной на каждыйдень отгрузки товара

В большинстве случаев такая детализация отчета избыточна YYYY гораздо боY

лее удобно анализировать итоговые объемы продаж за определенный промеY

жуток времени (например, месяц или квартал).

К счастью, Excel поддерживает группирование дат в сводной таблице. Это

гораздо эффективнее использования загадочной формулы =A2+1-ДЕНЬ(A2)(=A2+1-DAY(A2)), преобразующей произвольную дату в дату, соответствуюY

щую первому дню исходного месяца и года.

Чтобы сгруппировать даты с помощью пользовательского интерфейса ExY

cel, выделите любую ячейку в столбце ДатаОтгрузки и выберите команду

Группа и структура Группировать (Group and Show Detail) из раскрываюY

щегося списка Сводная таблица (PivotTable) панели инструментов Сводныетаблицы (PivotTable). В открывшемся диалоговом окне Группирование(Grouping) выберите значения Месяцы (Months), Кварталы (Quarters), Годы(Years) и щелкните на кнопке ОК (рис. 12.30).

Перед выполнением указанных выше действий сводная таблица содержала

поле ДатаОтгрузки с группированием дат по дням. После изменения спосоY

ба группирования дат сводная таблица также содержит поле ДатаОтгрузки,

однако теперь даты в этом поле сгруппированы по месяцам. Кроме того, в

сводную таблицу было добавлено два новых поля YYYY Годы (Years) и Кварталы

Page 334: ? Применение VBA и макросов в Microsoft® Excel

334 Часть II Автоматизация Excel

(Quarters). При группировании дат поле с наибольшей детализацией всегда

перенимает имя исходного поля, а остальные поля добавляются к сводной

таблице по мере необходимости.

Рис. 12.30. Диалоговое окно Группирование позволя&ет выбрать шаг группирования дат в сводной таблице

Результат группирования дат сводной таблицы по месяцам, кварталам и

годам показан на рис. 12.31.

Рис. 12.31. Сводные таблицы Excel поддерживают группирование дат помесяцам, кварталам и годам

Page 335: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 335

Чтобы выполнить аналогичное действие в VBA, следует воспользоваться

методом Group. Метод Group должен быть применен к диапазону, состоящеY

му из одной ячейки, YYYY заголовка столбца ДатаОтгрузки или любой его

ячейки с датой. Обратите внимание, что впервые в этой главе Excel позволяетY

ся пересчитать промежуточную сводную таблицу.

Прежде всего, создадим сводную таблицу с полем ДатаОтгрузки в обласY

ти столбцов и пересчитаем ее (это необходимо для заполнения поля ДатаОт-грузки данными). При группировании дат обратимся к свойству Label-Range, возвращающему заголовок соответствующего поля сводной таблицы.

Sub ReportByMonth() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="ДатаОтгрузки", ColumnFields:="Регион"

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0" .Name = "Общая выручка" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Сгруппировать содержимое столбца "ДатаОтгрузки"' по месяцам, кварталам и годам. PT.PivotFields("ДатаОтгрузки").LabelRange.Group _Start:=True, End:=True, Periods:=Array(False, False, False, _

Page 336: ? Применение VBA и макросов в Microsoft® Excel

336 Часть II Автоматизация Excel

False, True, True, True)

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

End Sub

Группирование дат по неделям

Excel позволяет группировать даты по дням, месяцам, кварталам, годам, но

не по неделям. Этот недочет легко исправить путем определения единицы

группирования, состоящей из 7 дней.

По умолчанию Excel начинает группирование с первой даты исходных

данных, в рассматриваемом случае YYYY с четверга 1 января 2004 года. Чтобы наY

чать группирование с понедельника, следует воспользоваться параметром

Start метода Group. Функция Weekday поможет определить смещение перY

вой даты исходных данных от начала недели.

Группирование по неделям имеет один существенный недостаток YYYY оно

исключает возможность какогоYлибо иного группирования. Другими словами,

Excel не разрешает группировать даты по неделям и, к примеру, кварталам.

Ниже приведен код, реализующий группирование дат сводной таблицы по

неделям.

Sub ReportByWeek() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="ДатаОтгрузки", ColumnFields:="Регион"

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1

Page 337: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 337

.NumberFormat = "#,##0" .Name = "Общая выручка" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Сгруппировать содержимое столбца "ДатаОтгрузки" по неделям.' Определить дату понедельника 1-й недели. FirstDate = PT.PivotFields("ДатаОтгрузки").LabelRange.Offset( _1, 0).Value WhichDay = Application.WorksheetFunction.Weekday(FirstDate, 3) StartDate = FirstDate - WhichDay PT.PivotFields("ДатаОтгрузки").LabelRange.Group _Start:=StartDate, End:=True, By:=7, _ Periods:=Array(False, False, False, True, False, _False, False)

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

End Sub

Результат выполнения макроса ReportByWeek показан на рис. 12.32.

Рис. 12.32. При необходимости даты сводной таблицыможно сгруппировать по неделям

Page 338: ? Применение VBA и макросов в Microsoft® Excel

338 Часть II Автоматизация Excel

Определение сроков выполнения заказов

Как упоминалось выше, при группировании дат поле с наибольшей детаY

лизацией всегда перенимает имя исходного поля, а остальные поля

(например, Годы (Years) или Кварталы (Quarters)) добавляются к сводной

таблице по мере необходимости.

Предположим, что предприятию необходимо определить сроки выполнеY

ния заказов. Полный цикл производства товара включает 12Yнедельную заY

держку, связанную с поставкой необходимых компонентов. В идеальной сиY

туации на выполнение заказа отводится не менее 13 недель. В противном слуY

чае следует реализовать систему прогнозирования поступления заказов.

Добавив к исходным данным поле ДатаЗаказа, создадим сводную таблиY

цу, показывающую поступление выручки от выполнения заказов по месяцам.

1. Создайте сводную таблицу с полем ДатаОтгрузки в области строк и

полем Выручка в области данных. Сгруппируйте поле ДатаОтгрузкипо месяцам и годам, в результате чего Excel создаст два новых поля YYYY

ДатаОтгрузки и Годы (Years).

2. Поместите поля ДатаОтгрузки и Годы в область столбцов сводной

таблицы.

3. Добавьте поле ДатаЗаказа к области строк сводной таблицы.

4. Сгруппируйте поле ДатаЗаказа по месяцам и годам, в результате чего

Excel создаст два новых поля YYYY ДатаЗаказа и Годы2 (Years2).

Следует отметить, что новые версии Excel корректно справляются с групY

пировкой дат в нескольких полях сводной таблицы, подтверждением чего моY

жет служить факт создания поля Годы2 вместо поля Годы.

Ниже приведен полный код макроса, создающего отчет о поступлении выY

ручки от выполнения заказов по месяцам.

Sub MeasureLeadtime() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные (2)")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Page 339: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 339

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("K2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк. PT.AddFields RowFields:="ДатаОтгрузки"

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0" .Name = "Общая выручка" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Сгруппировать содержимое поля "ДатаОтгрузки" по месяцам и годам. PT.PivotFields("ДатаОтгрузки").LabelRange.Group _Start:=True, End:=True, Periods:=Array(False, False, False, _False, True, False, True)

' Поместить поля "Годы" и "ДатаОтгрузки" в область столбцов. With PT.PivotFields("Годы") .Orientation = xlColumnField .Position = 1 End With With PT.PivotFields("ДатаОтгрузки") .Orientation = xlColumnField .Position = 2 End With

' Добавить поле "ДатаЗаказа" в область строк. With PT.PivotFields("ДатаЗаказа") .Orientation = xlRowField .Position = 1 End With

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Сгруппировать содержимое поля "ДатаЗаказа" по месяцам и годам. PT.PivotFields("ДатаЗаказа").LabelRange.Group _Start:=True, End:=True, Periods:=Array(False, False, False, _False, True, False, True)

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

End Sub

Page 340: ? Применение VBA и макросов в Microsoft® Excel

340 Часть II Автоматизация Excel

Результат выполнения макроса MeasureLeadtime показан на рис. 12.33.

Рис. 12.33. Данный отчет свидетельствует о том, что пред&приятие нуждается в гибкой системе прогнозирования по&ступления заказов

Дополнительные возможности сводных таблицЗачастую даже опытные пользователи Excel не знакомы со всеми возможY

ностями сводных таблиц. Восполним же этот пробел!

Отображение лучшей десятки заказчиков

Согласно широко известному правилу 80/20, 80% дохода компании приноY

сят 20% ее клиентов. В реальных условиях это не так уж далеко от истины.

Создавая отчет для руководства компании, разумно включить в него данY

ные о 5YY10 лучших заказчиках.

Чтобы отобразить заданное число наибольших (наименьших) элементов поY

ля сводной таблицы с помощью пользовательского интерфейса Excel, щелкните

на кнопке Дополнительно (Advanced) диалогового окна Вычисление полясводной таблицы (PivotTable Field). Установите переключатель Включено (On),

выберите из раскрывающегося списка Отображать (Show) значение

Наибольших (Top), установите значение расположенного справа от списка

Отображать счетчика равным 6 и выберите из раскрывающегося списка

Page 341: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 341

С помощью поля (Using field) значение Сумма по полю Выручка (Sum of ВыY

ручка), как показано на рис. 12.34.

Рис. 12.34. Функция Автоотображение лучшей десятки(Top 10 AutoShow) позволяет отобразить заданное число наи&больших (наименьших) элементов поля сводной таблицы

На заметку Название функции Автоотображение лучшей десятки (Top 10 AutoShow) можетввести в заблуждение. На самом деле, Excel позволяет отобразить заданное число(от 1 до 500) как наибольших, так и наименьших значений поля сводной таблицы.

Чтобы отобразить 6 наибольших элементов поля Заказчик с расчетом по

полю Общая выручка в VBA, воспользуйтесь методом AutoShow:

' Вывести 6 лучших заказчиков.PT.PivotFields("Заказчик").AutoShow Type:=xlAutomatic, _Range:=xlTop, Count:=6, Field:="Общая выручка"

Вызвав метод AutoShow и пересчитав сводную таблицу, рекомендуется

скопировать полученный отчет, после чего вернуться к исходной сводной

таблице, чтобы подсчитать значение поля Общая выручка для всех заказY

чиков. В приведенном ниже коде это достигается путем удаления поля За-казчик из сводной таблицы, ее пересчета и копирования в отчет полученY

ной итоговой строки.

Sub Top6CEOReport()' Этот макрос создает отчет о 6 лучших заказчиках' с полями "Общая прибыль", "Валовая прибыль" и' "Валовая прибыль, %". Dim WSD As Worksheet Dim WSR As Worksheet Dim WBN As Workbook Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

Page 342: ? Применение VBA и макросов в Microsoft® Excel

342 Часть II Автоматизация Excel

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Заказчик", ColumnFields:="Данные"

' Определить вычисляемые поля. PT.CalculatedFields.Add Name:="ВаловаяПрибыль_%", _Formula:="=Прибыль/Выручка"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" .Name = "Общая выручка" End With

With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0,K" .Name = "Валовая прибыль" End With

With PT.PivotFields("ВаловаяПрибыль_%") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "#0.0%" .Name = "Валовая прибыль, %" End With

' Отсортировать поле "Заказчик" по убыванию,' используя значение поля "Общая выручка". PT.PivotFields("Заказчик").AutoSort Order:=xlDescending, _Field:="Общая выручка"

' Отобразить 6 наибольших значений поля "Заказчик"' с расчетом по полю "Общая выручка". PT.PivotFields("Заказчик").AutoShow Type:=xlAutomatic, _Range:=xlTop, Count:=6, Field:="Общая выручка"

Page 343: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 343

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Создать новую рабочую книгу' с одним рабочим листом. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSR = WBN.Worksheets(1) WSR.Name = "Отчет"' Создать заголовок отчета. With WSR.[A1] .Value = "6 лучших заказчиков" .Font.Size = 14 End With

' Скопировать диапазон ячеек TableRange2.Offset(1, 0)' в рабочий лист "Отчет" новой рабочей книги. PT.TableRange2.Offset(1, 0).Copy WSR.[A3].PasteSpecial Paste:=xlPasteValuesAndNumberFormats LastRow = WSR.Cells(65536, 1).End(xlUp).Row WSR.Cells(LastRow, 1).Value = "Всего (по 6 заказчикам)"

' Подсчитать значение поля "Общая выручка" для всех заказчиков. PT.PivotFields("Заказчик").Orientation = xlHidden PT.ManualUpdate = False PT.ManualUpdate = True PT.TableRange2.Offset(2, 0).Copy WSR.Cells(LastRow + 2, 1).PasteSpecial Paste:= _xlPasteValuesAndNumberFormats WSR.Cells(LastRow + 2, 1).Value = "Всего (по всем заказчикам)"

' Удалить сводную таблицу и объект PivotCache. PT.TableRange2.Clear Set PTCache = Nothing

' Применить стилевое форматирование:' - выделить заголовки столбцов полужирным шрифтом;' - выровнять заголовки столбцов по правому краю;' - выполнить автоподбор ширины столбцов отчета. Range("A3").EntireRow.Font.Bold = True Range("A3").EntireRow.HorizontalAlignment = xlRight Range("A3").HorizontalAlignment = xlLeft Range("B3").Value = "Общая выручка" WSR.Range(WSR.Range("A2"), WSR.Cells(LastRow + 2,4)).Columns.AutoFit

Range("A2").Select MsgBox "Отчет для руководства компании успешно создан"

End Sub

Результат выполнения макроса Top6CEOReport показан на рис. 12.35.

Page 344: ? Применение VBA и макросов в Microsoft® Excel

344 Часть II Автоматизация Excel

Рис. 12.35. Отчет о 6 лучших заказчиках компании создан на основе двухсводных таблиц

Обратите внимание, что отчет о 6 лучших заказчиках компании был создан

на основе двух сводных таблиц YYYY таблицы с полем Заказчик в области строк,

которая позволила получить список 6 лучших заказчиков, и таблицы без полей в

области строк, которая использовалась для подсчета итоговой выручки.

Использование сводной таблицы для фильтрацииисходных данных

Проведем небольшой эксперимент. Дважды щелкните на любом числовом

значении сводной таблицы, в результате чего Excel создаст новый рабочий лист и

скопирует в него все записи исходных данных, на основании которых было полуY

чено это числовое значение. По существу, эта особенность сводных таблиц предY

ставляет собой простейший способ выполнения запросов к исходным данным.

Чтобы добиться аналогичного результата в VBA, следует установить значеY

ние свойства диапазона ячеек ShowDetail равным True, как показано ниже:

PT.TableRange2.Offset(2, 1).Resize(1, 1).ShowDetail = True

Следующий макрос создает сводную таблицу, содержащую сведения об

общей выручке, приходящейся на трех лучших заказчиков. Подробная инY

формация обо всех сделках каждого заказчика выводится на отдельном рабоY

чем листе. Похожая задача рассматривалась в практикуме ‘‘Использование

двух расширенных фильтров для создания отчетов по каждому заказчику’’ на

с. 293, где для ее решения предлагалось использовать расширенный фильтр.

Sub RetrieveTop3CustomerDetail() Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

Page 345: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 345

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Заказчик", ColumnFields:="Данные"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" .Name = "Общая выручка" End With

' Отсортировать поле "Заказчик" по убыванию,' используя значение поля "Общая выручка". PT.PivotFields("Заказчик").AutoSort Order:=xlDescending, _Field:="Общая выручка"

' Отобразить 3 наибольших значения поля "Заказчик"' с расчетом по полю "Общая выручка". PT.PivotFields("Заказчик").AutoShow Type:=xlAutomatic, _Range:=xlTop, Count:=3, Field:="Общая выручка"

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Создать отчеты о сделках каждого заказчика. For i = 1 To 3 PT.TableRange2.Offset(i + 1, 1).Resize(1, 1).ShowDetail =True Range("A1:A2").EntireRow.Insert Range("A1").Value = "Информация о сделках с заказчиком " _& PT.TableRange2.Offset(i + 1, 0).Resize(1, 1).Value & " _(порядковый номер в списке лучших заказчиков: " & i & ")"

Next i

MsgBox "Отчеты о сделках с 3-мя лучшими заказчиками _успешно созданы"

End Sub

Page 346: ? Применение VBA и макросов в Microsoft® Excel

346 Часть II Автоматизация Excel

Отчет о сделках самого крупного заказчика, полученный в результате выY

полнения макроса RetrieveTop3CustomerDetail, показан на рис. 12.36.

Рис. 12.36. В результате выполнения макроса была создана сводная таблица, со&держащая сведения о 3&х лучших заказчиках, а также подробные отчеты о сделкахкаждого из заказчиков

Использование полей области страницы сводной таблицы

В добавок к полям в области строк, области столбцов и области данных,

сводная таблица может содержать одно или несколько полей в области страY

ницы. Поля области страницы выводятся в строках, расположенных над отчеY

том сводной таблицы. Они могут использоваться для фильтрации отчета по

различным критериям, например, по товару, региону или комбинации товара

и региона. На рис. 12.37 показана сводная таблица, отображающая 10 лучших

заказчиков товара ABC в западном регионе.

Чтобы определить поле области страницы в VBA, воспользуйтесь параметY

ром PageFields метода AddFields. Следующий код определяет сводную

таблицу с полем Регион в области страницы:

PT.AddFields RowFields:="Заказчик", ColumnFields:="Данные", _PageFields:="Регион"

По умолчанию значение поля области страницы Регион устанавливается

равным (Все) ((All)). Чтобы ограничиться данными только по какомуYлибо

определенному региону (например, западному), воспользуйтесь свойством

CurrentPage объекта PivotField:

PT.PivotFields("Регион").CurrentPage = "Запад"

Page 347: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 347

Рис. 12.37. Область страницы сводной таблицы содержит по&ля Регион и Товар, которые могут использоваться дляфильтрации отчета по товару, региону или их комбинации

Поля области страницы часто применяются при создании пользовательY

ской формы, позволяющей выбрать требуемый регион или товар. Присвоив

выбранное значение свойству CurrentPage, можно быстро получить требуеY

мый отчет.

Другое применение поля области страницы заключается в создании отчеY

тов для всех значений этого поля. К примеру, чтобы определить общее число

регионов, воспользуйтесь свойством Count объекта PivotItems:

PT.PivotFields("Регион").PivotItems.Count

Ниже приведено два равноценных цикла по всем значениям поля Регион:

For i = 1 To PT.PivotFields("Регион").PivotItems.Count PT.PivotFields("Регион").CurrentPage = _PT.PivotFields("Регион").PivotItems(i).Name PT.ManualUpdate = False PT.ManualUpdate = TrueNext i

For Each PivItem In PT.PivotFields("Регион").PivotItems PT.PivotFields("Регион").CurrentPage = PivItem.Name PT.ManualUpdate = False PT.ManualUpdate = TrueNext PivItem

Конечно же, поочередный вывод отчетов на экран имеет немного практиY

ческого смысла. Обычно отчет создается для его последующего сохранения.

Ранее в этой главе для копирования содержимого сводной таблицы приY

менялось свойство TableRange2 объекта PivotTable. Свойство Table-Range2 ссылается на все строки сводной таблицы, включая строки полей обY

ласти страницы. Чтобы исключить строки полей области страницы, воспольY

зуйтесь свойством TableRange1 объекта PivotTable. Следующие строки

ссылаются на одинаковый диапазон ячеек рабочего листа, показанного на

рис. 12.37:

Page 348: ? Применение VBA и макросов в Microsoft® Excel

348 Часть II Автоматизация Excel

PT.TableRange2.Offset(4, 0)PT.TableRange1.Offset(1, 0)

Выбор того или иного свойства YYYY дело личного предпочтения. Тем не меY

нее, свойство TableRange2 имеет некоторое преимущество, так как вызов

метода TableRange2.Clear позволяет удалить сводную таблицу с рабочего

листа. А вот попытка вызова метода TableRange1.Clear неминуемо заверY

шится выводом сообщения об ошибке времени выполнения 1004, напомиY

нающего о невозможности перемещения или изменения части сводной табY

лицы Excel.

Следующий макрос создает отчеты о 10 лучших заказчиках в каждом из

регионов. Каждый отчет помещается в новую рабочую книгу.

Sub Top10ByRegionReport()' Этот макрос создает отчет о 10 лучших' заказчиках в каждом из регионов. Dim WSD As Worksheet Dim WSR As Worksheet Dim WBN As Workbook Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк, области' столбцов и области страницы. PT.AddFields RowFields:="Заказчик", ColumnFields:="Данные", _PageFields:="Регион"

' Определить вычисляемые поля. PT.CalculatedFields.Add Name:="ВаловаяПрибыль_%", _Formula:="=Прибыль/Выручка"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K"

Page 349: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 349

.Name = "Общая выручка" End With

With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0,K" .Name = "Валовая прибыль" End With

With PT.PivotFields("ВаловаяПрибыль_%") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "#0.0%" .Name = "Валовая прибыль, %" End With

' Отсортировать поле "Заказчик" по убыванию,' используя значение поля "Общая выручка". PT.PivotFields("Заказчик").AutoSort Order:=xlDescending, _Field:="Общая выручка"

' Отобразить 10 наибольших значений поля "Заказчик"' с расчетом по полю "Общая выручка". PT.PivotFields("Заказчик").AutoShow Type:=xlAutomatic, _Range:=xlTop, Count:=10, Field:="Общая выручка"

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True Ctr = 0

' Создать цикл по всем значениям поля "Регион". For Each PivItem In PT.PivotFields("Регион").PivotItems Ctr = Ctr + 1 PT.PivotFields("Регион").CurrentPage = PivItem.Name PT.ManualUpdate = False PT.ManualUpdate = True

' Создать новую рабочую книгу с одним рабочим листом. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSR = WBN.Worksheets(1) WSR.Name = PivItem.Name' Создать заголовок отчета. With WSR.[A1] .Value = "10 лучших заказчиков в регионе " & _PivItem.Name .Font.Size = 14 End With

' Скопировать диапазон ячеек TableRange2.Offset(3, 0)' в рабочий лист новой рабочей книги. PT.TableRange2.Offset(3, 0).Copy WSR.[A3].PasteSpecial Paste:=xlPasteValuesAndNumberFormats

Page 350: ? Применение VBA и макросов в Microsoft® Excel

350 Часть II Автоматизация Excel

LastRow = WSR.Cells(65536, 1).End(xlUp).Row WSR.Cells(LastRow, 1).Value = "Всего ( _по 10 лучшим заказчикам)"

' Применить стилевое форматирование:' - выделить заголовки столбцов полужирным шрифтом;' - выровнять заголовки столбцов по правому краю;' - выполнить автоподбор ширины столбцов отчета. Range("A3").EntireRow.Font.Bold = True Range("A3").EntireRow.HorizontalAlignment = xlRight Range("A3").HorizontalAlignment = xlLeft Range("B3").Value = "Выручка" WSR.Range(WSR.Range("A3"), WSR.Cells( _LastRow, 4)).Columns.AutoFit

Range("A2").Select

Next PivItem

' Удалить сводную таблицу и объект PivotCache. PT.TableRange2.Clear Set PTCache = Nothing

MsgBox Ctr & " отчета о лучших заказчиках в регионах _успешно созданы"

End Sub

Отчеты, созданные в результате выполнения макроса Top10ByRegion-Report, показаны на рис. 12.38.

Рис. 12.38. Отчеты о 10 лучших заказчиках в каждом регионе созданы с помощью цикла повсем значениям поля Регион

Page 351: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 351

Фильтрация элементов полей сводной таблицы вручную

Вдобавок к созданию вычисляемых элементов, Excel позволяет фильтроY

вать элементы полей сводной таблицы вручную.

Рассмотрим следующую задачу. К примеру, некий продавец обуви желает

получить отчет о продажах сандалий в регионах с теплым климатом. СледуюY

щая строка кода позволяет скрыть определенный элемент поля Магазин:

PT.PivotFields("Магазин").PivotItems("Миннеаполис").Visible = False

Присвоение значения False свойству Visible всех элементов поля приY

ведет к возникновению ошибки времени выполнения. К примеру, на 1Yй итеY

рации цикла макрос может отобразить товары A и B, а на 2Yй итерации YYYY тоY

вары C и D. Если скрыть товары A и B до того, как будут отображены товаY

ры C и D, возникнет ошибка. Чтобы избежать подобного недоразумения,

присвойте значение True свойству Visible всех элементов поля перед его

фильтрацией.

Создадим отчет, включающий информацию о выручке, прибыли и валовой

прибыли (%) от продаж товаров ABC и DEF по регионам.

Чтобы создать такой отчет с помощью пользовательского интерфейса

Excel, необходимо выполнить следующие действия.

1. Создать сводную таблицу с полем Регион в области строк, полем То-вар в области столбцов и полем Выручка в области данных.

2. Вручную отфильтровать поле Товар, скрыв все элементы за исключеY

нием ABC и DEF.

3. Переместить поле Товар из области столбцов в область страницы.

4. Поместить поля Прибыль и ВаловаяПрибыль_% (вычисляемое поле) в

область данных.

Сводная таблица, полученная в результате выполнения указанных выше

действий, показана на рис. 12.39.

Рис. 12.39. Элемент XYZ поля Товар скрыт, однако обэтом нет никаких уведомлений

Узнать о том, что элемент XYZ поля Товар скрыт, позволяет лишь раскрыY

вающийся список, расположенный справа от названия поля Товар (рис. 12.40).

Создание подобного отчета рекомендуется автоматизировать с помощью

VBA. Это позволит не только добавить заголовок и стилевое форматирование,

Page 352: ? Применение VBA и макросов в Microsoft® Excel

352 Часть II Автоматизация Excel

но и поместить поле Товар непосредственно в область страницы, отфильтроY

вав нужные элементы с помощью свойства Visible.

Рис. 12.40. Факт фильтрации поля Товар обнаруживаетсялишь при раскрытии соответствующего списка

Ниже приведен полный код макроса, создающего отчет о продажах товаров

ABC и DEF по регионам.

Sub ProduceReportOfTwoProducts()' Этот макрос создает отчет о продажах' товаров ABC и DEF в регионах. Dim WSD As Worksheet Dim WSR As Worksheet Dim WBN As Workbook Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Регион", ColumnFields:=Array( _"Данные", "Товар")

' Определить вычисляемые поля. PT.CalculatedFields.Add Name:="ВаловаяПрибыль_%", _

Page 353: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 353

Formula:="=Прибыль/Выручка"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" .Name = "Общая выручка" End With

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True

' Убедиться, что поле "Товар" не содержит скрытых элементов. For Each PivItem In PT.PivotFields("Товар").PivotItems PivItem.Visible = True Next PivItem

' Отфильтровать поле "Товар". For Each PivItem In PT.PivotFields("Товар").PivotItems Select Case PivItem.Name Case "ABC", "DEF" PivItem.Visible = True Case Else PivItem.Visible = False End Select Next PivItem

' Переместить поле "Товар" в область страницы. PT.PivotFields("Товар").Orientation = xlPageField

' Добавить оставшиеся поля области данных. With PT.PivotFields("Прибыль") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "#,##0,K" .Name = "Валовая прибыль" End With

With PT.PivotFields("ВаловаяПрибыль_%") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "#0.0%" .Name = "Валовая прибыль, %" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True Ctr = 0

Page 354: ? Применение VBA и макросов в Microsoft® Excel

354 Часть II Автоматизация Excel

' Создать новую рабочую книгу с одним рабочим листом. Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSR = WBN.Worksheets(1) WSR.Name = "Отчет"' Создать заголовок отчета. With WSR.[A1] .Value = "Продажи по регионам - только товары ABC и DEF" .Font.Size = 14 End With

' Скопировать диапазон ячеек TableRange2.Offset(3, 0)' в рабочий лист новой рабочей книги. PT.TableRange2.Offset(3, 0).Copy WSR.[A3].PasteSpecial Paste:=xlPasteValuesAndNumberFormats LastRow = WSR.Cells(65536, 1).End(xlUp).Row WSR.Cells(LastRow, 1).Value = "Всего (по товарам ABC и DEF)"

' Применить стилевое форматирование:' - выделить заголовки столбцов полужирным шрифтом;' - выровнять заголовки столбцов по правому краю;' - выполнить автоподбор ширины столбцов отчета. Range("A3").EntireRow.Font.Bold = True Range("A3").EntireRow.HorizontalAlignment = xlRight Range("A3").HorizontalAlignment = xlLeft Range("B3").Value = "Выручка" WSR.Range(WSR.Range("A3"), WSR.Cells(LastRow, _4)).Columns.AutoFit

Range("A2").Select

' Удалить сводную таблицу и объект PivotCache. PT.TableRange2.Clear Set PTCache = Nothing

MsgBox "Отчет о продажах товаров ABC и DEF успешно создан"

End Sub

Результат выполнения макроса ProduceReportOfTwoProducts показан

на рис. 12.41.

Рис. 12.41. VBA позволяет гарантировать отсутствие ошибки временивыполнения и упростить создание отчета о продажах товаров ABC и DEFпо регионам

Page 355: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 355

Сумма, среднее, количество, минимум,максимум и др.

Единственной статистикой, подсчитываемой для поля сводной таблицы

ранее в этой главе, была сумма значений элементов поля. Помимо суммы, ExY

cel позволяет вычислить среднее значение всех элементов поля, минимальное,

максимальное значения и т.п. Чтобы подсчитать требуемую статистику в VBA,

создайте поле области данных с уникальным именем и установите соответстY

вующее значение свойства xlFunction. Следующий макрос демонстрирует

пример вычисления 5Yти различных статистик для поля Выручка по каждому

заказчику.

Sub ReportManyDetailsByCustomer()' Макрос, вычисляющий общую сумму выручки, количество' заказов, среднюю выручку, минимальный и максимальный' заказ для каждого клиента. Dim WSD As Worksheet Dim PTCache As PivotCache Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных и создать' объект кэша сводных таблиц. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8) Set PTCache = ActiveWorkbook.PivotCaches.Add( _SourceType:=xlDatabase, SourceData:=PRange.Address)

Set PT = PTCache.CreatePivotTable(TableDestination:= _WSD.Range("J2"), TableName:="PivotTable1") PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Заказчик", ColumnFields:="Данные"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" .Name = "Общая выручка" End With

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlCount .Position = 2

Page 356: ? Применение VBA и макросов в Microsoft® Excel

356 Часть II Автоматизация Excel

.NumberFormat = "#,##0" .Name = "Кол-во заказов" End With

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlAverage .Position = 3 .NumberFormat = "#,##0" .Name = "Средняя выручка" End With

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlMin .Position = 4 .NumberFormat = "#,##0" .Name = "Минимальный заказ" End With

With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlMax .Position = 5 .NumberFormat = "#,##0" .Name = "Максимальный заказ" End With

' Заполнить нулями пустые ячейки в области данных. PT.NullString = "0"

' Пересчитать сводную таблицу. PT.ManualUpdate = False PT.ManualUpdate = True Ctr = 0

WSD.Select

End Sub

Результат выполнения макроса ReportManyDetailsByCustomer покаY

зан на рис. 12.42.

Дополнительные вычисления в полях областиданных сводной таблицы

Excel позволяет проводить так называемые дополнительные вычисления в

полях области данных сводной таблицы. В частности, значения элементов поY

ля можно отображать в виде доли от общей суммы, доли от суммы по строке,

доли от суммы по столбцу или в виде разницы по отношению к значению

другого элемента (рис. 12.43).

Page 357: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 357

Рис. 12.42. Каждое поле области данных сводной таблицы содержит различную статисти&ку поля Выручка (слева направо): общая сумма выручки, количество заказов, средняясумма выручки, минимальная сумма заказа, максимальная сумма заказа

Рис. 12.43. Excel предлагает разнообразные способыпроведения дополнительных вычислений в поляхобласти данных сводной таблицы

Page 358: ? Применение VBA и макросов в Microsoft® Excel

358 Часть II Автоматизация Excel

В VBA вид дополнительного вычисления определяется с помощью свойстY

ва Calculation объекта PivotField, которое может принимать следующие

значения: xlPercentOf, xlPercentOfColumn, xlPercentOfRow, xlPer-centOfTotal, xlRunningTotal, xlPercentDifferenceFrom, xlDif-ferenceFrom, xlIndex и xlNoAdditionalCalculation. Некоторые тиY

пы вычислений требуют указания базового поля (свойство BaseField объекY

та PivotField) или комбинации базового поля и базового элемента

(свойство BaseItem объекта PivotField). Более подробно дополнительные

вычисления в полях области данных сводной таблицы рассматриваются в слеY

дующих разделах этой главы.

Доля от общей суммы

Чтобы отобразить значения элементов поля в виде доли от общей суммы

по этому полю, установите значение свойства Calculation равным xlPer-centOfTotal, как показано ниже:

' Подсчитать долю от общей суммы.With PT.PivotFields("Выручка") .Orientation = xlDataField .Caption = "Доля от общей суммы" .Function = xlSum .Position = 2 .NumberFormat = "#0.0%" .Calculation = xlPercentOfTotalEnd With

Приведенное отличие от значенияпредыдущего элемента поля

Сгруппировав даты поля ДатаОтгрузки по месяцам, можно составить отY

чет о процентном изменении выручки относительно предыдущего месяца.

Для этого установите значение параметра Calculation равным xlPer-centDifferenceFrom, параметра BaseField — ДатаОтгрузки, а параY

метра BaseItem — (назад) ((previous)).

' Подсчитать процентное отличие от предыдущего месяца.With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Caption = "Отличие, %" .Calculation = xlPercentDifferenceFrom .BaseField = "ДатаОтгрузки" .BaseItem = "(назад)" .Position = 3 .NumberFormat = "#0.0%"End With

Одно из наиболее существенных ограничений, касающееся вычислений,

содержащих позиционные ссылки, заключается в невозможности использоY

вания методов AutoSort и AutoShow. В частности, это не позволяет сравY

Page 359: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 359

нить общий объем закупок товаров заказчиками, предварительно отсортироY

вав поле Заказчик по убыванию с помощью поля Общая выручка.

Приведенное отличие от значениязаданного элемента поля

Предположим, что компания предлагает своим клиентам товары трех каY

тегорий: аппаратное обеспечение, программное обеспечение и договора на

обслуживание компьютерной техники. Менеджеры по продажам получили заY

дание увеличить выручку от продажи программного обеспечения и заключеY

ния договоров на обслуживание на 10% по сравнению с выручкой от продажи

аппаратного обеспечения. Чтобы создать соответствующую сводную таблицу

с помощью VBA, установите значение параметра Calculation равным

xlPercentDifferenceFrom, как показано ниже:

' Подсчитать процентное отличие от выручки, полученной' в результате продажи аппаратного обеспечения.With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Caption = "Отличие (%) от продаж аппаратного обеспечения" .Calculation = xlPercentDifferenceFrom .BaseField = "Товар" .BaseItem = "Аппаратное обеспечение" .Position = 3 .NumberFormat = "#0.0%"End With

Нарастающий итог

Для вычисления нарастающего итога по полю сводной таблицы необходиY

мо указать базовое поле. В рассматриваемом примере таким полем является

поле области строк сводной таблицы ДатаОтгрузки. Таким образом, чтобы

вычислить нарастающий итог по полю Выручка, необходимо установить знаY

чение свойства BaseField равным ДатаОтгрузки, как показано ниже:

' Подсчитать нарастающий итог.With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Caption = "Нарастающий итог" .Calculation = xlRunningTotal .Position = 4 .NumberFormat = "#,##0,K" .BaseField = "ДатаОтгрузки"End With

На рис. 12.44 показана сводная таблица с тремя полями области данных,

полученными в результате описанных выше дополнительных вычислений, а

именно: вычисления доли от общей суммы, приведенного отличия от значеY

ния предыдущего элемента поля и нарастающего итога.

Page 360: ? Применение VBA и макросов в Microsoft® Excel

360 Часть II Автоматизация Excel

Рис. 12.44. Каждое из полей области данных сводной таблицы содержитразличные вычисления на основе суммы по полю Выручка: собственносумма по полю Выручка, доля от общей суммы по полю Выручка, при&веденное отличие от значения предыдущего элемента поля Общая вы-ручка и нарастающий итог по полю Общая выручка

Практикум

Создание сводных таблиц в Excel 97с помощью VBAВпервые сводные таблицы были представлены в Excel 95. В Excel 97 реализациясводных таблиц была значительно улучшена, а в Excel 2000 — кардинальным об&разом изменена за счет добавления объекта кэша сводных таблиц PivotCache.Несмотря на то что Microsoft официально прекратила поддержку Excel 97 несколь&ко лет назад, этим продуктом до сих пор пользуются все еще достаточно многокомпаний. Чтобы обеспечить совместимость кода VBA, созданного с помощью Ex&cel 2003, с Excel 97, его придется изрядно переработать.Для создания сводной таблицы в Excel 97 используется метод PivotTable-Wizard. Рассмотрим пример построения простой сводной таблицы, отображаю&щей выручку от продажи товаров по регионам.Sub PivotExcel97Compatible()' Этот макрос полностью совместим с Excel 97. Dim WSD As Worksheet Dim PT As PivotTable Dim PRange As Range

Set WSD = Worksheets("Данные")

' Удалить существующие сводные таблицы. For Each PT In WSD.PivotTables PT.TableRange2.Clear Next PT

' Задать диапазон исходных данных. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row

Page 361: ? Применение VBA и макросов в Microsoft® Excel

Сводные таблицы Глава 12 361

Set PRange = WSD.Cells(1, 1).Resize(FinalRow, 8)

' Создать сводную таблицу с помощью метода PivotTableWizard. Set PT = WSD.PivotTableWizard(SourceType:=xlDatabase, _SourceData:=PRange.Address, _ TableDestination:="R2C10", TableName:="PivotTable1")

PT.ManualUpdate = True' Определить поля области строк и области столбцов. PT.AddFields RowFields:="Регион", ColumnFields:="Товар"

' Определить поля области данных. With PT.PivotFields("Выручка") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "#,##0,K" .Name = "Общая выручка" End With

PT.ManualUpdate = False PT.ManualUpdate = True

WSD.Select

End Sub

Следующий шагСводные таблицы YYYY чрезвычайно гибкое и мощное средство в арсенале

пользователя Excel. В комбинации с VBA они предоставляют превосходный

вычислительный механизм и основу для создания всевозможных отчетов.

В следующей главе рассматриваются распространенные задачи, встречающиеY

ся при работе с Excel, и их решения с помощью VBA, предлагаемые опытными

программистами со всех уголков мира.

Page 362: ? Применение VBA и макросов в Microsoft® Excel
Page 363: ? Применение VBA и макросов в Microsoft® Excel

Расширение возможностейExcel с помощью VBA.................. 363Файловые операции .................. 365Объединение и разделениерабочих книг .................................372Работа с примечаниями .............376Замечательные возможностиExcel VBA ........................................381VBA для профессионалов.......... 386На закуску ..................................... 402Следующий шаг........................... 405

13Глава 13

Excel âñåìîãóùèé

Первый принцип удачного проY

граммиста состоит в том, чтобы ниY

когда не писать один и тот же код

дважды. Второй принцип удачного

программиста требует создавать код

для каждой рутинной операции.

В настоящей главе рассматриваY

ются макросы, присланные опытY

ными пользователями Excel со

всего мира. Эти программы не

только помогут сэкономить время,

но и прольют свет на новые спосоY

бы решения наиболее распростраY

ненных задач.

Различные программисты приY

держиваются различных подходов к

созданию программного кода. НаY

глядным подтверждением этого явY

ляются приведенные в данной главе

макросы.

Расширениевозможностей Excelс помощью VBA

VBA позволяет раскрыть возможY

ности Excel, недоступные посредстY

вом пользовательского интерфейса.

В следующих разделах рассматриваY

ется использование VBA для реалиY

зации условного форматирования с

более чем тремя условиями, и расY

ширенного фильтра с более чем двуY

мя условиями.

Page 364: ? Применение VBA и макросов в Microsoft® Excel

364 Часть II Автоматизация Excel

Условное форматирование с более чем тремя условиями

Макрос Worksheet_Change любезно предоставлен Расселом Гауфом

(Russell Hauf), проживающим в Бивертоне, штат Орегон, США.

По сути, макрос Worksheet_Change дублирует функцию условного форY

матирования Excel. Увеличение максимального числа условий достигается за

счет наличия управляющего листа, содержащего 2 столбца YYYY допустимых

значений ячеек (столбец A) и соответствующих индексов цвета заливки

(столбец B).

Private Sub Worksheet_Change(ByVal Target As Range)' Этот макрос реализует условное форматирование' с более чем 3-мя условиями. Dim rng As Range' Исходный диапазон может содержать более чем 1 ячейку,' поскольку он задается как пересечение диапазонов Target' и D:D. Благодаря этому макрос будет выполняться корректно' при удалении содержимого нескольких ячеек столбца D или' вводе значений нескольких ячеек столбца D в виде массива. Set rng = Intersect(Target, Range("D:D")) If rng Is Nothing Then Exit Sub Else Dim cl As Range For Each cl In rng On Error Resume Next' Если содержимое ячейки отсутствует' в диапазоне rngColors, ее заливка удаляется. cl.Interior.ColorIndex = _ Application.WorksheetFunction.VLookup(cl.Value, _ThisWorkbook.Sheets("УФ (управляющий лист)").Range("rngColors"), _2, False) If Err.Number <> 0 Then cl.Interior.ColorIndex = xlNone End If Next cl End IfEnd Sub

Расширенный фильтр с более чем двумя условиями

Макрос MultiFilter любезно предоставлен Ричи Силлсом (Richie Sills),

проживающим в Вустере, Англия. Ричи работает консультантом по налогам в

аудиторской компании.

Стандартный расширенный фильтр Excel позволяет задавать не более двух

условий. Следующий макрос позволяет обойти это ограничение.

Sub MultiFilter()' Обратите внимание, что Ричи размещает комментарии после кода.' Другими словами, комментарий на строке 20 относится к коду' на строке 19. Dim rngTarget As Range, rng1 As Range, rng2 As Range, _rngMyRange As Range Const Crit1 As String = "DEF, LLC"

Page 365: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 365

Const Crit2 As String = "FGH LTD." Const Crit3 As String = "QRS INC."' Критерии расширенного фильтра.

Application.ScreenUpdating = False With Worksheets("Расширенный фильтр") .Rows(1).Insert .Range("A1").Value = "dummy"' Создать заголовок "dummy".

Set rngTarget = .Range("A1:A" & .Cells(Rows.Count, _1).End(xlUp).Row)' Задать исходный диапазон.

rngTarget.AutoFilter Field:=1, Criteria1:=Crit1, _Operator:=xlOr, Criteria2:=Crit2' Применить стандартный расширенный фильтр с 2-мя критериями.

Set rng1 = .AutoFilter.Range.Offset(1, 0).Resize( _.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)' Создать диапазон ячеек, ссылающийся' на результат применения расширенного фильтра.

rngTarget.AutoFilter' Вернуться к исходным данным.

rngTarget.AutoFilter Field:=1, Criteria1:=Crit3' Применить стандартный расширенный фильтр с 3-м критерием.

Set rng2 = .AutoFilter.Range.Offset(1, 0).Resize( _.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)' Создать диапазон ячеек, ссылающийся' на результат применения расширенного фильтра.

rngTarget.AutoFilter .Rows(1).Delete' Удалить заголовок "dummy".

Set rngMyRange = Union(rng1, rng2)' Объединить диапазоны ячеек rng1 и rng2.

rngMyRange.EntireRow.Copy Destination:=Worksheets( _"РФ (результат)").Range("A2")' Скопировать полученный результат в рабочий лист "РФ (результат)". End With Worksheets("РФ (результат)").Select Application.ScreenUpdating = True MsgBox "Фильтр успешно применен"End Sub

Файловые операцииМакросы, приведенные в следующих разделах, используются для выполY

нения различных файловых операций.

Page 366: ? Применение VBA и макросов в Microsoft® Excel

366 Часть II Автоматизация Excel

Поиск файлов

Макрос Srch и функция BrowseForFolderShell любезно предоставлеY

ны Натаном П. Оливером (Nathan P. Oliver), проживающим в Миннеаполисе,

штат Миннесота, США. Натан занимает должности финансового консультанY

та и разработчика приложений.

Следующий макрос проводит поиск файлов, в имени которых встречается

заданная строка, в указанной папке и ее подпапках. По результатам поиска

создается список, в котором для каждого найденного файла выводится ссылка

на файл, размер файла и дата его последнего изменения.

Sub Srch() Dim i As Long, z As Long, ws As Worksheet, y As Variant Dim fLdr As String y = Application.InputBox("Пожалуйста, введите строку, _встречающуюся в имени файла", "Ввод информации") If y = False And Not TypeName(y) = "String" Then Exit Sub Application.ScreenUpdating = False fLdr = BrowseForFolderShell With Application.FileSearch .NewSearch .LookIn = fLdr .SearchSubFolders = True .Filename = y Set ws = ThisWorkbook.Worksheets.Add(Sheets(1)) On Error GoTo 12: ws.Name = "Результат поиска файлов" On Error GoTo 0 If .Execute() > 0 Then For i = 1 To .FoundFiles.Count If Left$(.FoundFiles(i), 1) = Left$(fLdr, 1) Then If CBool(Len(Dir(.FoundFiles(i)))) Then z = z + 1 ws.Cells(z + 1, 1).Resize(, 3) = _ Array(Dir(.FoundFiles(i)), _ FileLen(.FoundFiles(i)) \ 1000, _ FileDateTime(.FoundFiles(i))) ws.Hyperlinks.Add Anchor:=Cells(z + 1, _1), Address:=.FoundFiles(i) End If End If Next i End If End With

ActiveWindow.DisplayHeadings = False

With ws With .[a1:c1 ] .Value = [{"Ссылка на файл","Размер (Kb)","Дата _последнего изменения"}] .Font.Underline = xlUnderlineStyleSingle .EntireColumn.AutoFit .HorizontalAlignment = xlCenter End With

Page 367: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 367

.[d1:iv1 ].EntireColumn.Hidden = True Range(.[a65536 ].End(3)(2), _ .[a65536 ]).EntireRow.Hidden = True Range(.[a2 ], .[c65536 ]).Sort [a2 ], xlAscending, _Header:=xlNo End With

Application.ScreenUpdating = True Exit Sub

1: Application.DisplayAlerts = False Worksheets("Результат поиска файлов").Delete Application.DisplayAlerts = True GoTo 2End Sub

Function BrowseForFolderShell() As String Dim objShell As Object, objFolder As Object Set objShell = CreateObject("Shell.Application")' Расскомментируйте следующую строку, чтобы начать' обзор папок с рабочего стола Windows. 'Set objFolder =objShell.BrowseForFolder(0,"Пожалуйста, _выберите папку", 0, 0)

' Укажите папку, с которой нужно начать обзор. Set objFolder = objShell.BrowseForFolder(0, "Пожалуйста, _выберите папку", 0, "c:\") If (Not objFolder Is Nothing) Then On Error Resume Next If IsError(objFolder.Items.Item.Path) Then _BrowseForFolderShell = CStr(objFolder): GoTo Here On Error GoTo 0 If Len(objFolder.Items.Item.Path) > 3 Then BrowseForFolderShell = objFolder.Items.Item.Path _& Application.PathSeparator Else BrowseForFolderShell = objFolder.Items.Item.Path End If Else: Application.ScreenUpdating = True: End End If

Here: Set objFolder = Nothing: Set objShell = NothingEnd Function

Удаление рабочей книги после определенной даты

Макрос Workbook_Open любезно предоставлен Томом Уртисом (Tom UrY

tis), проживающим в СанYФранциско, штат Калифорния, США. Том YYYY глава

консалтинговой компании Atlas Programming Management, расположенной в

районе Залива.

Приведенный ниже макрос удаляет активную рабочую книгу после

31 декабря 2004 года.

Page 368: ? Применение VBA и макросов в Microsoft® Excel

368 Часть II Автоматизация Excel

Внимание Файл рабочей книги не помещается в Корзину (Recycle Bin), а навсегда удаляется скомпьютера.

Sub Workbook_Open() If Date <= #12/31/2004# Then Exit Sub MsgBox "Сейчас рабочая книга будет удалена!" With ThisWorkbook .Saved = True .ChangeFileAccess xlReadOnly Kill .FullName .Close False End WithEnd Sub

Создание команды меню “Закрыть и удалить”Макросы Workbook_AddinInstall, Workbook_AddinnUninstall и

CloseAndKill любезно предоставлены Томми Майлзом (Tommy Miles),

проживающем в Хьюстоне, штат Техас, США.

Одной из наиболее распространенных операций, выполняемых в Excel, являY

ется открытие временного файла, копирование из него нужной информации и заY

крытие этого файла. Подобные файлы ‘‘разового использования’’ имеют свойство

накапливаться, захламляя пространство жесткого диска компьютера.

Макрос Workbook_AddinInstall добавляет к меню Excel Файл (File) коY

манду Закрыть и удалить (рис. 13.1), выполнение которой приводит к закрытию

активной рабочей книги и удалению ее файла. Помимо этого, имя файла активY

ной рабочей книги удаляется из списка ранее открывавшихся файлов.

Рис. 13.1. Команда Закрыть и удалить использу&ется для закрытия активной рабочей книги и уда&ления ее файла

Page 369: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 369

Public Const CONTROLNAME As String = "Закрыть и у&далить"

Sub Workbook_AddinInstall() Dim cmdControl As CommandBarButton On Error Resume Next Set cmdControl =Application.CommandBars(1).Controls("Файл").Controls(CONTROLNAME) If cmdControl Is Nothing Then Set cmdControl =Application.CommandBars(1).Controls("Файл").Controls.Add( _Type:=msoControlButton, Before:=Application.CommandBars( _1).Controls("Файл").Controls("Сохранить").Index) With cmdControl .Caption = CONTROLNAME .FaceId = 67 .Style = msoButtonIconAndCaption .DescriptionText = "Закрыть активную рабочую книгу _и удалить ее файл" .OnAction = "CloseAndKill" End With Set cmdControl = Nothing End If On Error GoTo 0 MsgBox "Команда ""Закрыть и удалить"" доступна из меню ""Файл"""End Sub

Sub Workbook_AddinUninstall() On Error Resume Next Application.CommandBars(1).Controls("Файл").Controls( _CONTROLNAME).Delete MsgBox "Команда ""Закрыть и удалить"" успешно удалена _из меню ""Файл"""End Sub

Sub CloseAndKill() Dim tmpAnswer As Variant If ActiveWorkbook Is Nothing Then Exit Sub

tmpAnswer = MsgBox("Вы действительно хотите удалить _рабочую книгу " & ActiveWorkbook.FullName & """?", _vbYesNoCancel + vbInformation) If tmpAnswer = vbYes Then Dim tmpFileName As String Dim RecentFle As RecentFile tmpFileName = ActiveWorkbook.FullName' Удалить имя файла активной рабочей книги из списка' ранее открывавшихся файлов. For Each RecentFle In Application.RecentFiles If RecentFle.Path = tmpFileName Then RecentFle.Delete Next ActiveWorkbook.Close SaveChanges:=False On Error Resume Next Kill tmpFileName ' Удалить файл. If Err.Number <> 0 Then MsgBox "Невозможно удалить файл """ & tmpFileName &"""." End If End IfEnd Sub

Page 370: ? Применение VBA и макросов в Microsoft® Excel

370 Часть II Автоматизация Excel

Импорт CSVLфайлов

Макрос OpenLargeCSVFast любезно предоставлен Масару Каджи

(Masaru Kaji), проживающим в КобеYСити, Япония. Масару автор WebYсайта

Colo’s Excel Junk Room (http://www.puremis.net/excel/), посвященного

Excel и VBA.

Следующий макрос импортирует CSVYфайл в Excel, а затем удаляет его.

Option Base 1

Sub OpenLargeCSVFast() Dim buf(1 To 256) As Variant Dim i As Long Const strFilePath As String = "C:\temp\Test.CSV" 'Подставьте _сюда путь к нужному файлу. Dim strRenamedPath As String strRenamedPath = Split(strFilePath, ".")(0) & "txt" With Application .ScreenUpdating = False .DisplayAlerts = False End With

'Создание массива для параметра FieldInfo метода OpenText. For i = 1 To 256 buf(i) = Array(i, 2) Next

Name strFilePath As strRenamedPath Workbooks.OpenText Filename:=strRenamedPath, _DataType:=xlDelimited, Comma:=True, FieldInfo:=buf Erase buf ActiveSheet.UsedRange.Copy ThisWorkbook.Sheets( _"CSV").Range("A5") ActiveWorkbook.Close False Kill strRenamedPath With Application .ScreenUpdating = True .DisplayAlerts = True End WithEnd Sub

Считывание текстового файла в памятьи его последующий анализ

Макрос ReadTxtLines любезно предоставлен Суатом Мехметом Озгуром

(Suat Mehmet Ozgur), проживающим в Стамбуле, Турция. Суат разрабатывает

ExcelY, AccessY и Visual BasicYприложения для компаний MrExcel Consulting и

TheOfficeExperts.com.

Следующий макрос реализует весьма необычный подход к считыванию соY

держимого текстового файла. Вместо построчного чтения, макрос загружает

весь файл в память и сохраняет его в строковой переменной. Затем полученY

ная переменная разбивается на строки. Преимущество этого метода заключаY

Page 371: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 371

ется в единственном обращении к файлу на диске. Последующая обработка

файла осуществляется в памяти компьютера.

Sub ReadTxtLines()'Нет необходимости устанавливать библиотеку'Microsoft Scripting Runtime, поскольку'в этом макросе используется позднее связывание. Dim sht As Worksheet Dim fso As Object Dim fil As Object Dim txt As Object Dim strtxt As String Dim tmpLoc As Long

'Работаем с активным рабочим листом. Set sht = ActiveSheet

'Очистить содержимое активного рабочего листа. sht.UsedRange.ClearContents

'Создать объект файловой системы. Set fso = CreateObject("Scripting.FileSystemObject")

'Создать объект требуемого файла. Set fil = fso.GetFile("c:\test.csv")

'Открыть файл как текст. Set txt = fil.OpenAsTextStream(1)

'Считать содержимое файла в строковую переменную. strtxt = txt.ReadAll

'Закрыть файл. txt.Close

'Найти позицию 1-го символа новой строки. tmpLoc = InStr(1, strtxt, vbCrLf)

'Выполнять до тех пор, пока в переменной strtxt'будут оставаться символы новой строки. Do Until tmpLoc = 0'Сохранить строку в следующей пустой ячейке столбца А. sht.Cells(65536, 1).End(xlUp).Offset(1).Value = _Left(strtxt, tmpLoc - 1)' Удалить "отработанную" строку из переменной. strtxt = Right(strtxt, Len(strtxt) - tmpLoc - 1)'Найти позицию следующего символа новой строки. tmpLoc = InStr(1, strtxt, vbCrLf) Loop'Последняя строка не содержит символа новой строки. sht.Cells(65536, 1).End(xlUp).Offset(1).Value = strtxt'Несмотря на то что файл уже закрыт, правила "хорошего тона"'требуют установить значение переменной fso равным Nothing. Set fso = NothingEnd Sub

Page 372: ? Применение VBA и макросов в Microsoft® Excel

372 Часть II Автоматизация Excel

Объединение и разделение рабочих книгСледующие 4 макроса демонстрируют возможность объединения нескольY

ких рабочих книг в одну, а также сохранения листов рабочей книги в виде отY

дельных рабочих книг или документов Word.

Сохранение листов рабочей книги в виде отдельныхрабочих книг

Макрос SplitWorkbook любезно предоставлен Томми Майлзом (Tommy

Miles), проживающим в Хьюстоне, штат Техас, США.

Следующий макрос сохраняет все листы активной рабочей книги в виде

отдельных рабочих книг, файлы которых носят имена соответствующих рабоY

чих листов и размещаются в той же папке, что и исходная рабочая книга. При

попытке перезаписать существующий файл выводится предупреждение.

Sub SplitWorkbook() Dim ws As Worksheet Dim DisplayStatusBar As Boolean DisplayStatusBar = Application.DisplayStatusBar Application.DisplayStatusBar = True Application.ScreenUpdating = False

For Each ws In ThisWorkbook.Sheets Dim NewFileName As String Application.StatusBar = "Осталось рабочих листов: " & _ThisWorkbook.Sheets.Count If ThisWorkbook.Sheets.Count <> 1 Then NewFileName = ThisWorkbook.Path & "\" & ws.Name & _".xls" ws.Copy ActiveWorkbook.Sheets(1).Name = "Sheet1" ActiveWorkbook.SaveAs Filename:=NewFileName ActiveWorkbook.Close SaveChanges:=False Else NewFileName = ThisWorkbook.Path & "\" & ws.Name & _".xls" ws.Name = "Sheet1" ThisWorkbook.SaveAs Filename:=NewFileName End If Next Application.StatusBar = False Application.DisplayStatusBar = DisplayStatusBar Application.ScreenUpdating = TrueEnd Sub

Объединение нескольких рабочих книг в одну

Макрос CombineWorkbooks также любезно предоставлен Томми Майлзом.

Следующий макрос объединяет все рабочие книги, расположенные в заY

данной в папке, в одну. Рабочие листы полученной книги будут названы по

именам соответствующих исходных рабочих книг.

Page 373: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 373

Sub CombineWorkbooks() Dim CurFile As String

Dim DestWB As Workbook Dim ws As Object 'Рабочие листы могут быть произвольного типа.

Const DirLoc As String = "C:\Data\" 'Местоположение _исходных файлов.

Application.ScreenUpdating = False

Set DestWB = Workbooks.Add(xlWorksheet)

CurFile = Dir(DirLoc & "*.xls")

Do While CurFile <> vbNullString Dim OrigWB As Workbook

Set OrigWB = Workbooks.Open(Filename:=DirLoc & CurFile, _ReadOnly:=True)

CurFile = Left(Left(CurFile, Len(CurFile) - 4), 29) 'Получение базового имени 'рабочего листа путем отсечения 'последних 4-х символов имени 'исходного файла (".xls").

For Each ws In OrigWB.Sheets ws.Copy After:=DestWB.Sheets(DestWB.Sheets.Count)

If OrigWB.Sheets.Count > 1 Then DestWB.Sheets(DestWB.Sheets.Count).Name = _CurFile & ws.Index Else DestWB.Sheets(DestWB.Sheets.Count).Name = CurFile End If Next

OrigWB.Close SaveChanges:=False

CurFile = Dir Loop

Application.DisplayAlerts = False DestWB.Sheets(1).Delete Application.DisplayAlerts = True

Application.ScreenUpdating = True

Set DestWB = NothingEnd Sub

Фильтрация данных с последующим копированиемполученного результата в отдельные рабочие листы

Макрос Filter_NewSheet любезно предоставлен Деннисом ВалентайY

ном (Dennis Wallentin), проживающим в Остерсунде, Швеция. Деннис дает

советы, касающиеся использования Excel и VBA, на своем собственном WebY

сайте по адресу: www.xldennis.com.

Page 374: ? Применение VBA и макросов в Microsoft® Excel

374 Часть II Автоматизация Excel

Следующий макрос фильтрует исходные данные (рис. 13.2) и копирует поY

лученные результаты в отдельные рабочие листы (рис. 13.3).

Рис. 13.2. Исходные данные Рис. 13.3. Результат примененияфильтра скопирован в новый ра&бочий лист

Sub Filter_NewSheet()Dim wbBook As WorkbookDim wsSheet As WorksheetDim rnStart As Range, rnData As RangeDim i As Long

Set wbBook = ThisWorkbookSet wsSheet = wbBook.Worksheets("Фильтр и копирование")

With wsSheet'Убедитесь, что 1-я строка содержит заголовки столбцов. Set rnStart = .Range("A2") Set rnData = .Range(.Range("A2"), .Range("C65536").End(xlUp))End With

Application.ScreenUpdating = True

For i = 1 To 5'Применение расширенного фильтра. rnStart.AutoFilter Field:=1, Criteria1:="AA" & i'Копирование результата фильтрации. rnData.SpecialCells(xlCellTypeVisible).Copy'Добавление нового рабочего листа. Worksheets.Add Before:=wsSheet'Присвоение имени новому рабочему листу. ActiveSheet.Name = "AA" & i'Вставка результата фильтрации'в новый рабочий лист. Range("A2").PasteSpecial xlPasteValuesNext i

'Вернуться к исходным данным.rnStart.AutoFilter Field:=1

Page 375: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 375

With Application'Очистить буфер обмена. .CutCopyMode = False .ScreenUpdating = FalseEnd With

End Sub

Экспорт данных в Word

Макрос Export_Data_Word_Table также любезно предоставлен ДенниY

сом Валентайном.

Следующий макрос экспортирует данные с рабочего листа Excel в докуY

мент Word. Поскольку используется раннее связывание, необходимо добавить

ссылку (команда меню редактора Visual Basic Tools References (Сервис

Ссылки)) на библиотеку Microsoft Word Object Library.

Sub Export_Data_Word_Table()Dim wdApp As Word.ApplicationDim wdDoc As Word.DocumentDim wdCell As Word.CellDim i As LongDim wbBook As WorkbookDim wsSheet As WorksheetDim rnData As RangeDim vaData As Variant

Set wbBook = ThisWorkbookSet wsSheet = wbBook.Worksheets("Экспорт в Word")

With wsSheet Set rnData = .Range("A1:A10")End With

'Поместить данные из диапазона A1:A10 в одномерный массив Variant.vaData = rnData.Value

'Создать объект Word.Set wdApp = New Word.Application'Документ Test.doc должен находиться в той же папке,'что и рабочая книга.Set wdDoc = wdApp.Documents.Open(ThisWorkbook.Path & "\Test.doc")

'Импортировать данные в 1-й столбец 1-й таблицы.For Each wdCell In wdDoc.Tables(1).Columns(1).Cells i = i + 1 wdCell.Range.Text = vaData(i, 1)Next wdCell

'Сохранить и закрыть документ.With wdDoc .Save .CloseEnd With

Page 376: ? Применение VBA и макросов в Microsoft® Excel

376 Часть II Автоматизация Excel

'Завершить работу скрытой копии Microsoft Word.wdApp.Quit'Удалить внешние переменные из памяти.Set wdDoc = NothingSet wdApp = Nothing

MsgBox "Данные были успешно экспортированы в документ Test.doc.", _vbInformation

End Sub

Работа с примечаниямиВ большинстве случаев примечания ячеек Excel используются не достаточY

но эффективно. Рассматриваемые в следующих разделах макросы помогут исY

править это упущение.

Вывод примечаний

Макрос ListComments любезно предоставлен Томми Майлзом.

Excel позволяет печатать примечания, однако не позволяет выводить инY

формацию о рабочей книге и (или) рабочем листе, к которым относится то

или иное примечание. Следующий макрос помещает примечания, имена их

авторов и сведения о местоположении в новую рабочую книгу для последуюY

щего просмотра, сохранения и (или) печати.

Sub ListComments() Dim wb As Workbook Dim ws As Worksheet

Dim cmt As Comment

Dim cmtCount As Long

cmtCount = 2

On Error Resume Next Set ws = ActiveSheet If ws Is Nothing Then Exit Sub On Error GoTo 0

Application.ScreenUpdating = False

Set wb = Workbooks.Add(xlWorksheet)

With wb.Sheets(1) .Range("$A$1") = "Автор" .Range("$B$1") = "Рабочая книга" .Range("$C$1") = "Рабочий лист" .Range("$D$1") = "Диапазон" .Range("$E$1") = "Примечание" End With

For Each cmt In ws.Comments

Page 377: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 377

With wb.Sheets(1) .Cells(cmtCount, 1) = cmt.author .Cells(cmtCount, 2) = cmt.Parent.Parent.Parent.Name .Cells(cmtCount, 3) = cmt.Parent.Parent.Name .Cells(cmtCount, 4) = cmt.Parent.Address .Cells(cmtCount, 5) = CleanComment(cmt.author, _cmt.Text) End With

cmtCount = cmtCount + 1 Next

wb.Sheets(1).UsedRange.WrapText = False

Application.ScreenUpdating = True

Set ws = Nothing Set wb = NothingEnd Sub

Private Function CleanComment(author As String, _cmt As String) As String Dim tmp As String

tmp = Application.WorksheetFunction.Substitute(cmt, _author & ":", "") tmp = Application.WorksheetFunction.Substitute(tmp, _Chr(10), "")

CleanComment = tmpEnd Function

Результат выполнения макроса ListComments показан на рис. 13.4.

Рис. 13.4. Макрос ListComments позволяет получить исчерпывающуюинформацию о примечаниях

Изменение размера области примечания

Макрос CommentFitter1 любезно предоставлен Томом Уртисом.

Следующий макрос изменяет размер области примечания так, чтобы она

вместила в себя весь текст примечания.

Sub CommentFitter1()Application.ScreenUpdating = FalseDim x As Range, y As Long

For Each x In Cells.SpecialCells(xlCellTypeComments) Select Case True Case Len(x.NoteText) <> 0 With x.Comment

Page 378: ? Применение VBA и макросов в Microsoft® Excel

378 Часть II Автоматизация Excel

.Shape.TextFrame.AutoSize = True If .Shape.Width > 250 Then y = .Shape.Width * .Shape.Height .Shape.Width = 150 .Shape.Height = (y / 200) * 1.2 End If End With End SelectNext xApplication.ScreenUpdating = TrueEnd Sub

Результат выполнения макроса CommentFitter1 показан на рис. 13.5.

Рис. 13.5. Теперь область примечания включает в себя весь его текст

Изменение размера области примечания с помощьюцентрирования

Макрос CommentFitter2 также любезно предоставлен Томом Уртисом.

Следующий макрос изменяет размер области примечания путем центрироY

вания текста примечания.

Sub CommentFitter2()Application.ScreenUpdating = FalseDim x As Range, y As Long

For Each x In Cells.SpecialCells(xlCellTypeComments) Select Case True Case Len(x.NoteText) <> 0 With x.Comment .Shape.TextFrame.AutoSize = True If .Shape.Width > 250 Then y = .Shape.Width * .Shape.Height .Shape.ScaleHeight 0.9, msoFalse, _msoScaleFromTopLeft .Shape.ScaleWidth 1#, msoFalse, _msoScaleFromTopLeft End If End With End SelectNext xApplication.ScreenUpdating = TrueEnd Sub

Результат выполнения макроса CommentFitter2 показан на рис. 13.6.

Page 379: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 379

Рис. 13.6. Результат центрирования текста примечания

Размещение диаграммы в примечании

Макрос PlaceGraph любезно предоставлен Томом Уртисом.

Несмотря на то что Excel не позволяет разместить в примечании

‘‘настоящую’’ диаграмму, это можно сделать с ее изображением, как показано

на рис. 13.7.

Рис. 13.7. “Диаграмма”, размещенная в примечании

Чтобы поместить изображение диаграммы в примечание с помощью польY

зовательского интерфейса Excel, выполните следующие действия.

1. Создайте требуемое изображение.

2. Создайте примечание и выделите соответствующую ячейку.

Page 380: ? Применение VBA и макросов в Microsoft® Excel

380 Часть II Автоматизация Excel

3. Выберите команду меню Excel Вставка Изменить примечание (Insert

Edit Comment) или щелкните на ячейке правой кнопкой мыши и выбериY

те команду контекстного меню Изменить примечание (Edit Comment).

4. Щелкните правой кнопкой мыши на границе области примечания и

выберите команду контекстного меню Формат примечания (Format

Comment).

5. Перейдите во вкладку Цвета и линии (Colors and Lines) и раскройте

список Цвет (Color), расположенный в области Заливка (Fill).

6. Выберите команду Способы заливки (Fill Effects), перейдите во вкладку

Рисунок (Picture) открывшегося диалогового окна Способы заливки(Fill Effects) и щелкните на кнопке Рисунок (Picture).

7. Выберите требуемое изображение и щелкните на кнопке OK для закрыY

тия диалогового окна Способы заливки. Еще раз щелкните на кнопке

OK, для того чтобы закрыть диалоговое окно Формат примечания.

Чтобы ‘‘диаграмма’’, помещенная в примечание описанным выше образом,

всегда содержала текущие сведения, включите следующий код VBA в обработY

чик события SheetChange, срабатывающего при изменении исходных данных

диаграммы (укажите требуемое имя файла изображения, название диаграммы,

название рабочего листа, адрес ячейки и размер области примечания).

Sub PlaceGraph()Dim x As String, z As Range

Application.ScreenUpdating = Falsex = "C:\XWMJGraph.gif"

Set z = Worksheets("Диаграмма в примечании").Range("A3")

On Error Resume Nextz.Comment.DeleteOn Error GoTo 0

ActiveSheet.ChartObjects("Chart 1").ActivateActiveChart.Export x

With z.AddComment With .Shape .Height = 322 .Width = 465 .Fill.UserPicture x End WithEnd With

Range("A1").ActivateApplication.ScreenUpdating = True

Set z = NothingEnd Sub

Page 381: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 381

Замечательные возможности Excel VBAВ следующих разделах рассматриваются макросы, демонстрирующие богаY

тые возможности Excel VBA.

Выделение ячейки с помощью условного форматирования

Макрос Worksheet_SelectionChange любезно предоставлен Иваном

Ф. Моалой (Ivan F. Moala), проживающим в Окленде, Новая Зеландия.

Иван YYYY автор WebYсайта The XcelFiles (www.xcelfiles.com), посвященного

задачам, решить которые с помощью Excel представляется невероятным или

невозможным.

Следующий макрос выделяет активную ячейку с помощью условного форY

матирования. Следует отметить, что макрос Worksheet_SelectionChangeудаляет любое существующее условное форматирование рабочего листа,

а также очищает буфер обмена, что приводит к затруднению выполнения опеY

раций вырезания, копирования и вставки данных.

'/////////////////////////////////////////////////////'// Исправлено 14 февраля 2003 - с комментариями'// Хуана Пабло Г. (Juan Pablo G.).'// Локализованные версии Excel могут неправильно'// интерпретировать значение TRUE.'// Воспользуемся фактом, что TRUE можно'// заменить любым целым числом, не равным 0.'////////////////////////////////////////////////////

Const iInternational As Integer = Not (0)

Private Sub Worksheet_SelectionChange(ByVal Target As Range)Dim iColor As Integer'// Примечание: этот макрос удаляет любое'// существующее условное форматирование!

'// Продолжить выполнение макроса, если'// пользователь выделит диапазон ячеек.On Error Resume NextiColor = Target.Interior.ColorIndex'// Оставить действие строки On Error Resume Next'// в силе на случай возникновения ошибок смещения строк.

If iColor < 0 Then iColor = 36Else iColor = iColor + 1End If

'// Проверить, совпадает ли цвет текста с цветом заливки.If iColor = Target.Font.ColorIndex Then iColor = iColor + 1

Cells.FormatConditions.Delete

'// Выделение с помощью горизонтальной полосы.With Range("A" & Target.Row, Target.Address) 'Rows(Target.Row) .FormatConditions.Add Type:=2, Formula1:=iInternational ' "TRUE" .FormatConditions(1).Interior.ColorIndex = iColor

Page 382: ? Применение VBA и макросов в Microsoft® Excel

382 Часть II Автоматизация Excel

End With

'// Выделение с помощью вертикальной полосы.With Range(Target.Offset(1 - Target.Row, 0).Address & ":" & _Target.Offset(-1, 0).Address) .FormatConditions.Add Type:=2, Formula1:=iInternational ' "TRUE" .FormatConditions(1).Interior.ColorIndex = iColorEnd With

End Sub

Выделение ячейки без применения условногоформатирования

Макрос HighLight и вспомогательные макросы HighlightRight,

HighlightLeft, HighlightUp, HighlightDown, DisableDelete и Re-Set также любезно предоставлены Иваном Ф. Моалой.

Следующий макрос выделяет ячейку, которая была сделана активной в реY

зультате использования клавиш управления курсором, без применения условY

ного форматирования.

'// Альтернативный вариант макроса, выделяющего активную ячейку:'// - не использует условное форматирование;'// - сохраняет существующее условное форматирование рабочего листа;'// - позволяет выполнять операции вырезания,'// копирования и вставки данных.'//'// Макрос создан Нейтом Оливером (Nate Oliver) для Альдо (Aldo).'//'// Альдо предложил обработку нажатия клавиши <Del>.'//'// Спасибо, друзья!!'//'// См. дополнительные комментарии в коде.

'// Размещено в стандартном модуле.

Dim strCol As StringDim iCol As IntegerDim dblRow As Double

Sub HighlightRight() HighLight 0, 1End Sub

Sub HighlightLeft() HighLight 0, -1End Sub

Sub HighlightUp() HighLight -1, 0, -1End Sub

Sub HighlightDown() HighLight 1, 0, 1End Sub

Sub HighLight(dblxRow As Double, iyCol As Integer, _

Page 383: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 383

Optional dblZ As Double = 0)

On Error GoTo NoGostrCol = Mid(ActiveCell.Offset(dblxRow, iyCol).Address, _InStr(ActiveCell.Offset(dblxRow, iyCol).Address, "$") + 1, _InStr(2, ActiveCell.Offset(dblxRow, iyCol).Address, "$") - 2)iCol = ActiveCell.ColumndblRow = ActiveCell.Row

'// Позволяет избежать мерцания экрана.Application.ScreenUpdating = False

With Range(strCol & ":" & strCol & "," & dblRow + dblZ & _":" & dblRow + dblZ) .Select'// Сейчас экран следует обновить. Application.ScreenUpdating = True .Item(dblRow + dblxRow).ActivateEnd With

NoGo:End Sub

Sub DisableDelete() Cells(ActiveCell.Row, ActiveCell.Column).Select Application.OnKey "{DEL}"End Sub

Sub ReSet() Application.OnKey "{RIGHT}" Application.OnKey "{LEFT}" Application.OnKey "{UP}" Application.OnKey "{DOWN}"End Sub

Транспонирование данных

Макрос TransposeData любезно предоставлен Масару Каджи.

Следующий макрос транспонирует данные по заданному столбцу.

Sub TransposeData() Dim shOrg As Worksheet, shRes As Worksheet Dim rngStart As Range, rngPaste As Range Dim lngData As Long

Application.ScreenUpdating = False On Error Resume Next Application.DisplayAlerts = False Sheets("Транспонирование (результат)").Delete Application.DisplayAlerts = True On Error GoTo 0

On Error GoTo terminate

Set shOrg = Sheets("Транспонирование") Set shRes = Sheets.Add(After:=shOrg) shRes.Name = "Транспонирование (результат)" With shOrg'Отсортировать. .Cells.CurrentRegion.Sort Key1:=.[B2], Order1:=1, _

Page 384: ? Применение VBA и макросов в Microsoft® Excel

384 Часть II Автоматизация Excel

Key2:=.[C2], Order2:=1, Key3:=.[E2], Order3:=1, Header:=xlYes'Скопировать заголовок. .Rows(1).Copy shRes.Rows(1)'Задать начальный диапазон. Set rngStart = .[C2] Do Until IsEmpty(rngStart) Set rngPaste = shRes.[A65536].End(xlUp).Offset(1) lngData = GetNextRange(rngStart) rngStart.Offset(, -2).Resize(, 5).Copy rngPaste

'Копировать V1 в V14. rngStart.Offset(, 2).Resize(lngData).Copy rngPaste.Offset(, 5).PasteSpecial Paste:=xlAll, _Operation:=xlNone, SkipBlanks:=False, Transpose:=True'Копировать V1FP в V14FP. rngStart.Offset(, 1).Resize(lngData).Copy rngPaste.Offset(, 19).PasteSpecial Paste:=xlAll, _Operation:=xlNone, SkipBlanks:=False, Transpose:=True Set rngStart = rngStart.Offset(lngData) Loop End With Application.GoTo shRes.[A1] shRes.Cells.Columns.AutoFit Application.ScreenUpdating = True Application.CutCopyMode = False If MsgBox("Удалить исходный рабочий лист?", 36) = 6 Then Application.DisplayAlerts = False Sheets("Транспонирование").Delete Application.DisplayAlerts = True End If Set rngPaste = Nothing Set rngStart = Nothing Set shRes = Nothing Exit Subterminate:

End Sub

Function GetNextRange(ByVal rngSt As Range) As Long Dim i As Long i = 0 Do Until rngSt.Value <> rngSt.Offset(i).Value i = i + 1 Loop GetNextRange = iEnd Function

Выделение и отмена выделения несмежных ячеек

Макросы ModifyRightClick, DeselectActiveCell и DeselectAc-tiveArea любезно предоставлены Томом Уртисом.

Чтобы отменить выделение ячейки или диапазона ячеек на рабочем листе,

нужно щелкнуть на произвольной невыделенной ячейке. После выполнения

этой операции выделение требуемых ячеек необходимо начинать заново, что

весьма проблематично, если речь идет о большом количестве несмежных ячеек.

Page 385: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 385

Следующий макрос добавляет в контекстное меню 2 новые команды:

Отменить выделение активной ячейки и Отменить выделение активнойобласти (рис. 13.8).

Рис. 13.8. Процедура Modi-fyRightClick создает 2 новыекоманды контекстного меню

Удерживая нажатой клавишу <Ctrl>, щелкните левой кнопкой мыши на

ячейке несмежного диапазона, выделение которой следует отменить. ЩелкY

ните правой кнопкой мыши и выберите команду контекстного меню

Отменить выделение активной ячейки (для отмены выделения только одной

активной ячейки) или Отменить выделение активной области (для отмены

выделения области, которой принадлежит активная ячейка).

Поместите приведенный ниже код в стандартный модуль.

Sub ModifyRightClick() Dim O1 As Object, O2 As Object On Error Resume Next With CommandBars("Cell") .Controls("Отменить выделение активной ячейки").Delete .Controls("Отменить выделение активной области").Delete End With On Error GoTo 0 Set O1 = CommandBars("Cell").Controls.Add With O1 .Caption = "Отменить выделение активной ячейки" .OnAction = "DeselectActiveCell" End With Set O2 = CommandBars("Cell").Controls.Add With O2 .Caption = "Отменить выделение активной области" .OnAction = "DeselectActiveArea" End WithEnd Sub

Page 386: ? Применение VBA и макросов в Microsoft® Excel

386 Часть II Автоматизация Excel

Sub DeselectActiveCell() Dim x As Range, y As Range If Selection.Cells.Count > 1 Then For Each y In Selection.Cells If y.Address <> ActiveCell.Address Then If x Is Nothing Then Set x = y Else Set x = Application.Union(x, y) End If End If Next y If x.Cells.Count > 0 Then x.Select End If End IfEnd Sub

Sub DeselectActiveArea() Dim x As Range, y As Range If Selection.Areas.Count > 1 Then For Each y In Selection.Areas If Application.Intersect(ActiveCell, y) Is Nothing Then If x Is Nothing Then Set x = y Else Set x = Application.Union(x, y) End If End If Next y x.Select End IfEnd Sub

Разместите следующий код в модуле ЭтаКнига (ThisWorkbook).

Private Sub Workbook_Deactivate() Application.CommandBars("Cell").ResetEnd Sub

Private Sub Workbook_Activate() ModifyRightClickEnd Sub

VBA для профессионаловVBAYпрограммисты находятся в постоянном поиске более эффективных

решений тех или иных задач. Размещая результаты своей работы в Internet,

они оказывают неоценимую услугу всему сообществу VBAYпрограммистов.

Установка параметров страницы

Макросы Macro1, Macro1_Version2, Macro1_Version3 и Macro1_Version4 любезно предоставлены Хуаном Пабло Гонсалесом (Juan Pablo

Page 387: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 387

Gonzales), проживающим в Боготе, Колумбия. Хуан Пабло YYYY разработчик

программы F&I Menu Wizard, он также выполняет для Mr.Excel.com все закаY

зы, поступающие от испаноязычных клиентов.

Следующие макросы выполняют одно и то же действие: устанавливают разY

меры верхнего, нижнего, левого и правого полей страницы равными 1,5 дюйма

(3,8 см), а размеры полей верхнего колонтитула и нижнего колонтитула YYYY равY

ными 1 дюйму (2,5 см). Макрос Macro1 создан средством записи макросов.

Макросы Macro1_Version2, Macro1_Version3 и Macro1_Version4 деY

монстрируют возможность улучшения автоматически сгенерированного кода с

целью повышения его производительности. На рис. 13.9 показана сравниY

тельная таблица скорости выполнения всех четырех макросов.

Рис. 13.9. Сравнительная таблица скорости выполнениямакросов, устанавливающих параметры страницы

Sub Macro1()'' Macro1 Macro' Macro recorded 12/2/2003 by Juan Pablo Gonzalez' With ActiveSheet.PageSetup .PrintTitleRows = "" .PrintTitleColumns = "" End With ActiveSheet.PageSetup.PrintArea = "" With ActiveSheet.PageSetup .LeftHeader = "" .CenterHeader = "" .RightHeader = "" .LeftFooter = "" .CenterFooter = "" .RightFooter = ""

Page 388: ? Применение VBA и макросов в Microsoft® Excel

388 Часть II Автоматизация Excel

.LeftMargin = Application.InchesToPoints(1.5) .RightMargin = Application.InchesToPoints(1.5) .TopMargin = Application.InchesToPoints(1.5) .BottomMargin = Application.InchesToPoints(1.5) .HeaderMargin = Application.InchesToPoints(1) .FooterMargin = Application.InchesToPoints(1) .PrintHeadings = False .PrintGridlines = False .PrintComments = xlPrintNoComments .CenterHorizontally = False .CenterVertically = False .Orientation = xlPortrait .Draft = False .PaperSize = xlPaperLetter .FirstPageNumber = xlAutomatic .Order = xlDownThenOver .BlackAndWhite = False .Zoom = 100 End WithEnd Sub

Как обычно, средство записи макросов создало весьма громоздкий код.

Учитывая низкую скорость обновления объекта PageSetup, макрос Macro1остро нуждается в оптимизации, как показано ниже:

Sub Macro1_Version2() With ActiveSheet.PageSetup .LeftMargin = Application.InchesToPoints(1.5) .RightMargin = Application.InchesToPoints(1.5) .TopMargin = Application.InchesToPoints(1.5) .BottomMargin = Application.InchesToPoints(1.5) .HeaderMargin = Application.InchesToPoints(1) .FooterMargin = Application.InchesToPoints(1) End WithEnd Sub

Среднее время выполнения макроса Macro1_Version2 более чем на 70%

меньше среднего времени выполнения макроса Macro1, однако это еще далеко

не все. Принимая во внимание низкую скорость обновления объекта Page-Setup, воспользуемся выражением If для установки значения только тех паY

раметров страницы, которые этого требуют.

В приведенном ниже макросе вызов функции Application.Inches-ToPoints был заменен фактическими значениями параметров страницы.

Sub Macro1_Version3() With ActiveSheet.PageSetup If .LeftMargin <> 108 Then .LeftMargin = 108 If .RightMargin <> 108 Then .RightMargin = 108 If .TopMargin <> 108 Then .TopMargin = 108 If .BottomMargin <> 108 Then .BottomMargin = 108 If .HeaderMargin <> 72 Then .HeaderMargin = 72 If .FooterMargin <> 72 Then .FooterMargin = 72 End WithEnd Sub

Page 389: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 389

Разница во времени выполнения макросов Macro1_Version2 и Macro1_Version3 становится заметной при условии, что некоторые параметры страY

ницы уже содержат нужные значения.

Макрос Macro1_Version4 вызывает XLMYметод PAGE.SETUP, позволяя

тем самым сократить среднее время своего выполнения более чем на 95% по

сравнению со средним временем выполнения макроса Macro1. Параметры

метода PAGE.SETUP left, right, top, bot, head_margin и foot_marginизмеряются не в точках, а в дюймах.

Sub Macro1_Version4() Dim St As String St = "PAGE.SETUP(, , " & _ "1.5, 1.5, 1.5, 1.5" & _ ", 0, False, False, False, 1, 1, True, 1, 1,False, , " & _ "1, 1" & _ ", False)" Application.ExecuteExcel4Macro StEnd Sub

Параметрам left, right, top и bot соответствует 4Yя строка приведенY

ного выше кода, параметрам head_margin и foot_margin YYYY 6Yя строка.

К сожалению, макрос Macro1_Version4 имеет два существенных недостатY

ка. ВоYпервых, он основан на языке XLM, включенном в Excel для обеспечеY

ния обратной совместимости. Неизвестно, как долго Microsoft намерена подY

держивать этот язык. ВоYвторых, ошибка при указании параметров метода

PAGE.SETUP приведет к тому, что этот метод не будет выполнен без какогоY

либо уведомления.

Вычисление времени выполнения кода макроса

Ниже приведен код, использующийся для вычисления времени выполнения

макросов Macro1, Macro1_Version2, Macro1_Version3 и Macro1_Version4 (см. рис. 13.9).

Public Declare Function QueryPerformanceFrequency Lib _ "kernel32" (lpFrequency As Currency) As Long

Public Declare Function QueryPerformanceCounter Lib _ "kernel32.dll" (lpPerformanceCount As Currency) As Long

Sub Test() Dim Ar(1 To 20, 1 To 4) As Currency, WS As Worksheet Dim n As Currency, str As Currency, fin As Currency Dim y As Currency

Dim i As Long, j As Long

Application.ScreenUpdating = False For i = 1 To 4 For j = 1 To 20 Set WS = ThisWorkbook.Sheets.Add WS.Range("A1").Value = 1

Page 390: ? Применение VBA и макросов в Microsoft® Excel

390 Часть II Автоматизация Excel

QueryPerformanceFrequency y QueryPerformanceCounter str Select Case i Case 1: Macro1 Case 2: Macro1_Version2 Case 3: Macro1_Version3 Case 4: Macro1_Version4 End Select QueryPerformanceCounter fin Application.DisplayAlerts = False WS.Delete Application.DisplayAlerts = True n = (fin - str) Ar(j, i) = CCur(Format(n, _"##########.############") / y) Next j Next i With Range("A8").Resize(1, 4) .Value = Array("Macro1", "Macro1_Version2", _"Macro1_Version3", "Macro1_Version4") .Font.Bold = True End With Range("A9").Resize(20, 4).Value = Ar

With Range("A29").Resize(1, 4)' В англоязычной версии Excel:' .FormulaR1C1 = "=AVERAGE(R2C:R21C)" .FormulaR1C1Local = "=СРЗНАЧ(R2C:R21C)"' В англоязычной версии Excel:' .Offset(1).FormulaR1C1 = "=RANK(R22C, R22C1:R22C4, 1)" .Offset(1).FormulaR1C1Local = "=РАНГ(R22C; R22C1:R22C4; 1)" .Resize(2).Font.Bold = True End With Application.ScreenUpdating = TrueEnd Sub

Запрет/разрешение выполнения операций вырезания,копирования и вставки

Макросы EnableAllClear и DisAbleAllCLear любезно предоставлены

Иваном Ф. Моалой.

Иногда изменение пользователями содержимого рабочего листа крайне

нежелательно. Следующий код запрещает/разрешает все способы выполнения

операций вырезания, копирования и вставки данных.

Option Private Module

Dim ComBar As CommandBarDim ComBarCtrl As CommandBarControl

Sub EnableAllClear()'// Команда Вставка (Insert).. EnableControl 295, True '// ..Ячейки (Cells) EnableControl 296, True '// ..Строки (Rows) EnableControl 297, True '// ..Столбцы (Columns)

Page 391: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 391

'// Команда... EnableControl 478, True '// Правка->Удалить (Edit->Delete) EnableControl 292, True '// Удалить (Delete), контекстное '// меню ячейки EnableControl 293, True '// Удалить строки (Delete Rows), '// контекстное меню строки EnableControl 294, True '// Удалить (Delete), контекстное '// меню столбца EnableControl 847, True '// Правка->Удалить лист '// (Edit->Delete Sheet)'// Команда... EnableControl 3125, True '// Очистить содержимое (Clear '// Contents), контекстное меню EnableControl 1964, True '// Правка->Очистить->Все (All) EnableControl 872, True '// Правка->Очистить->Форматы '// (Edit->Clear->Formats) EnableControl 873, True '// Правка->Очистить->Содержимое '// (Edit->Clear->Contents) EnableControl 874, True '// Правка->Очистить->Примечания '// (Edit->Clear->Comments)'// Команда... EnableControl 21, True '// Вырезать (Cut) EnableControl 19, True '// Копировать (Copy) EnableControl 22, True '// Вставить (Paste) EnableControl 755, True '// Специальная вставка '// (Paste Special)'// Комбинации клавиш. With Application .OnKey "^c" .OnKey "^v" .OnKey "+{DEL}" .OnKey "+{INSERT}" .CellDragAndDrop = True .OnDoubleClick = "" End With'// Панели инструментов. CommandBars("ToolBar List").Enabled = True

End Sub

Sub DisAbleAllCLear()'// Команда Вставка (Insert).. EnableControl 295, False '// ..Ячейки (Cells) EnableControl 296, False '// ..Строки (Rows) EnableControl 297, False '// ..Столбцы (Columns)'// Команда... EnableControl 478, False '// Правка->Удалить (Edit->Delete) EnableControl 292, False '// Удалить (Delete), контекстное '// меню ячейки EnableControl 293, False '// Удалить строки (Delete Rows), '// контекстное меню строки EnableControl 294, False '// Удалить (Delete), контекстное '// меню столбца EnableControl 847, False '// Правка->Удалить лист '// (Edit->Delete Sheet)'// Команда... EnableControl 21, False '// Вырезать (Cut)

Page 392: ? Применение VBA и макросов в Microsoft® Excel

392 Часть II Автоматизация Excel

EnableControl 19, False '// Копировать (Copy) EnableControl 22, False '// Вставить (Paste) EnableControl 755, False '// Специальная вставка '// (Paste Special)'// Команда... EnableControl 3125, False '// Очистить содержимое (Clear '// Contents), контекстное меню EnableControl 1964, False '// Правка->Очистить->Все (All) EnableControl 872, False '// Правка->Очистить->Форматы '// (Edit->Clear->Formats) EnableControl 873, False '// Правка->Очистить->Содержимое '// (Edit->Clear->Contents) EnableControl 874, False '// Правка->Очистить->Примечания '// (Edit->Clear->Comments)'// Комбинации клавиш. With Application .OnKey "^c", "Dummy" .OnKey "^v", "Dummy" .OnKey "+{DEL}", "Dummy" .OnKey "+{INSERT}", "Dummy" .CellDragAndDrop = False .OnDoubleClick = "Dummy" End With'// Панели инструментов. CommandBars("ToolBar List").Enabled = False

End Sub

Sub EnableControl(iId As Integer, blnState As Boolean)Dim ComBar As CommandBarDim ComBarCtrl As CommandBarControl

On Error Resume NextFor Each ComBar In Application.CommandBars Set ComBarCtrl = ComBar.FindControl(Id:=iId, recursive:=True) If Not ComBarCtrl Is Nothing Then ComBarCtrl.Enabled = blnStateNext

End Sub

Sub Dummy() '// Вывод сообщения. MsgBox "Команда недоступна!"End Sub

Определение порядка сортировки

Макрос CustomSort любезно предоставлен Вэем Цзянгом (Wei Jiang),

проживающим в г. Шиян, Китай. Цзянг работает на должности консультанта

в компании MrExcel Consulting.

Excel поддерживает сортировку списков в числовом или алфавитном поY

рядке. Иногда этого оказывается недостаточно. Как показано на рис. 13.10,

желаемый порядок сортировки списка выглядит так: ‘‘Пояса’’, ‘‘Сумки’’,

‘‘Часы’’, ‘‘Бумажники’’, ‘‘Все остальное’’.

Page 393: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 393

Рис. 13.10. Желаемый порядок сортировки списка вячейках A2:C16 указан в столбце I

Следующий макрос сортирует список с учетом заданного порядка сортиY

ровки.

Sub CustomSort() ' Задать желаемый порядок сортировки. Application.AddCustomList ListArray:=Range("I1:I5")

' Определить номер списка, задающего порядок сортировки. nIndex = Application.GetCustomListNum(Range("I1:I5").Value)

' Отсортировать список, используя заданный порядок сортировки.' Номер списка, задающего порядок сортировки, равен nIndex + 1,' поскольку обычный порядок сортировки имеет номер 1. Range("A2:C16").Sort Key1:=Range("B2"), Order1:=xlAscending, _Header:=xlNo, Orientation:=xlSortColumns, OrderCustom:=nIndex + 1 Range("A2:C16").Sort Key1:=Range("A2"), Order1:=xlAscending, _Header:=xlNo, Orientation:=xlSortColumns

' Удалить список, задающий порядок сортировки. Application.DeleteCustomList nIndexEnd Sub

Результат выполнения макроса CustomSort показан на рис. 13.11.

Рис. 13.11. В результате выполнения макроса список вячейках A2:C16 отсортирован сперва по дате, а затем —в соответствии с порядком, заданным в столбце I

Page 394: ? Применение VBA и макросов в Microsoft® Excel

394 Часть II Автоматизация Excel

Создание индикатора хода процесса

Макрос Worksheet_Change любезно предоставлен Томом Уртисом.

Следующий макрос создает индикатор хода процесса в столбце C, основыY

ваясь на данных в столбцах A и B (рис. 13.12).

Рис. 13.12. Индикатор хода процесса

Private Sub Worksheet_Change(ByVal Target As Range)If Target.Column > 2 Or Target.Cells.Count > 1 Then Exit SubIf Application.IsNumber(Target.Value) = False Then Application.EnableEvents = False Application.Undo Application.EnableEvents = True MsgBox "Введите число." Exit SubEnd IfSelect Case Target.Column Case 1 If Target.Value > Target.Offset(0, 1).Value Then Application.EnableEvents = False Application.Undo Application.EnableEvents = True MsgBox "Значение в столбце A не может быть больше _значения в столбце B." Exit Sub End If Case 2 If Target.Value < Target.Offset(0, -1).Value Then Application.EnableEvents = False Application.Undo Application.EnableEvents = True MsgBox "Значение в столбце B не может быть меньше _значения в столбце A." Exit Sub End IfEnd SelectDim x As Long

Page 395: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 395

x = Target.RowDim z As Stringz = Range("B" & x).Value - Range("A" & x).ValueWith Range("C" & x)' В англоязычной версии Excel:' .Formula = "=IF(RC[-1]<=RC[-2],REPT(""n"",RC[-1])&REPT(""n"", _RC[-2]-RC[-1]),REPT(""n"",RC[-2])&REPT(""o"",RC[-1]-RC[-2]))" .FormulaLocal = "=ЕСЛИ(RC[-1]<=RC[-2];ПОВТОР(""n""; _RC[-1])&ПОВТОР(""n"";RC[-2]-RC[-1]);ПОВТОР(""n""; _RC[-2])&ПОВТОР(""o"";RC[-1]-RC[-2]))" .Value = .Value .Font.Name = "Wingdings" .Font.ColorIndex = 1 .Font.Size = 10 If Len(Range("A" & x)) <> 0 Then .Characters(1, (.Characters.Count - z)).Font.ColorIndex = 3 .Characters(1, (.Characters.Count - z)).Font.Size = 12 End IfEnd WithEnd Sub

Создание защищенного поля для ввода пароля

Макрос HiddenPassword любезно предоставлен Даниелем Клэнном

(Daniel Klann), проживающим в Сиднее, Австралия. Даниель знаком со мноY

жеством различных языков программирования, однако предпочитает разраY

ботку приложений на VBA для Excel и Access. Клэнн YYYY автор собственного

WebYсайта, который находится по адресу: www.danielklann.com.

Использование для ввода пароля обычного текстового поля крайне нежеY

лательно, поскольку все вводимые символы отображаются на экране. СлеY

дующий макрос заменяет символы пароля знаками звездочки (*), превращая

обычное текстовое поле в защищенное поле ввода пароля (рис. 13.13).

Рис. 13.13. Макрос HiddenPassword пре&вращает обычное текстовое поле в защищен&ное поля ввода пароля

'Используемые функции API.Private Declare Function CallNextHookEx Lib "user32" _(ByVal hHook As Long, ByVal ncode As Long, _ByVal wParam As Long, lParam As Any) As Long

Private Declare Function GetModuleHandle Lib "kernel32" Alias _"GetModuleHandleA" (ByVal lpModuleName As String) As Long

Page 396: ? Применение VBA и макросов в Microsoft® Excel

396 Часть II Автоматизация Excel

Private Declare Function SetWindowsHookEx Lib "user32" Alias _"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _ByVal hmod As Long, ByVal dwThreadId As Long) As Long

Private Declare Function UnhookWindowsHookEx Lib "user32" _(ByVal hHook As Long) As Long

Private Declare Function SendDlgItemMessage Lib "user32" Alias _"SendDlgItemMessageA" (ByVal hDlg As Long, _ByVal nIDDlgItem As Long, ByVal wMsg As Long, _ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function GetClassName Lib "user32" _Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName _As String, ByVal nMaxCount As Long) As Long

Private Declare Function GetCurrentThreadId Lib "kernel32" () _As Long

'Константы, используемые в функциях API.Private Const EM_SETPASSWORDCHAR = &HCCPrivate Const WH_CBT = 5Private Const HCBT_ACTIVATE = 5Private Const HC_ACTION = 0

Private hHook As Long

Sub HiddenPassword()

If InputBoxDK("Введите пароль", "Ввод пароля") <> _"password" Then

MsgBox "Неверный пароль! Доступ запрещен."

Else

MsgBox "Верный пароль! Добро пожаловать!"

End If

End Sub

Public Function NewProc(ByVal lngCode As Long, _ByVal wParam As Long, ByVal lParam As Long) As Long Dim RetVal Dim strClassName As String, lngBuffer As Long

If lngCode < HC_ACTION Then NewProc = CallNextHookEx(hHook, lngCode, wParam, lParam) Exit Function End If

strClassName = String$(256, " ") lngBuffer = 255

If lngCode = HCBT_ACTIVATE Then 'Окно активировано.

Page 397: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 397

RetVal = GetClassName(wParam, strClassName, lngBuffer)

'Имя класса обычного текстового поля. If Left$(strClassName, RetVal) = "#32770" Then

'Следующая строка превращает обычное текстовое поле в защищенное'поле ввода пароля. Символ "*" можно заменить на любой другой. SendDlgItemMessage wParam, &H1324, _EM_SETPASSWORDCHAR, Asc("*"), &H0 End If

End If

'Следующая строка гарантирует корректный вызов'всех обработчиков прерываний. CallNextHookEx hHook, lngCode, wParam, lParam

End Function

Public Function InputBoxDK(Prompt, Optional Title, _Optional Default, Optional XPos, Optional YPos, _Optional HelpFile, Optional Context) As String Dim lngModHwnd As Long, lngThreadID As Long

lngThreadID = GetCurrentThreadId lngModHwnd = GetModuleHandle(vbNullString)

hHook = SetWindowsHookEx(WH_CBT, AddressOf NewProc, _lngModHwnd, lngThreadID) On Error Resume Next InputBoxDK = InputBox(Prompt, Title, Default, XPos, YPos, _HelpFile, Context) UnhookWindowsHookEx hHook

End Function

Изменение регистра текста

Макрос TextCaseChange любезно предоставлен Иваном Ф. Моалой.

Word позволяет изменять регистр выделенного текста. Следующий макрос

делает возможным изменение регистра текста, находящегося в выделенном

диапазоне рабочего листа Excel.

Sub TextCaseChange()Dim RgText As RangeDim oCell As RangeDim Ans As StringDim strTest As StringDim sCap As Integer, _ lCap As Integer, _ i As Integer

'// Предполагается, что перед вызовом макроса'// пользователь выделил требуемый диапазон текста.

Again:

Page 398: ? Применение VBA и макросов в Microsoft® Excel

398 Часть II Автоматизация Excel

Ans = Application.InputBox("[С]трочные" & vbCr & "[П]рописные" _& vbCr & "[К]ак в предложениях" & vbCr & "[Н]ачинать с прописных" _& vbCr & "[М]алые прописные", "Введите букву", Type:=2)

If Ans = "False" Then Exit SubIf InStr(1, "СПКНМ", UCase(Ans), vbTextCompare) = 0 Or _Len(Ans) > 1 Then GoTo Again

On Error GoTo NoTextIf Selection.Count = 1 Then Set RgText = SelectionElse Set RgText = Selection.SpecialCells(xlCellTypeConstants, 2)End IfOn Error GoTo 0

For Each oCell In RgText Select Case UCase(Ans) Case "С": oCell = LCase(oCell.Text) Case "П": oCell = UCase(oCell.Text) Case "К": oCell = UCase(Left(oCell.Text, 1)) & _LCase(Right(oCell.Text, Len(oCell.Text) - 1)) Case "Н": oCell = Application.WorksheetFunction.Proper( _oCell.Text) Case "М" lCap = oCell.Characters(1, 1).Font.Size sCap = Int(lCap * 0.85)'Малые прописные для всех букв. oCell.Font.Size = sCap oCell.Value = UCase(oCell.Text) strTest = oCell.Value'Большие прописные для 1-х букв слов. strTest = Application.Proper(strTest) For i = 1 To Len(strTest) If Mid(strTest, i, 1) = UCase(Mid(strTest, _i, 1)) Then oCell.Characters(i, 1).Font.Size = lCap End If Next i End SelectNext

Exit SubNoText:MsgBox "Текст в диапазоне " & Selection.Address & " отсутствует"

End Sub

Обработка события удаления строки или столбца

Макросы EventHack и EventReset, а также вспомогательные процедуры

AssignMacro, JudgeRng и DelExecute любезно предоставлены Масару

Каджи (Masaru Kaji).

Excel не предусматривает возможность обработки события удаления строY

ки или столбца. Следующий макрос устраняет этот недостаток: при удалении

Page 399: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 399

строки или столбца на экран выводится сообщение, содержащее номер удаY

ленной строки или удаленного столбца.

Sub EventHack() AssignMacro "JudgeRng"End SubSub EventReset() AssignMacro ""End Sub

Private Sub AssignMacro(ByVal strProc As String) Dim lngId As Long Dim CtrlCbc As CommandBarControl Dim CtrlCbcRet As CommandBarControls Dim arrIdNum As Variant

'// 293: команда Удалить строки (Delete Rows)'// контекстного меню строки.'// 294: команда Удалить (Delete) контекстного'// меню столбца.'// 478: команда Удалить (Delete) меню Правка (Edit). arrIdNum = Array(293, 294, 478)

For lngId = LBound(arrIdNum) To UBound(arrIdNum) Set CtrlCbcRet = CommandBars.FindControls( _ID:=arrIdNum(lngId)) For Each CtrlCbc In CtrlCbcRet CtrlCbc.OnAction = strProc Next Set CtrlCbcRet = Nothing NextEnd Sub

Private Sub JudgeRng() If Not TypeOf Selection Is Range Then Exit Sub With Selection If .Address = .EntireRow.Address Then Call DelExecute("строка: " & .Row, xlUp) ElseIf .Address = .EntireColumn.Address Then Call DelExecute("столбец: " & .Column, xlToLeft) Else Application.Dialogs(xlDialogEditDelete).Show End If End WithEnd Sub

Private Sub DelExecute(ByVal str, ByVal lngDerec As Long) MsgBox "Удален(а): " & str Selection.Delete lngDerecEnd Sub

Поиск заданного текста с помощью свойства SpecialCells

Макросы CheckAllCells и CheckSpecialCellsOnly любезно предосY

тавлены Иваном Ф. Моалой.

При поиске значения, текста или формулы в заданном диапазоне Excel

проверяет каждую ячейку этого диапазона. Макрос CheckAllCells провоY

Page 400: ? Применение VBA и макросов в Microsoft® Excel

400 Часть II Автоматизация Excel

дит поиск заданного текста в диапазоне A1:Z20000, проверяя каждую его

ячейку. Макрос CheckSpecialCellsOnly проводит поиск заданного текста

в диапазоне A1:Z20000, проверяя только ячейки, содержащие текстовые

константы. По окончании поиска оба макроса выводят сведения о результатах

поиска и затраченном на это времени.

Sub CheckAllCells()Dim TheRange As RangeDim oCell As Range

StartTime = Now Ctr = 0 Set TheRange = Range("A1:Z20000") For Each oCell In TheRange If oCell.Text = "Ваш текст" Then Ctr = Ctr + 1 End If Next oCell EndTime = Now

Msg = "Проверено " & TheRange.Cells.Count & " ячеек. _Найдено " & Ctr & " совпадений. Время поиска = " & _Format(EndTime - StartTime, "h:mm:ss") MsgBox Msg

End Sub

Sub CheckSpecialCellsOnly()Dim TheRange As RangeDim oCell As Range

StartTime = Now Ctr = 0

Set TheRange = Range("A1:Z20000").SpecialCells( _xlCellTypeConstants, xlTextValues)

For Each oCell In TheRange If oCell.Text = "Ваш текст" Then Ctr = Ctr + 1 End If Next oCell EndTime = Now

Msg = "Проверено " & TheRange.Cells.Count & " ячеек. _Найдено " & Ctr & " совпадений. Время поиска = " _& Format(EndTime - StartTime, "h:mm:ss") MsgBox Msg

End Sub

Условное удаление строк

Макрос Delete_rows_with_conditions любезно предоставлен ДенниY

сом Валентайном (Dennis Wallentin), проживающим в Остерсунде, Швеция.

Page 401: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 401

Следующий макрос удаляет определенное число строк при выполнении усY

ловия ‘‘ячейка в столбце A пуста’’.

Sub Delete_rows_with_conditions()Dim wbBook As WorkbookDim wsSheet As WorksheetDim rnArea As RangeDim lnLastRow As Long, lnMoreRows As LongDim i As Long, j As Long, k As Long

Set wbBook = ThisWorkbookSet wsSheet = wbBook.Worksheets("Условное удаление строк")

Application.ScreenUpdating = False

'Определение числа строк, которые нужно удалить.j = 5

With wsSheet'Определение номера последней строки по столбцу A. lnLastRow = .Cells(Rows.Count, 1).End(xlUp).Row + 1

'Определение номера последней строки по столбцам A, B и C. For k = 1 To 3 lnMoreRows = .Cells(Rows.Count, k).End(xlUp).Row + 1 If lnLastRow < lnMoreRows Then lnLastRow = lnMoreRows End If Next k

'Удаление строк с пустой ячейкой в столбце A. For i = lnLastRow To 1 Step -1 If IsEmpty(.Cells(i, 1)) Then .Cells(i, 1).Resize(j, 1).EntireRow.Delete End If Next iEnd With

Application.ScreenUpdating = True

End Sub

Сокрытие строки формул

Макрос Worksheet_SelectionChange любезно предоставлен Томом

Уртисом.

Если активная ячейка содержит более 50 символов, строка формул автомаY

тически увеличивается в размере и перекрывает часть рабочего листа Excel.

Следующий макрос скрывает строку формул при выделении ячейки, содерY

жащей более 50 символов.

Private Sub Worksheet_SelectionChange(ByVal Target As Range)If Target.Cells.Count > 1 Then Exit SubOn Error Resume NextIf Len(Target.Text) > 50 Or Len(Target.Formula) > 50 Then

Page 402: ? Применение VBA и макросов в Microsoft® Excel

402 Часть II Автоматизация Excel

Application.DisplayFormulaBar = FalseElse Application.DisplayFormulaBar = TrueEnd IfEnd Sub

Результат выполнения макроса Worksheet_SelectionChange показан

на рис. 13.14.

Рис. 13.14. Макрос Worksheet_SelectionChange скрываетстроку формул при выделении ячейки, содержащей более50 символов

На закускуВ этом разделе рассматривается несколько занятных макросов, которым

можно найти применение в самых различных приложениях.

Извлечение информации о курсах акций из Internet

Процедура GetQuote любезно предоставлена Натаном П. Оливером.

Следующая процедура извлекает из Internet информацию о курсе акций

компании на заданную дату.

Page 403: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 403

Private Sub GetQuote()Dim ie As Object, lCharPos As Long, sHTML As StringDim HistDate As Date, HighVal As String, LowVal As StringDim cl As Range

Set cl = ActiveCellHistDate = cl(, 0)

If Intersect(cl, [c2:c65366]) Is Nothing Then MsgBox "Выберите ячейку в столбце C." Exit SubEnd If

If Not CBool(Len(cl(, -1))) Or Not CBool(Len(cl(, 0))) Then MsgBox "Введите символ акций и требуемую дату." Exit SubEnd If

Set ie = CreateObject("InternetExplorer.Application")

With ie .Navigate "http://bigcharts.marketwatch.com/historical/ _default.asp?detect=1&symbol=" & cl(, -1) & "&close_date=" & _Month(HistDate) & "%2F" & Day(HistDate) & "%2F" & _Year(HistDate) & "&x=31&y=26" Do While .Busy And .ReadyState <> 4 DoEvents Loop sHTML = .Document.body.innertext .QuitEnd With

Set ie = Nothing

lCharPos = InStr(1, sHTML, "High:", vbTextCompare)If lCharPos Then HighVal = Mid$(sHTML, lCharPos + 5, 15)

If Not Left$(HighVal, 3) = "n/a" Then lCharPos = InStr(1, sHTML, "Low:", vbTextCompare) If lCharPos Then LowVal = Mid$(sHTML, lCharPos + 4, 15) cl.Value = (Val(LowVal) + Val(HighVal)) / 2Else: lCharPos = InStr(1, sHTML, "Closing Price:", vbTextCompare) cl.Value = Val(Mid$(sHTML, lCharPos + 14, 15))End If

Set cl = NothingEnd Sub

Результат выполнения процедуры GetQuote показан на рис. 13.15.

Рис. 13.15. Процедура GetQuote извлекаетиз Internet информацию о курсе акций ком&пании на заданную дату

Page 404: ? Применение VBA и макросов в Microsoft® Excel

404 Часть II Автоматизация Excel

Вставка программного кода во вновьсозданную рабочую книгу

Ранее в этой главе был рассмотрен макрос, создающий отчеты для региоY

нальных менеджеров в виде отдельных рабочих книг. Усложним задачу, поY

требовав скопировать в новые рабочие книги программный код. Для этого обY

ратимся к объектной модели Microsoft Visual Basic for Applications Extensibility,

позволяющей не только импортировать в рабочую книгу модули с программY

ным кодом, но и создавать код непосредственно в рабочей книге.

Прежде чем выполнить какойYлибо из приведенных ниже макросов, подY

ключите библиотеку Microsoft Visual Basic for Applications Extensibility 5.3, выбрав

команду меню редактора Visual Basic Tools References (Сервис Ссылки) и усY

тановив соответствующий флажок в открывшемся диалоговом окне.

Наиболее простой способ переноса программного кода заключается в

экспорте модуля и пользовательской формы из текущей рабочей книги и их

последующем импорте в новую рабочую книгу. Предположим, что региоY

нальному менеджеру необходимо передать отчет с данными о его регионе

и 3 макроса, реализующие форматирование и печать отчета. Поместите все

3 макроса в модуль modToRegion. Предположим также, что макросы модуля

modToRegion вызывают пользовательскую форму frmRegion. Следующий

макрос перенесет программный код и пользовательскую форму в новую рабоY

чую книгу.

Sub MoveDataAndMacro() Dim WSD As Worksheet Set WSD = Worksheets("Отчет")' Скопировать отчет в новую рабочую книгу. WSD.Copy' Сделать новую рабочую книгу активной.' Удалить старые копии промежуточных файлов с диска. On Error Resume Next Kill ("C:\ModToRegion.bas") Kill ("C:\frmRegion.frm") On Error GoTo 0' Экспортировать модуль и форму из исходной рабочей книги. ThisWorkbook.VBProject.VBComponents("ModPics").Export _("C:\ModToRegion.bas") ThisWorkbook.VBProject.VBComponents("frmModPics").Export _("C:\frmRegion.frm")' Импортировать модуль и форму в новую рабочую книгу. ActiveWorkbook.VBProject.VBComponents.Import _("C:\ModToRegion.bas") ActiveWorkbook.VBProject.VBComponents.Import _("C:\frmRegion.frm") On Error Resume Next Kill ("C:\ModToRegion.bas") Kill ("C:\frmRegion.frm") On Error GoTo 0End Sub

Page 405: ? Применение VBA и макросов в Microsoft® Excel

Excel всемогущий Глава 13 405

Чтобы создать программный код непосредственно в рабочей книге, следует

обратить внимание на два инструмента: метод Lines и метод InsertLines.

Метод Lines позволяет извлечь заданное число строк из указанного модуля,

а метод InsertLines — вставить код в модуль.

Внимание Код, который добавляется в рабочую книгу с помощью метода InsertLines, тутже компилируется. Сбой при компиляции кода может привести к ошибке общегонарушения защиты (General Protection Failure, GPF), чего нужно всячески избегать.

Следующий макрос копирует весь код модуля ЭтаКнига исходной рабочей

книги в модуль ЭтаКнига новой рабочей книги.

Sub MoveDataAndMacro() Dim WSD As Worksheet Dim WBN As Workbook Set WSD = Worksheets("Отчет")' Скопировать отчет в новую рабочую книгу. WSD.Copy' Сделать новую рабочую книгу активной. Set WBN = ActiveWorkbook' Скопировать обработчики событий уровня рабочей книги. Set WBCodeMod1 = ThisWorkbook.VBProject.VBComponents( _"ЭтаКнига").CodeModule Set WBCodeMod2 = WBN.VBProject.VBComponents( _"ЭтаКнига").CodeModule WBCodeMod2.InsertLines 1, WBCodeMod1.Lines(1, _WBCodeMod1.CountOfLines)

Следующий шагВ следующей главе рассматриваются WebYзапросы, позволяющие импорY

тировать данные из Internet в приложения Excel.

Page 406: ? Применение VBA и макросов в Microsoft® Excel
Page 407: ? Применение VBA и макросов в Microsoft® Excel

Извлечение данных изInternet........................................... 407Извлечение данных изInternet в режиме реальноговремени..........................................413Анализ данных, извлеченныхиз Internet.......................................414Размещение данных на WebLстранице.........................................418Следующий шаг........................... 425

14Глава 14

Âçàèìîäåéñòâèåñ Internet

В этой главе рассматривается авY

томатизация WebYзапросов, целью

которых является помещение инY

формации из Internet в электронную

таблицу, и наоборот.

Извлечение данныхиз Internet

На рис. 14.1 показана страница

WebYсайта Finance.Yahoo.com, содерY

жащая сведения о курсах акций разY

личных компаний.

Понимая всю важность электронY

ных таблиц, разработчики поместили

внизу страницы ссылку, позволяюY

щую загрузить данные, которые были

получены в результате WebYзапроса,

в файле формата CSV.

Создание WebLзапросас помощьюпользовательскогоинтерфейса Excel

Рассмотрим создание WebYзапроса

вручную с помощью пользовательского

интерфейса Excel. Запустите WebY

обозреватель и откройте страницу, соY

держащую требуемую информацию.

Ниже приведен адрес URL страницы,

изображенной на рис. 14.1:

http://finance.yahoo.com/q/cq?d=v1&s=PSO,+SJM,+KO,+MSFT,+CSCO,+INTC

Page 408: ? Применение VBA и макросов в Microsoft® Excel

408 Часть II Автоматизация Excel

Рис. 14.1. Web&сайт Finance.Yahoo.com позволяет получить информацию отекущих курсах акций

Откройте Excel и выберите на рабочем листе пустую область, предназначенY

ную для вставки данных из Internet. Выберите команду меню Данные Импортвнешних данных Создать веб-запрос (Data Import External Data New Web

Query). Скопируйте адрес WebYстраницы из окна обозревателя в поле Адрес(Address) открывшегося диалогового окна Создание веб-запроса (New Web

Query) и щелкните на кнопке Пуск (Go). Загрузившаяся WebYстраница будет

содержать значки с изображением черной стрелки в желтом квадрате, обознаY

чающие левые верхние углы имеющихся на странице таблиц. При подведении

указателя мыши к такому значку на экране появится рамка, ограничивающая

соответствующую таблицу. Щелкните на значке, чтобы выбрать таблицу. В реY

зультате этого стрелка сменится флажком, а цвет фона станет зеленым вместо

желтого (рис. 14.2).

Щелкните на кнопке Импорт (Import), а затем YYYY на кнопке OK в открывY

шемся диалоговом окне Импорт данных (Import Data). Через несколько сеY

кунд данные из Internet будут помещены на рабочий лист Excel, как показано

на рис. 14.3.

Page 409: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 409

Рис. 14.2. Выберите требуемую таблицу, щелкнув на соответствующем значке с изображе&нием черной стрелки в желтом квадрате

Рис. 14.3. Данные успешно скопированы с Web&страницы на рабочий лист Excel

Обновление существующего WebLзапроса с помощью VBA

Чтобы обновить все WebYзапросы на текущем рабочем листе, выполните

следующий код VBA, назначив его кнопке или комбинации клавиш:

Sub RefreshAllWebQueries() Dim QT As QueryTable For Each QT In ActiveSheet.QueryTables Application.StatusBar = "Обновление " & QT.Connection QT.Refresh

Page 410: ? Применение VBA и макросов в Microsoft® Excel

410 Часть II Автоматизация Excel

Next QT Application.StatusBar = FalseEnd Sub

Создание WebLзапроса с помощью VBAРассмотренный ранее пример имеет один существенный недостаток YYYY

при изменении портфеля акций соответствующим образом следует изменить

и жестко заданный WebYзапрос.

Создать WebYзапрос ‘‘на лету’’ совсем не сложно. Для этого нужно сформиY

ровать так называемую строку подключения, пример которой показан ниже:

URL;http://finance.yahoo.com/q/cq?d=v1&s=PSO,+SJM,+KO,+MSFT,+CSCO,+INTC

При формировании строки подключения не обойтись без символа соедиY

нения строк, реализующего ‘‘сцепление’’ основной части строки подключеY

ния с заданными пользователем символами акций.

На рис. 14.4 показан простейший интерфейс создания WebYзапросов.

Рис. 14.4. Введите символы акций в ячейки столбца A и щелкните на кнопке Узнатькурсы акций

Введите символы акций в ячейки столбца A и щелкните на кнопке Узнатькурсы акций, чтобы выполнить макрос CreateNewQuery.

Макрос CreateNewQuery создает строку подключения, объединяя ее осY

новную часть с символом акций, размещенном в ячейке A2:

ConnectString = "URL;http://finance.Yahoo.com/q/cq?d=v1&s=" & _WSD.Cells(i, 1).Value

По мере обнаружения новых символов акций макрос добавляет в конец

существующей строки подключения комбинацию ,+ и символ акции:

ConnectString = ConnectString & ",+" & WSD.Cells(i, 1).Value

Page 411: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 411

После формирования строки подключения макрос удаляет все ранее созY

данные WebYзапросы, выполняет новый WebYзапрос и помещает его результат

на рабочий лист Вспомогательный лист.

Следует отметить, что при выполнении WebYзапроса параметр Back-groundRefresh метода Refresh устанавливается равным False. Это поY

зволяет приостановить выполнение макроса на время, требующееся для изY

влечения информации из Internet.

После получения данных макрос присваивает имя соответствующему диаY

пазону ячеек рабочего листа Вспомогательный лист и переносит извлеY

ченную из Internet информацию на рабочий лист Портфель акций с помоY

щью формул ВПР (VLOOKUP).

Sub CreateNewQuery() Dim WSD As Worksheet Dim WSW As Worksheet Dim QT As QueryTable

Set WSD = Worksheets("Портфель акций") Set WSW = Worksheets("Вспомогательный лист")

' Создание строки подключения. FinalRow = WSD.Cells(65536, 1).End(xlUp).Row For i = 2 To FinalRow Select Case i Case 2 ConnectString = _"URL;http://finance.Yahoo.com/q/cq?d=v1&s=" & WSD.Cells(i, 1).Value Case Else ConnectString = _ConnectString & ",+" & WSD.Cells(i, 1).Value End Select Next i

' Удаление существующих запросов. For Each QT In WSW.QueryTables QT.Delete Next QT

WSW.Select WSW.Cells.Clear

' Создание нового запроса. Set QT = WSW.QueryTables.Add(Connection:=ConnectString, _Destination:=WSW.Range("A1")) With QT .Name = "portfolio" .FieldNames = True .RowNumbers = False .FillAdjacentFormulas = False .PreserveFormatting = True .RefreshOnFileOpen = False .BackgroundQuery = False .RefreshStyle = xlInsertDeleteCells .SavePassword = False

Page 412: ? Применение VBA и макросов в Microsoft® Excel

412 Часть II Автоматизация Excel

.SaveData = True .AdjustColumnWidth = True .RefreshPeriod = 0 .WebSelectionType = xlSpecifiedTables .WebFormatting = xlWebFormattingNone .WebTables = "20" .WebPreFormattedTextToColumns = True .WebConsecutiveDelimitersAsOne = True .WebSingleBlockTextImport = False .WebDisableDateRecognition = False .WebDisableRedirections = False End With

' Выполнение запроса. QT.Refresh BackgroundQuery:=True

' Создание именованного диапазона,' содержащего результаты запроса. WSW.Cells(1, 1).Resize(FinalRow, 6).Name = "WebInfo"

' Перенесение полученной информации' на рабочий лист "Портфель акций". RowCount = FinalRow - 1' В англоязычной версии Excel:'WSD.Cells(2, 2).Resize(RowCount, 1).FormulaR1C1 = _"=VLOOKUP(RC1,WebInfo,3,False)" WSD.Cells(2, 2).Resize(RowCount, 1).FormulaR1C1Local = _"=ВПР(RC1;WebInfo;3;ЛОЖЬ)"' В англоязычной версии Excel:'WSD.Cells(2, 3).Resize(RowCount, 1).FormulaR1C1 = _"=VLOOKUP(RC1,WebInfo,4,False)" WSD.Cells(2, 3).Resize(RowCount, 1).FormulaR1C1Local = _"=ВПР(RC1;WebInfo;4;ЛОЖЬ)"' В англоязычной версии Excel:'WSD.Cells(2, 4).Resize(RowCount, 1).FormulaR1C1 = _"=VLOOKUP(RC1,WebInfo,5,False)" WSD.Cells(2, 4).Resize(RowCount, 1).FormulaR1C1Local = _"=ВПР(RC1;WebInfo;5;ЛОЖЬ)"' В англоязычной версии Excel:'WSD.Cells(2, 5).Resize(RowCount, 1).FormulaR1C1 = _"=VLOOKUP(RC1,WebInfo,6,False)" WSD.Cells(2, 5).Resize(RowCount, 1).FormulaR1C1Local = _"=ВПР(RC1;WebInfo;6;ЛОЖЬ)" WSD.Cells(2, 6).Resize(RowCount, 1).Value = Time WSD.Cells(2, 6).Resize(RowCount, 1).NumberFormat = "h:m:s"

WSD.Select MsgBox "Подождите, пока будут обновлены данные"

End Sub

Результат выполнения макроса CreateNewQuery показан на рис. 14.5.

Page 413: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 413

Рис. 14.5. В результате выполнения макроса CreateNewQuery на рабочий листПортфель акций помещается только существенная информация. Необработанныйрезультат Web&запроса можно увидеть на листе Вспомогательный лист

Извлечение данных из Internet в режимереального времени

В Internet существует много служб, позволяющих доставлять данные непоY

средственно на рабочий лист Excel в режиме реального времени. Обычно для

доставки данных используется технология DDE.

Вызов типичной DDEYслужбы реального времени осуществляется посредY

ством формулы, идентифицирующей внешний исполняемый файл (.exe).

Чтобы передать удаленной программе входные данные, используется символ

перенаправления (|).

На рис. 14.6 показан пример вызова удаленной программы MktLink.exe,

возвращающей курс акций с символом AA.

Рис. 14.6. Вызов типичной DDE&службы ре&ального времени

Наблюдать за изменением курса акций в режиме реального времени, несоY

мненно, интересно. Однако еще более интересно и полезно анализировать

получаемую информацию с целью выявления трендов.

Page 414: ? Применение VBA и макросов в Microsoft® Excel

414 Часть II Автоматизация Excel

Анализ данных, извлеченных из InternetVBA содержит метод OnTime, позволяющий выполнить любую процедуY

ру в определенный момент времени или по прошествии заданного периода

времени.

Ниже приведен код VBA, извлекающий данные из Internet каждый час на

протяжении всего рабочего дня.

Sub ScheduleTheDay() Application.OnTime EarliestTime:=TimeValue("8:00 AM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("9:00 AM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("10:00 AM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("11:00 AM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("12:00 AM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("1:00 PM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("2:00 PM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("3:00 PM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("4:00 PM"), _Procedure:="CaptureData" Application.OnTime EarliestTime:=TimeValue("5:00 PM"), _Procedure:="CaptureData"End Sub

Sub CaptureData() Dim WSQ As Worksheet Set WSQ = Worksheets("MyQuery")' Выполнить запрос. WSQ.Range("A2").QueryTable.Refresh BackgroundQuery:=False' Приостановить выполнение макроса. Application.Wait (Now + TimeValue("0:00:05"))' Скопировать результаты запроса. NextRow = WSQ.Range("A65536").End(xlUp).Row + 1 WSQ.Range("A2:B2").Copy WSQ.Cells(NextRow, 1)' Зафиксировать дату и время. WSQ.Cells(NextRow, 2).Value = WSQ.Cells(NextRow, 2).ValueEnd Sub

Условия выполнения метода OnTime

Метод OnTime выполняется в заданный момент времени при условии преY

бывания Excel в режиме готовности (Ready), копирования (Copy), вырезания

(Cut) или поиска (Find). Excel не сможет выполнить макрос CaptureData в

08:00, если в это время какаяYлибо ячейка рабочего листа находится в режиме

редактирования.

Page 415: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 415

Обратите внимание, что в предыдущем примере было задано только наY

чальное время выполнения макроса CaptureData. Это означает, что Excel

будет терпеливо ожидать возвращения в режим готовности, чтобы выполнить

указанный макрос.

Предположим, что пользователь начал редактировать ячейку в 07:59, а заY

тем был вызван на экстренное совещание, продолжавшееся до 10:30. За это

время Excel должен был выполнить макрос CaptureData три раза: в 08:00,

09:00 и 10:00. Вернувшись на свое рабочее место и нажав клавишу <Enter>,

чтобы выйти из режима редактирования, пользователь обнаружит, что три

первых WebYзапроса были выполнены между 10:30 и 10:31.

Определение временного окна для выполнения макроса

Чтобы обойти описанную выше проблему, можно определить временные

рамки для выполнения макроса. Следующий код указывает Excel на необхоY

димость выполнения макроса CaptureData в промежутке времени между

08:00 и 08:05. Если на протяжении всего этого периода Excel будет пребывать

в режиме редактирования, выполнение назначенного задания отменяется.

Application.OnTime EarliestTime:=TimeValue("8:00 AM"), _Procedure:="CaptureData", LatestTime:=TimeValue("08:05 AM")

Отмена назначенного заданияОтменить ранее назначенное задание весьма непросто, так как для этого

необходимо знать точное время выполнения макроса. Чтобы отменить назнаY

ченное задание, вызовите метод OnTime, установив значение параметра

Schedule равным False. Ниже приведен код, отменяющий выполнение

макроса CaptureData, назначенное на 11:00.

Sub CancelEleven() Application.OnTime EarliestTime:=TimeValue("11:00 AM"), _ Procedure:="CaptureData", _ Schedule:=FalseEnd Sub

Обратите внимание, что расписание, заданное с помощью метода OnTime,

существует на уровне выполняющейся копии Excel. Другими словами, закрыY

тие рабочей книги не отменяет текущее расписание, если копия Excel остается

открытой. Рассмотрим приведенную ниже последовательность действий.

1. Открытие Excel в 07:30.

2. Открытие рабочей книги Schedule.xls и запуск макроса, назначаюY

щего выполнение процедуры на 08:00.

3. Закрытие рабочей книги Schedule.xls.

4. Открытие новой рабочей книги и начало ввода данных.

В 08:00 Excel откроет рабочую книгу Schedule.xls и выполнит назнаY

ченное задание. Естественно, это может стать полной неожиданностью для

Page 416: ? Применение VBA и макросов в Microsoft® Excel

416 Часть II Автоматизация Excel

пользователя. При большом числе назначенных заданий рекомендуется отY

крывать две копии Excel, одну из которых использовать для выполнения задаY

ний, а другую YYYY для работы.

Отмена всех назначенных заданий

Чтобы отменить все назначенные задания, закройте Excel с помощью коY

манды меню Файл Выход (File Exit). Обычно к подобному действию приY

бегают при необходимости отмены большого числа автоматически назначенY

ных заданий с заранее неизвестным точным временем выполнения.

Выполнение макроса по прошествии заданного периодавремени

Excel позволяет выполнить макрос по прошествии заданного периода вреY

мени. Например, макрос CaptureData будет запущен через 2 мин и 30 с поY

сле выполнения следующего кода.

Sub ScheduleAnything() WaitHours = 0 WaitMin = 2 WaitSec = 30 NameOfScheduledProc = "CaptureData"

' Определение времени выполнения назначенного задания. NextTime = Time + TimeSerial(WaitHours, WaitMin, WaitSec)

' Создание назначенного задания. Application.OnTime EarliestTime:=NextTime, _Procedure:=NameOfScheduledProc

End Sub

Периодическое выполнение макроса через определенныепромежутки времени

Предположим, что некий макрос нужно выполнять каждые 2 мин. Если в

заданное время Excel находится в режиме редактирования, выполнение макY

роса, назначенное на это время, следует отменить.

Одно из наиболее очевидных решений поставленной задачи заключается в

рекурсивном планировании макросом своего собственного выполнения.

Sub ScheduleRepeatedly() WaitHours = 0 WaitMin = 2 WaitSec = 0 NameOfThisProcedure = "ScheduleRepeatedly" NameOfScheduledProc = "CaptureData"

' Определение времени выполнения назначенного задания. NextTime = Time + TimeSerial(WaitHours, WaitMin, WaitSec)

Page 417: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 417

' Создание назначенного задания. Application.OnTime EarliestTime:=NextTime, _Procedure:=NameOfThisProcedure

' Выполнить макрос NameOfScheduledProc' (в данном случае - макрос "CaptureData"). Application.Run NameOfScheduledProc

End Sub

Подобный подход имеет неоспоримые преимущества. ВоYпервых, он поY

зволяет не планировать огромное число заданий наперед. В каждый момент

времени существует только одно назначенное задание. ВоYвторых, чтобы преY

кратить периодическое выполнение макроса CaptureData каждые 2 мин,

достаточно закомментировать строку Application.OnTime Earliest-Time:=NextTime, Procedure:=NameOfThisProcedure и дождаться поY

следнего выполнения этого макроса.

Практикум

Отслеживание размера национального долга СШАРассмотрим рабочий лист, показанный на рис. 14.7.

Рис. 14.7. Ячейка A2 содержит результат Web&запро&

са, а ячейка B2 — текущие дату и время. Цель мак&роса DebtClock — каждые 15 с получать из Internetданные о размере национального долга США исохранять их на рабочем листе Национальныйдолг США, начиная с 6&й строки

Ячейка A2 содержит результаты Web&запроса по адресу: http://brillig.com/debt_clock/, а ячейка B2 — функцию ТДАТА (NOW).Макрос DebtClock предназначен для отслеживания размера национальногодолга США. Следующий код выполняет Web&запрос, сохраняет полученный ре&зультат на рабочем листе и планирует свое выполнение через 15 с.Sub DebtClock() Dim WSQ As Worksheet Set WSQ = Worksheets("Национальный долг США")

' Ячейка A2 содержит Web-запрос по адресу: ' http://brillig.com/debt_clock WaitSec = 15

Page 418: ? Применение VBA и макросов в Microsoft® Excel

418 Часть II Автоматизация Excel

NameOfThisProcedure = "DebtClock"

' Определение времени выполнения назначенного задания. NextTime = Time + TimeSerial(0, 0, WaitSec)

' Создание назначенного задания. Application.OnTime EarliestTime:=NextTime, _Procedure:=NameOfThisProcedure

' Выполнение Web-запроса. WSQ.Range("A2").QueryTable.Refresh BackgroundQuery:=False' Приостановка выполнения макроса. Application.Wait (Now + TimeValue("0:00:05"))' Копирование результатов запроса. NextRow = WSQ.Range("A65536").End(xlUp).Row + 1 WSQ.Range("A2:B2").Copy WSQ.Cells(NextRow, 1)' Фиксирование даты и времени. WSQ.Cells(NextRow, 2).Value = WSQ.Cells(NextRow, 2).Value

End Sub

Запустив макрос и подождав несколько минут, можно увидеть, что каждую ми&нуту национальный долг США увеличивается примерно на 2 млн долларов(рис. 14.8).

Рис. 14.8. Спустя несколько минут после запуска

макроса DebtClock на рабочем листе будут содер&жаться данные, достаточные для анализа темповизменения национального долга США

Размещение данных на WebLстраницеРанее в этой главе были рассмотрены различные способы извлечения инY

формации из Internet. Вместе с тем, Excel поддерживает и обратную операY

цию YYYY размещение данных рабочего листа на WebYстранице.

Page 419: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 419

В главе 12, ‘‘Сводные таблицы’’, был описан макрос, создающий отчеты

для региональных менеджеров компании. Вместо отправки отчетов по факсу

или электронной почте их можно сохранить в формате HTML и разместить на

корпоративном сайте компании.

Рассмотрим отчет, показанный на рис. 14.9.

Рис. 14.9. Отчет, сгенерированный макросом из главы 12

Чтобы сохранить содержимое рабочего листа в формате HTML с помощью

пользовательского интерфейса Excel, выберите команду меню ФайлСохранить как (File Save As).

Выбрав формат сохранения Веб-страница (Web Page), убедитесь, что флаY

жок Добавить интерактивность (Add interactivity) сброшен (рис. 14.10). В проY

тивном случае созданную WebYстраницу можно будет просмотреть только при

условии наличия на компьютере установленной копии Excel.

Рис. 14.10. Сохраняя рабочий лист в формате Web&страницы, проверьте, чтобыфлажок Добавить интерактивность (Add interactivity) был сброшен — Web&страница будет доступна для гораздо большего числа пользователей

Page 420: ? Применение VBA и макросов в Microsoft® Excel

420 Часть II Автоматизация Excel

Файл, полученный в результате сохранения рабочего листа в формате

HTML, можно просмотреть с помощью любого обозревателя Web, как покаY

зано на рис. 14.11.

Рис. 14.11. Excel успешно справляется с задачей сохранения рабочеголиста в формате HTML

Новая концепция сохранения данных в формате WebYстраницы, представY

ленная Microsoft, предполагает возможность восстановления рабочего листа

на основе полученного HTMLYфайла. Платой за подобную гибкость является

чрезмерный объем генерируемого HTMLYкода. В частности, для представлеY

ния информации, показанной на рис. 14.11, достаточно 457 байт. Будучи пеY

реведенной в формат HTML, эта же информация занимает уже 9105 байт.

Создание WebLстраниц с помощью VBA

Лишенные возможности сохранения рабочего листа в формате WebY

страницы, пользователи предыдущих версий Excel были вынуждены создавать

HTMLYкод с помощью VBA. Следует отметить, что этот метод имеет одно весьY

ма существенное преимущество YYYY он позволяет создавать ‘‘полноценные’’ WebY

страницы (содержащие логотип компании, навигационные панели и т.п.), готоY

вые к немедленному размещению на сайте.

Шаблон типичной WebYстраницы содержит код для отображения логотипа

компании и навигационных панелей, данные этой страницы и код, заверY

шающий HTMLYфайл. Создайте подобный шаблон, поместив вместо данных

страницы текст ‘‘ДАННЫЕ WEBYСТРАНИЦЫ’’, и просмотрите полученный

код с помощью приложения Блокнот (Notepad), как показано на рис. 14.12.

Page 421: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 421

Рис. 14.12. Шаблон типичной Web&страницы можно условно разделить на три части: код дляотображения логотипа компании и навигационных панелей; данные Web&страницы; и код, за&вершающий HTML&файл

Анализ кода типичной WebYстраницы наталкивает на мысль о необходиY

мости поэтапного создания HTMLYкода с помощью VBA.

1. Создайте код для отображения логотипа компании и навигационных

панелей.

2. Создайте код, размещающий на WebYстранице данные с рабочего листа

Excel.

3. Создайте код, завершающий HTMLYфайл.

Применение Excel в качестве системы управлениясодержимым

Создадим простую систему управления содержимым, генерирующую WebY

страницы на основе имеющихся данных Excel.

На рис. 14.13 показано содержимое типичной базы данных.

Разработаем код VBA, генерирующий WebYстраницу на основе данных, поY

казанных на рис. 14.13, и на основе HTMLYкода, показанного на рис. 14.12.

Page 422: ? Применение VBA и макросов в Microsoft® Excel

422 Часть II Автоматизация Excel

Рис. 14.13. Базы данных, подобные этой, поддерживаются огромным числом всевозможныхкомпаний

Добавим к рабочей книге Excel, содержащей сведения из базы данных, два

рабочих листа. Первый рабочий лист (назовем его Top) будет содержать код,

отображающий логотип компании и навигационные панели. Второй рабочий

лист (назовем его Bottom) будет содержать код, завершающий HTMLYфайл

(рис. 14.14).

Конечным результатом выполнения макроса

WriteMembershipHTML является HTMLYфайл sam-pledirectory.html. Первым делом макрос копируY

ет в этот файл HTMLYкод, размещенный на рабочем

листе Top.

На следующем этапе макрос WriteMember-shipHTML экспортирует сведения из базы данных в

файл sampledirectory.html.

Наконец, макрос WriteMembershipHTML копируY

ет в файл sampledirectory.html HTMLYкод, разY

мещенный на рабочем листе Bottom.

Sub WriteMembershipHTML()' Этот макрос создает Web-страницу. Dim WST As Worksheet Dim WSB As Worksheet Dim WSM As Worksheet Set WSB = Worksheets("Bottom") Set WST = Worksheets("Top") Set WSM = Worksheets("База данных")

' Определение пути к текущей рабочей книге. MyPath = ThisWorkbook.Path

LineCtr = 0

Рис. 14.14. Рабочий листBottom содержит деск&рипторы, необходимыедля завершения HTML&файла

Page 423: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 423

FinalT = WST.Cells(65536, 1).End(xlUp).Row FinalB = WSB.Cells(65536, 1).End(xlUp).Row FinalM = WSM.Cells(65536, 1).End(xlUp).Row

MyFile = "sampledirectory.html"

ThisFile = MyPath & Application.PathSeparator & MyFile ThisHostFile = MyFile

' Удалить существующую Web-страницу. On Error Resume Next Kill (ThisFile) On Error GoTo 0

' Создать заголовок Web-страницы. ThisTitle = "<Title>Список членов организации ""Lake _Township Chamber of Commerce""</Title>" WST.Cells(3, 2).Value = ThisTitle

' Открыть файл для записи. Open ThisFile For Output As #1

' Скопировать HTML-код с рабочего листа "Top". For j = 2 To FinalT Print #1, WST.Cells(j, 2).Value Next j

' Экспортировать сведения из базы данных в HTML-файл. For j = 2 To FinalM' Название компании, выделенное полужирным шрифтом. Print #1, "<b>" & WSM.Cells(j, 1).Value & "</b><br>"' Адрес компании. Print #1, WSM.Cells(j, 2).Value & "<br>"' Город, штат и Zip-код. Addr = WSM.Cells(j, 3) & " " & WSM.Cells(j, 4) & " " _& WSM.Cells(j, 5) Print #1, Addr & "<br>"' Номер телефона и 2 символа разрыва строки. Print #1, WSM.Cells(j, 6).Value & "<br><br>" Next j

' 20 символов разрыва страницы. For j = LineCtr To 20 Print #1, "<br>" Next j

' Дата последнего изменения Web-страницы. Print #1, "<br>" Print #1, "Последнее изменение " & Format(Date, "mmmm dd, _yyyy") & " " & Format(Time, "h:mm AM/PM")

' Скопировать HTML-код с рабочего листа "Bottom". For j = 2 To FinalB Print #1, WSB.Cells(j, 2).Value Next j' Закрыть файл. Close #1

Page 424: ? Применение VBA и макросов в Microsoft® Excel

424 Часть II Автоматизация Excel

Application.StatusBar = False Application.CutCopyMode = False MsgBox "Web-страница успешно создана"

End Sub

Результат выполнения макроса WriteMembershipHTML показан на

рис. 14.15.

Рис. 14.15. Web&страница, созданная с помощью макроса WriteMembershipHTML

Подобная система управления содержимым имеет много преимуществ.

Сотруднику, поддерживающему базу данных, достаточно щелкнуть на кнопке,

чтобы обновить содержимое WebYстраницы.

С другой стороны, WebYдизайнеру, решившему изменить внешний вид

шаблона WebYстраницы, достаточно скопировать обновленный HTMLYкод на

рабочие листы Top и Bottom.

Также следует отметить, что размер WebYстраницы, созданной с помощью

макроса WriteMembershipHTML, в несколько раз меньше размера WebY

страницы, сгенерированной с помощью встроенного средства сохранения

файлов Excel.

Рассмотренная система управления содержимым может быть с успехом

взята за основу более сложной системы, создающей не одну, а несколько деY

сятков различных WebYстраниц.

Page 425: ? Применение VBA и макросов в Microsoft® Excel

Взаимодействие с Internet Глава 14 425

Загрузка WebLстраницы на FTPLсервер

После создания WebYстраницы ее нужно загрузить с жесткого диска комY

пьютера на FTPYсервер. К сожалению, далеко не все пользователи Excel могут

справиться с этой задачей.

Воспользуемся бесплатным FTPYклиентом WCL_FTP, созданным Кеном

Андерсоном (Ken Anderson), по адресу: http://www.pacific.net/~ken/software/. Разместите файл WCL_FTP.exe в корневой папке жесткого дисY

ка C: и примените следующий код для загрузки созданной ранее WebY

страницы на ваш FTPYсервер.

Sub DoFTP(fname, pathfname)' Скопируйте файл wcl_ftp.exe в корневую папку диска C:.' FTP-клиент WCL_FTP находится по адресу:http://www.pacific.net/~ken/software/.

' Создать командную строку со следующим синтаксисом:' WCL_FTP.exe "Заголовок окна" АдресСервераFTP ИмяПользователя' Пароль КаталогНаСервереFTP ИмяФайлаНаСервереFTP ЛокальноеИмяФайла' Операция (get или put) РежимПередачи (0 - Ascii, 1 - двоичный)' Журнал (0 - нет, 1 - да) ФоновыйРежим (0 - нет, 1 - да)' ЗакрытьПоОкончанииРаботы (0 - нет, 1 - да)' ПассивныйРежим (0 - нет, 1 - да) ЖурналОшибок (0 - нет, 1 - да)

s = """c:\wcl_ftp.exe"" " _ & """Загрузка файла на FTP-сервер"" " _ & "ftp.АдресСервераFTP.com ИмяПользователя Пароль _КаталогНаСервереFTP " _ & fname & " " _ & """" & pathfname & """ " _ & "put " _ & "0 0 0 1 1 1"

Shell s, vbMinimizedNoFocusEnd Sub

Следующий шагСледующая глава посвящена передаче данных между приложениями с поY

мощью XML. Использование XML намного эффективнее WebYзапросов. НеY

которые сайты (например, Amazon.com) предлагают такую услугу уже сегодня.

Page 426: ? Применение VBA и макросов в Microsoft® Excel
Page 427: ? Применение VBA и макросов в Microsoft® Excel

Введение в XML ............................427Правила XML ................................ 428Универсальный форматфайлов........................................... 429XML набирает обороты ............. 429Схемы и сопоставления XML.... 429Сохранение и считываниесодержимого рабочей книгиExcel в формате XML....................431Следующий шаг........................... 438

15Глава 15

ÏîääåðæêàXML âïðîôåññèîíàëü-íîì âûïóñêåExcel 2003

Одним из наиболее существенных

нововведений профессионального выY

пуска Office 2003 является улучшенная

поддержка работы с данными в формаY

те XML. Для тех, кто еще не сталкиY

вался с XML в своей повседневной

работе, в конце главы имеется пракY

тикум, демонстрирующий получение

данных в формате XML с WebYсайта

Amazon.com.

Введение в XML Исходный код WebYстраницы

‘‘усыпан’’ так называемыми HTMLY

тегами. Например, в самом начале

страницы обычно присутствует тег,

определяющий ее заголовок:

<TITLE>Заголовок Web-страницы</TITLE>

Типичная WebYстраница содерY

жит также теги, определяющие абзаY

цы, таблицы, строки в таблицах и т.п.

Синтаксис тегов описан в специфиY

кации HTML.

XML имеет много общего с HTML.

Одно из ключевых отличий XML от

HTML состоит в том, что XML позвоY

ляет определять любой тег. Ниже приY

Page 428: ? Применение VBA и макросов в Microsoft® Excel

428 Часть II Автоматизация Excel

веден код XML, содержащий информацию о заключенных за день сделках (для

создания подобного кода можно воспользоваться приложением Блокнот(Notepad)):

<TodaysOrders> <SalesOrder> <Customer>BCA Co</Customer> <Address>123 North</Address> <City>Stow</City> <State>OH</State> <Zip>44224</Zip> <ItemSKU>23456</ItemSKU> <Quantity>500</Quantity> <UnitPrice>21.75</UnitPrice> </SalesOrder> <SalesOrder> <Customer>DEF Co</Customer> <Address>234 Carapace Lane</Address> <City>South Bend</City> <State>IN</State> <Zip>44685</Zip> <ItemSKU>34567</ItemSKU> <Quantity>20</Quantity> <UnitPrice>50.00</UnitPrice> </SalesOrder></TodaysOrders>

Правила XML Ниже приведено несколько простых правил, подчеркивающих отличия

между XML и HTML.

Каждый элемент данных должен быть заключен в идентичные теги.

Поскольку теги XML чувствительны к регистру, запись

<TagName>Data</Tagname> некорректна. Примером правильной заY

писи является запись <TagName>Data</TagName>.

XMLYфайл должен начинаться и заканчиваться так называемым корY

невым тегом. В каждом XMLYфайле может существовать только один

корневой тег. В рассмотренном выше примере таким тегом является тег

<TodaysOrders>.

XML допускает наличие пустых тегов, отличающихся символом косой

черты после названия тега. Например, чтобы указать на отсутствие в

данной записи информации о ZipYкоде, используйте тег <Zip/>.

При вложении внутренние теги должны закрываться раньше, чем внешY

ние теги. Например, в HTML допускается такая запись: <b>XML - этоочень <i>круто</b></i>. В XML подобная запись была бы некорY

ректной. Примером корректного закрытия тегов в XML является запись

<Item><a>data</a></Item>.

Page 429: ? Применение VBA и макросов в Microsoft® Excel

Поддержка XML в профессиональном выпуске Excel 2003 Глава 15 429

Универсальный формат файловНа протяжении многих лет универсальным форматом файлов считался

формат CSV. Практически все приложения для работы с электронными табY

лицами обладали возможностью сохранения и считывания данных в виде знаY

чений с разделителямиYзапятыми. На сегодняшний момент наиболее вероятY

ным претендентом на звание универсального является формат файлов XML.

При обмене данными в формате CSV обе стороны должны иметь одинакоY

вое представление об их структуре. В рассмотренном выше примере поле ZipY

кода имеет порядковый номер 5, а поле кода SKU — порядковый номер 6. НаY

рушение очередности следования этих полей может привести к нежелательY

ным последствиям. На рис. 15.1 показан результат открытия в Excel типичного

CSVYфайла.

Рис. 15.1. Формат CSV не содержит никакой информации о структуреданных

XML набирает оборотыФормат XML предлагает гораздо более широкие возможности. На рис. 15.2

показан результат открытия в Excel XMLYфайла, содержащего сведения о

сделках, заключенных в продолжение рабочего дня.

На основе информации, хранящейся в XMLYфайле, Excel отображает загоY

ловки столбцов и даже может вывести так называемую схему данных. Схема

хранится в отдельном файле и описывает столбцы данных и существующие

между ними отношения.

Excel поддерживает сохранение данных в формате XML. Добавьте новые

записи в XMLYсписок и выберите команду меню Файл Сохранить как (File

Save As). Из раскрывающегося списка Тип файла (Save as type) выберите знаY

чение XML-данные (XML Data) и щелкните на кнопке Сохранить (Save), как

показано на рис. 15.3.

Схемы и сопоставления XMLВ предыдущем разделе было рассмотрено считывание, редактирование и

сохранение XMLYданных с помощью Excel.

Существует два дополнительных типа файлов, предназначенных для рабоY

ты с XMLYданными YYYY файл схемы и файл сопоставления.

В то время как XMLYфайл содержит данные и имена полей, схема XML опY

ределяет взаимоотношения между полями и правила проверки корректности

данных (например, значение, представляющее ZipYкод, должно состоять из

пяти цифр). Схема XML хранится в файле с расширением .XSD.

Page 430: ? Применение VBA и макросов в Microsoft® Excel

430 Часть II Автоматизация Excel

Рис. 15.2. Формат XML содержит сведения о структуре данных, корректно интерпретируемые Excel

Рис. 15.3. Excel поддерживает два способа сохранения XML&данных: в виде элек&тронной таблицы XML и в виде обычного XML&файла

Сопоставление описывает способ отображения XMLYданных на документ

Excel. В файле сопоставления можно определить поля XMLYфайла, которые

Page 431: ? Применение VBA и макросов в Microsoft® Excel

Поддержка XML в профессиональном выпуске Excel 2003 Глава 15 431

будут отображены на рабочем листе. Схеме XML могут соответствовать неY

сколько сопоставлений, каждое из которых будет определять некоторое предY

ставление одних и тех же данных. Сопоставление XML хранится в файле с

расширением .XLS.

XSDY и XLSYфайлы обычно поставляются вместе с XMLYданными. При неY

обходимости, Excel может вывести схему XML на основе существующего XMLY

файла. Откройте созданный ранее файл TodaysOrders.xml и введите в окне

Immediate (Быстрое выполнение) редактора Visual Basic следующую строку:

Print ActiveWorkbook.XmlMaps(1).Schemas(1).XML

Скопируйте полученный результат в Блокнот (Notepad) и сохраните его в

файле с именем TodaysOrders.xsd. Сгенерированная схема XML с добавY

ленными для повышения удобочитаемости переносами строк и отступами поY

казана на рис. 15.4.

Рис. 15.4. Схема XML, выведенная на основе содержимого файла TodaysOr-ders.xml

В отличие от схемы, Excel не поддерживает автоматического генерироY

вания сопоставления XML. Более подробную информацию о создании

XSLYфайлов вы сможете найти по адресу: http://www.mrexcel.com/tip064.shtml.

Сохранение и считывание содержимого рабочейкниги Excel в формате XML

Microsoft рассматривает формат XML как стандартный формат файлов доY

кументов Office. Это означает, что, теоретически, любая программа, способY

ная сохранять данные в формате XML, может быть использована для создания

файла Excel.

Page 432: ? Применение VBA и макросов в Microsoft® Excel

432 Часть II Автоматизация Excel

На рис. 15.5 показан результат сохранения и последующего считывания соY

держимого файла Excel в формате XML.

Рис. 15.5. Формат XML можно применять в качестве стандартного формата файлов Excel 2003

На рис. 15.5 слева показан исходный файл Excel, содержащий стилевое

форматирование и диаграмму, а на рис. 15.5 справа YYYY результат открытия

XMLYфайла, созданного при сохранении исходного файла в виде электронной

таблицы XML. При сохранении файла рабочей книги в виде электронной табY

лицы XML Excel предупреждает о невозможности сохранения диаграмм и

проектов VBA. Во всем остальном полученный файл XML ничем не отличаетY

ся от исходного файла Excel.

Фрагмент XMLYкода, сгенерированного при сохранении файла Excel в виY

де электронной таблицы XML, представлен на рис. 15.6.

Page 433: ? Применение VBA и макросов в Microsoft® Excel

Поддержка XML в профессиональном выпуске Excel 2003 Глава 15 433

Рис. 15.6. Придерживаясь спецификаций Microsoft, любая программа, способная сохранятьданные в формате XML, может быть использована для создания файла Excel

Практикум

Извлечение XML-данных с сайта Amazon.comРассмотрим пример создания VBA&макроса, извлекающего XML&данные с сайтаAmazon.com.Прежде чем приступить к созданию макроса, загрузите с сайта Amazon.com наборинструментальных средств разработки, выполнив следующие действия.1. С помощью обозревателя Internet посетите страницу http://amazon.com/

webservices.

2. Щелкните на ссылке E-Commerce Service (Служба электронной коммерции),расположенной на левой навигационной панели.

3. В разделе Other Versions Available (Другие версии) щелкните на ссылке Here(Здесь) для загрузки файла kit.zip на свой компьютер.

4. Распакуйте файл kit.zip, чтобы извлечь его содержимое.

5. В наборе инструментальных средств разработки содержится описание двухсхем XSD: упрощенной и полной. Откройте файл READMEFIRST.txt и отыщитев нем ссылку на полную XSD&схему. На момент написания этой книги полнаяXSD&схема была доступна по адресу: http://xml.amazon.com/schemas3/dev-heavy.xsd.

Page 434: ? Применение VBA и макросов в Microsoft® Excel

434 Часть II Автоматизация Excel

6. Откройте ссылку в обозревателе Internet и сохраните XSD&схему на жесткомдиске компьютера.

Создайте новую рабочую книгу Excel и присоедините к ней XSD&схему, выполнивследующие действия.

1. Выберите в меню Excel команду Данные XML Источник XML(Data XML XML Source).

2. Щелкните на кнопке Карты XML (XML Maps), расположенной в области задачИсточник XML (XML Source).

3. В открывшемся диалоговом окне Карты XML (XML Maps) щелкните на кнопкеДобавить (Add).

4. Выберите сохраненный ранее файл dev-heavy.xsd и щелкните на кнопкеОткрыть (Open).

5. Выберите элемент ProductInfo в списке Выберите корень (Please select aroot) диалогового окна Несколько корней (Multiple Roots) и щелкните на кноп&ке OK.

6. Щелкните на кнопке OK, чтобы закрыть диалоговое окно Карты XML.

В области задач Источник XML появится список полей схемы ProductInfo. Пере&несите нужные поля на рабочий лист, как показано на рис. 15.7.

Рис. 15.7. Присоединив XSD&схему к рабочей книге, перетащите требуемые поля из областизадач Источник XML (XML Source) на рабочий лист Excel

Page 435: ? Применение VBA и макросов в Microsoft® Excel

Поддержка XML в профессиональном выпуске Excel 2003 Глава 15 435

Завершив подготовку рабочего листа, откройте редактор Visual Basic, чтобы соз&дать код, извлекающий XML&данные с сайта Amazon.com.Выберите в меню редактора Visual Basic команду Tools References (СервисСсылки) и установите флажок, соответствующий библиотеке Microsoft WinHTTPServices. Щелкните на кнопке OK, чтобы закрыть диалоговое окно References(Ссылки).Набор инструментальных средств разработки Amazon.com содержит примеры за&просов в виде строк URL по имени автора, издателю, коду ISBN и т.п.Следующий макрос формирует строку запроса URL и отправляет ее в виде HTTP&запроса серверу Amazon.com. Результат запроса копируется на рабочий лист спомощью метода ImportXML.Ниже приведен код макроса, запрашивающего у Amazon.com все книги БиллаДжелена (Bill Jelen), изданные в 2002 году.Sub QuerybyAuthor()' Запрос к Amazon.com возвращает все книги' Билла Джелена (Bill Jelen), изданные в 2002 году. Dim ws As Worksheet Dim whr As New WinHttpRequest Dim lobj As ListObject Dim nCount As Integer Dim objSelected As Object

Dim sURI As String

Set objSelected = Selection Set ws = Worksheets("Sheet1") Set lobj = ws.ListObjects(1)

Application.Cursor = xlWait

sURI = "http://xml.amazon.com/onca/xml2?t=webservices-20 _&dev-t=D3VCCO47XZEQFA" _ & "&PowerSearch=author:Bill Jelen and pubdate:2002" _ & "&mode=books&type=heavy&page=1&f=xml"

whr.Open "GET", sURI whr.Send

ActiveWorkbook.XmlMaps(1).ImportXml whr.ResponseText, _Overwrite:=True

Application.Cursor = xlDefault

End Sub

Результат запроса помещается в объект Список (List) на рабочем листе Excel. Осо&бенности структуры XML&данных, полученных с Amazon.com, обуславливают на&личие более чем одной строки для книг, написанных несколькими авторами (поодной на каждого автора). Подобный запрос может использоваться для отслежи&вания рейтинга книг и текущей стоимости их подержанных экземпляров(рис. 15.8).

Page 436: ? Применение VBA и макросов в Microsoft® Excel

436 Часть II Автоматизация Excel

Рис. 15.8. Метод ImportXML используется для копирования результатов запроса на рабочийлист. Обратите внимание, что на экране будут видны только те поля XML&данных, которые бы&ли сопоставлены с рабочим листом путем перетаскивания из области задач Источник XML

Извлечение нескольких страниц XML-данныхДля извлечения XML&данных, занимающих несколько страниц, необходимо вы&полнить соответствующее число запросов. Номер запрашиваемой страницы ука&зывается в строке URL с помощью параметра page (например, page=2). Чтобыуказать на необходимость добавления извлеченных XML&данных к существующе&му объекту Список (List), установите параметр Overwrite метода ImportXMLравным False. Следующий макрос запрашивает у Amazon.com две страницыXML&данных, сгенерированных в результате запроса книг, опубликованных из&дательством Sams в 2003 году.Sub QuerybyPublisher() Dim ws As Worksheet Dim whr As New WinHttpRequest Dim lobj As ListObject Dim nCount As Integer Dim objSelected As Object

Dim sURI As String

Set objSelected = Selection Set ws = Worksheets("Sheet1") Set lobj = ws.ListObjects(1)

Page 437: ? Применение VBA и макросов в Microsoft® Excel

Поддержка XML в профессиональном выпуске Excel 2003 Глава 15 437

Application.Cursor = xlWait

sURI = "http://xml.amazon.com/onca/xml2?t=webservices-20 _&dev-t=D3VCCO47XZEQFA" _ & "&PowerSearch=publisher:Sams and pubdate:2003" _ & "&mode=books&type=heavy&page=1&f=xml"

' Получить первые 20 строк XML-данных. whr.Open "GET", sURI whr.Send ActiveWorkbook.XmlMaps(1).ImportXml whr.ResponseText, _Overwrite:=True

' Получить следующие 20 строк XML-данных. sURI = "http://xml.amazon.com/onca/xml2?t=webservices-20 _&dev-t=D3VCCO47XZEQFA" _ & "&PowerSearch=publisher:Sams and pubdate:2003" _ & "&mode=books&type=heavy&page=2&f=xml"

whr.Open "GET", sURI whr.Send ActiveWorkbook.XmlMaps(1).ImportXml whr.ResponseText, _Overwrite:=False

Application.Cursor = xlDefault

End Sub

Результат выполнения макроса QuerybyPublisher показан на рис. 15.9.

Рис. 15.9. Если XML&данные занимают несколько страниц, для их извлечения потребуетсявыполнить соответствующее число запросов

Page 438: ? Применение VBA и макросов в Microsoft® Excel

438 Часть II Автоматизация Excel

Следует отметить, что за счет наличия огромного числа полей карта Product-Info_Map позволяет легко манипулировать отображаемыми результатами запросабез необходимости внесения изменений в код VBA. Например, чтобы получить све&дения о дате выхода книги (ReleaseDate), ее номере в каталоге Amazon.com(ListID) или средней оценке книги читателями (AvgCustomerRating), перета&щите на рабочий лист соответствующие поля из области задач Источник XML(XML Source).

Следующий шагОсновная задача XML заключается в обеспечении возможности обмена

данными между разнородными приложениями. Программы, входящие в соY

став пакета Microsoft Office, обладают встроенной возможностью обмена данY

ными между собой. Следующая глава посвящена автоматизации управления

текстовым редактором Microsoft Word средствами Excel VBA.

Page 439: ? Применение VBA и макросов в Microsoft® Excel

Раннее связывание..................... 439Позднее связывание................... 442Работа с объектами .................... 443Объекты Word.............................. 445Следующий шаг........................... 460

16Глава 16

ÀâòîìàòèçàöèÿWord

Word, Excel, PowerPoint, Outlook и

Access используют один и тот же язык

программирования VBA, отличаясь

между собой только объектной модеY

лью (например, рабочая книга Excel

представлена объектом Workbook, а

документ Word — объектом Docu-ment). Каждое из перечисленных

приложений может получить доступ

к объектной модели другого прилоY

жения при условии, что последнее

установлено на компьютере.

Для доступа к объектной библиоY

теке Word из кода Excel VBA на нее

необходимо установить ссылку поY

средством раннего или позднего связы*вания. Ранее связывание подразумеY

вает создание ссылки на объект приY

ложения во время компиляции

программы, а позднее связывание YYYY

во время ее выполнения.

В этой главе рассматривается досY

туп к объектной модели Word средстY

вами Excel VBA. Чтобы познакомитьY

ся со структурой объектной модели

Word или другого приложения, вхоY

дящего в состав пакета Microsoft OfY

fice, воспользуйтесь диспетчером

объектов редактора Visual Basic соотY

ветствующего приложения.

Раннее связываниеКод, созданный с применением

раннего связывания, выполняется

быстрее, чем код, созданный с приY

менением позднего связывания.

Page 440: ? Применение VBA и макросов в Microsoft® Excel

440 Часть II Автоматизация Excel

Раннее связывание предполагает создание ссылки на объектную библиотеку

Word на этапе разработки программного кода. Это делает объекты, свойства и

методы Word доступными в диспетчере объектов Visual Basic, что, в частности,

позволяет отображать динамические подсказки, как показано на рис. 16.1.

Рис. 16.1. Раннее связывание позволяет существенно упроститьзнакомство с синтаксисом объектной модели Word

Недостатком раннего связывания является требование обязательного приY

сутствия в системе объектной библиотеки, на которую создается ссылка.

Именно поэтому макрос, использующий объектную модель Word 2003 и ранY

нее связывание, не удастся выполнить на компьютере с Word 2002.

Чтобы добавить ссылку на объектную библиотеку Word с помощью редакY

тора Visual Basic, выполните следующие действия.

1. Выберите в меню редактора Visual Basic команду Tools References(Сервис Ссылки).

2. В списке Available References (Доступные ссылки) установите флажок

рядом со ссылкой на библиотеку Microsoft Word 11.0 Object Library

(рис. 16.2).

3. Щелкните на кнопке OK.

На заметку Отсутствие объектной библиотеки Word в списке Available References означает,что приложение не установлено на компьютере. Если в списке доступных ссылоксодержится объектная библиотека другой версии Word (например, 10.0), значитна компьютере установлена другая версия этого текстового редактора.

Добавив ссылку на библиотеку, можно начинать объявлять переменные,

используя типы из объектной модели Word. Если в качестве типа переменной

указать тип Object, это приведет к использованию позднего связывания.

Page 441: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 441

Рис. 16.2. Выберите требуемую объектную библиотеку всписке Available References

Совет В поисках ссылки на тип объекта Excel последовательно просматривает все под&ключенные библиотеки. Если нужная ссылка содержится более чем в одной биб&лиотеке, Excel выберет ссылку, встретившуюся первой. Повлиять на выбор той илииной библиотеки можно путем изменения ее приоритета в списке AvailableReferences.

Sub WordEarlyBinding()' Раннее связывание.

Dim wdApp As Word.Application Dim wdDoc As Document

Set wdApp = New Word.Application Set wdDoc = wdApp.Documents.Open(ThisWorkbook.Path & _"\Автоматизация Word.doc") wdApp.Visible = True Set wdApp = Nothing Set wdDoc = NothingEnd Sub

Макрос WordEarlyBinding открывает существующий документ Word. ПеY

ременная wdApp используется для обращения к объекту Word.Application(аналог объекту Application в Excel VBA), а переменная wdDoc — для обY

ращения к объекту Document. Для создания нового экземпляра Word испольY

зуется выражение New Word.Application.

После создания экземпляра Word освободите память, занимаемую переY

менными wdApp и wdDoc, присвоив каждой из них значение Nothing.

Page 442: ? Применение VBA и макросов в Microsoft® Excel

442 Часть II Автоматизация Excel

Совет Созданный экземпляр Word не отображается на экране, если в момент выполне&ния макроса в системе отсутствует другая активная копия Word. Чтобы вывестиокно Word на экран, присвойте свойству Visible объекта Word.Applicationзначение True.

Ошибка компиляции: отсутствие библиотеки

Если объектная библиотека Word, на которую была создана ссылка, отсутY

ствует в системе, Excel не сможет откомпилировать макрос и отобразит сообY

щение об ошибке. В списке Available References (Доступные ссылки) отсутY

ствующая библиотека будет отмечена словом ‘‘MISSING’’ (‘‘Отсутствует’’),

как показано на рис. 16.3.

Рис. 16.3. Excel не сможет откомпилировать макрос, еслитребуемая объектная библиотека отсутствует в системе

Если в системе присутствует другая версия объектной библиотеки Word,

можно попытаться откомпилировать макрос, создав ссылку на эту библиотеY

ку. Различные версии библиотек Word содержат много одинаковых объектов.

Позднее связываниеПозднее связывание предполагает создание объектов Word до установки

ссылки на соответствующую объектную библиотеку. Это позволяет использоY

вать любую версию библиотеки Word, содержащую требуемые объекты, метоY

ды и свойства. К тому же, версию библиотеки Word можно определить в коде

макроса и создавать экземпляры только содержащихся в ней объектов.

Недостаток позднего связывания заключается в полной неосведомленноY

сти Excel об обращении к объектной модели Word. Помимо невозможности

Page 443: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 443

отображения динамических подсказок, Excel не позволяет использовать

встроенные константы Word и не может проверить корректность создаваемых

ссылок. В результате этого все ошибки, связанные с использованием библиоY

теки Word, обнаруживаются во время выполнения программного кода.

Следующий макрос открывает существующий документ Word и выводит

его на экран.

Sub WordLateBinding()' Позднее связывание.

Dim wdApp As Object, wdDoc As Object Set wdApp = CreateObject("Word.Application") Set wdDoc = wdApp.Documents.Open(ThisWorkbook.Path & _"\Автоматизация Word.doc") wdApp.Visible = True Set wdApp = Nothing Set wdDoc = NothingEnd Sub

Переменная wdApp содержит ссылку на объект приложения (CreateObject("Word.Application")) и используется при создании переменной wdDoc,

ссылающейся на объект библиотеки Word.

На заметку Необходимость использования позднего связывания обусловлена выбором типапеременных wdApp и wdDoc (Object). Макрос не может создать требуемые ссыл&ки на объекты библиотеки Word до выполнения функции CreateObject.

Работа с объектамиВ следующих разделах рассматривается создание новых объектов, а также

обращение к уже существующим объектам.

Ключевое слово New

Ключевое слово New можно использовать для создания объекта приложеY

ния при раннем связывании (см. макрос WordEarlyBinding выше в этой

главе). Аналогичного результата позволяет добиться также функция Cre-ateObject, а вот функция GetObject предназначена для получения ссылки

на уже существующий объект. Использовать ключевое слово New при позднем

связывании нельзя.

Внимание Если окно созданного экземпляра Word не отображается на экране, откройте при&ложение Диспетчер задач Windows (Windows Task Manager) и проверьте наличиев памяти компьютера процесса WINWORD.EXE. Если процесс запущен, выполнитеследующую строку кода с помощью окна Immediate (Быстрое выполнение) ре&дактора Visual Basic: Word.Application.Visible = True

Page 444: ? Применение VBA и макросов в Microsoft® Excel

444 Часть II Автоматизация Excel

При наличии в памяти компьютера нескольких экземпляров процесса WIN-WORD.EXE выполняйте приведенную выше строку до тех пор, пока не доберетесьдо нужной копии Word, попутно закрывая окна “лишних” экземпляров.

Функция CreateObject

Функцию CreateObject можно использовать для создания нового экY

земпляра объекта как при позднем (см. макрос WordLateBinding выше в

этой главе), так и при раннем связывании. В качестве обязательного параметY

ра функции CreateObject необходимо передать имя приложения и тип созY

даваемого объекта (например, Word.Application).

Функция GetObject

Функция GetObject возвращает ссылку на уже существующий экземпляр

объекта. Если обнаружить указанный экземпляр объекта не удалось, генериY

руется сообщение об ошибке.

Первый параметр функции GetObject определяет полный путь к файлу,

содержащему требуемый объект. Второй параметр функции GetObject задаY

ет класс объекта. Несмотря на то что по отдельности каждый из параметров

является необязательным, пропуск первого из них автоматически означает

необходимость указания второго.

Sub UseGetObject() Dim wdDoc As Object Set wdDoc = GetObject(ThisWorkbook.Path & _"\Автоматизация Word.doc") wdDoc.Application.Visible = True Set wdDoc = NothingEnd Sub

Макрос UseGetObject открывает документ внутри существующего экземпY

ляра приложения Word и выводит окно последнего на экран. Поскольку переменY

ная wdDoc ссылается на объект документа, для вывода окна Word на экран исY

пользуется свойство Application объекта Document (wdDoc.Applicati-on.Visible = True).

На заметку Несмотря на установку значения свойства Visible объекта Application рав&ным True, макрос UseGetObject не делает приложение Word активным.

Следующий код пытается вставить диаграмму Excel в конец открытого доY

кумента Word, предварительно отключив обработку ошибок. Если на момент

выполнения кода ни один документ Word не был открыт, создается новый доY

кумент.

Sub IsWordOpen() Dim wdApp As Object ActiveChart.ChartArea.Copy

Page 445: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 445

On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 With wdApp.Selection .EndKey Unit:=wdStory .TypeParagraph .PasteSpecial link:=False, DataType:=wdPasteOLEObject, _ Placement:=wdInLine, DisplayAsIcon:=False End With Set wdApp = NothingEnd Sub

Обработка ошибок отключается с помощью строки On Error ResumeNext. Ошибка возникает при попытке связать переменную wdApp с несущеY

ствующим объектом. В этом случае переменная wdApp не будет иметь значеY

ния, чем можно воспользоваться (If wdApp Is Nothing Then) для открыY

тия нового экземпляра Word, создания пустого документа и отображения окна

Word на экране. Чтобы открыть новый экземпляр Word, значение первого паY

раметра функции GetObject задается как "". Возвратиться к обычному реY

жиму обработки ошибок позволяет строка On Error GoTo 0.

Объекты WordПолучить первичное представление об объектной модели Word поможет

средство записи макросов Word. Помня обо всех недостатках средства записи

макросов Excel, рассматривавшегося в начале этой книги, обращайте внимаY

ние только на использованные в сгенерированном коде объекты, методы и

свойства.

Внимание Средство записи макросов Word накладывает некоторые ограничения на действияпользователя. В частности, перемещать курсор и выделять объекты разрешаетсятолько с помощью клавиатуры. Использование мыши для выполнения указанныхопераций не предусмотрено.

Ниже приведен код, сгенерированный средством записи макросов Word

при добавлении нового документа:

Documents.Add Template:="Normal", NewTemplate:=False, _DocumentType:=0

Page 446: ? Применение VBA и макросов в Microsoft® Excel

446 Часть II Автоматизация Excel

На самом деле, добавить новый документ Word можно с помощью гораздо

более простого и эффективного кода:

Documents.Add

Свойства Template, NewTemplate и DocumentType необязательны и

обычно используются для гарантированного задания значений параметров.

Чтобы выполнить приведенный выше код в Excel, необходимо создать

ссылку на объектную библиотеку Word. В следующих разделах рассматриваY

ются основные объекты Word. Для более подробного изучения объектной моY

дели Word обратитесь к диспетчеру объектов редактора Visual Basic.

Объект Document

Объект Word Document является эквивалентом объекта Excel Workbook.

Документ Word состоит из символов (свойство Characters объекта Docu-ment), слов (свойство Words объекта Document), предложений (свойство

Sentences объекта Document), абзацев (свойство Paragraphs объекта

Document), разделов (свойство Sections объекта Document), а также верхY

них (свойство Headers объекта Section) и нижних колонтитулов (свойство

Footers объекта Section). Свойства и методы объекта Document позволяY

ют создавать новые документы Word, закрывать существующие документы,

осуществлять печать, редактирование и многое другое.

Создание документа Word

Чтобы создать новый документ внутри существующего экземпляра Word,

воспользуйтесь методом Add (для создания нового документа с открытием экY

земпляра Word примените функцию CreateObject или GetObject, о чем

уже говорилось ранее в этой главе).

Sub NewDocument() Dim wdApp As Word.Application On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 Set wdApp = NothingEnd Sub

Макрос NewDocument создает новый документ Word на основе стандартY

ного шаблона. Ниже приведен пример создания нового документа Word на

основе шаблона Современная записка (Contemporary Memo).

wdApp.Documents.Add Template:="Современная записка.dot"

Page 447: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 447

В качестве значения параметра Template следует указать либо полный

путь к файлу шаблона, либо имя файла одного из шаблонов, поставляющихся

вместе с Word.

Открытие и сохранение документа Word

Чтобы открыть существующий документ Word, воспользуйтесь методом

Open. Этот метод имеет несколько параметров, таких как ReadOnly и

AddtoRecentFiles. В результате выполнения следующего кода документ

Автоматизация Word.doc будет открыт в режиме только для чтения и не

будет добавлен в список ранее открывавшихся файлов:

wdApp.Documents.Open Filename:="C:\Автоматизация Word.doc", _ReadOnly:=True, AddtoRecentFiles:=False

Чтобы сохранить документ под его текущим именем, воспользуйтесь метоY

дом Save:

wdApp.Documents.Save

Чтобы сохранить документ под новым именем (в том числе новый докуY

мент), воспользуйтесь методом SaveAs:

wdApp.ActiveDocument.SaveAs "C:\Служебная записка.doc "

На заметку Метод SaveAs предполагает использование объекта ActiveDocument.

Закрытие документа Word

Чтобы закрыть определенный документ Word или все открытые докуменY

ты, воспользуйтесь методом Close. По умолчанию при попытке закрытия

документа с несохраненными изменениями выводится окно сообщения.

Чтобы закрыть все открытые документы без сохранения изменений, устаноY

вите значение параметра SaveChanges метода Close равным wdDoNot-SaveChanges:

wdApp.Documents.Close SaveChanges:=wdDoNotSaveChanges

Ниже приведен пример закрытия текущего документа:

wdApp.ActiveDocument.Close

и документа с указанным именем:

wdApp.Documents("Автоматизация Word.doc").Close

Печать документа Word

Чтобы отправить на печать документ Word или его часть, воспользуйтесь

методом PrintOut. Ниже приведен пример печати текущего документа со

стандартными параметрами печати:

wdApp.ActiveDocument.PrintOut

Page 448: ? Применение VBA и макросов в Microsoft® Excel

448 Часть II Автоматизация Excel

По умолчанию на печать выводится весь документ целиком. Чтобы напечаY

тать только определенный диапазон страниц, воспользуйтесь параметрами

Range и Pages метода PrintOut:

wdApp.ActiveDocument.PrintOut Range:=wdPrintRangeOfPages, Pages:="2"

Объект Selection

Объект Selection используется для представления выделенной области в

документе Word (слова, предложения, места вставки и т.п.). Тип выделенной

области хранится в свойстве Type объекта Selection (wdSelectionIP,

wdSelectionColumn, wdSelectionShape и т.п.).

Методы HomeKey и EndKey

Методы HomeKey и EndKey используются для изменения выделенной обY

ласти и эквивалентны нажатию клавиш <Home> и <End>, соответственно.

Каждый метод принимает 2 параметра: Unit и Extend. Параметр Unit опреY

деляет диапазон смещения или расширения выделенной области: начало

(метод HomeKey) или конец (метод EndKey) строки текста (wdLine), докуY

мента (wdStory), столбца таблицы (wdColumn) или строки таблицы (wdRow).

Параметр Extend определяет тип действия: смещение выделенной области

(wdMove) или ее расширение (wdExtend).

Следующий код перемещает курсор в начало документа:

wdApp.Selection.HomeKey Unit:=wdStory, Extend:=wdMove

В результате выполнения приведенной ниже строки кода будет выделен

фрагмент от текущего места вставки до конца документа:

wdApp.Selection.EndKey Unit:=wdStory, Extend:=wdExtend

Метод TypeText

Метод TypeText используется для вставки текста в документ Word. СпоY

соб вставки текста определяется значением различных параметров приложеY

ния, таких как параметр Overtype.

Sub InsertText() Dim wdApp As Word.Application Dim wdDoc As Document Dim wdSln As Selection On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0

Page 449: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 449

Set wdDoc = wdApp.ActiveDocument Set wdSln = wdApp.Selection wdDoc.Application.Options.Overtype = False With wdSln If .Type = wdSelectionIP Then .TypeText ("Вставка текста в месте текущего _положения курсора.") ElseIf .Type = wdSelectionNormal Then If wdApp.Options.ReplaceSelection Then .Collapse Direction:=wdCollapseStart End If .TypeText ("Вставка текста перед выделенным блоком.") End If .TypeText vbCrLf End With Set wdApp = Nothing Set wdDoc = NothingEnd Sub

Объект Range

Объект Range используется для представления непрерывной области

(диапазона) в документе Word. Диапазон определяется позицией первого и

последнего входящего в него символа. Примером диапазона является место

вставки, фрагмент текста, а также весь документ Word вместе с непечатаемыY

ми символами, такими как символ пробела и символ абзаца.

Несмотря на кажущуюся схожесть, объект Range выгодно отличается от

объекта Selection. В частности, использование объекта Range позволяет

создавать более эффективный код за счет упрощенного способа обращения к

требуемым элементам документа Word.

Определение диапазона

Чтобы определить диапазон, укажите позицию первого и последнего вхоY

дящего в него символа:

Sub RangeText() Dim wdApp As Word.Application Dim wdDoc As Document Dim wdRng As Word.Range On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 InsertText Set wdDoc = wdApp.ActiveDocument

Page 450: ? Применение VBA и макросов в Microsoft® Excel

450 Часть II Автоматизация Excel

Set wdRng = wdDoc.Range(0, 22) wdRng.Select Set wdApp = Nothing Set wdDoc = Nothing Set wdRng = NothingEnd Sub

Результат выполнения макроса RangeText показан на рис. 16.4.

Рис. 16.4. Пример выделения фрагмента текста с помо&щью объекта Range

Диапазон, представленный объектом Range, включает 22 символа, в том

числе символы абзаца.

На заметку Выделение диапазона wdRng в макросе RangeText было предпринято для повы&шения наглядности рассматриваемого примера. Работать с диапазоном можно ибез его предварительного выделения.

Позиция первого символа в документе Word всегда равна нулю. Позиция

последнего символа в документе Word равна общему числу символов в доY

кументе.

Объект Range можно использовать для выделения абзацев. Следующий

макрос выделяет третий абзац документа Word, копирует его и помещает на

рабочий лист Excel как объект Word (рис. 16.5) и как обычный текст

(рис. 16.6).

Sub SelectSentence() Dim wdApp As Word.Application Dim wdRng As Word.Range On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 InsertText InsertText InsertText With wdApp.ActiveDocument If .Paragraphs.count >= 3 Then Set wdRng = .Paragraphs(3).Range

Page 451: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 451

wdRng.Copy End If End With' Вставить скопированный абзац как объект Word. Worksheets("Объекты Word").Select Range("B22").Select ActiveSheet.PasteSpecial' Вставить скопированный абзац в ячейку B24 как обычный текст.' Обратите внимание, что перед вставкой абзаца нужно выделить' соответствующий диапазон рабочего листа Excel. Range("B24").Select ActiveSheet.Paste Set wdApp = Nothing Set wdRng = NothingEnd Sub

Рис. 16.5. Скопированный абзац помещается на рабочий лист Excel как объект Word

Рис. 16.6. Скопированный абзац помещается на ра&бочий лист Excel как обычный текст

Стилевое форматирование диапазона

Следующий макрос добавляет полужирное начертание к первому слову

всех абзацев документа Word.

Sub ChangeFormat() Dim wdApp As Word.Application Dim wdRng As Word.Range Dim count As Integer On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 InsertText InsertText InsertText With wdApp.ActiveDocument For count = 1 To .Paragraphs.count Set wdRng = .Paragraphs(count).Range With wdRng .Words(1).Font.Bold = True .Collapse

Page 452: ? Применение VBA и макросов в Microsoft® Excel

452 Часть II Автоматизация Excel

End With Next count End With Set wdApp = NothingEnd Sub

Результат выполнения макроса ChangeFormat показан на рис. 16.7.

Рис. 16.7. Макрос ChangeFormat добавляет полужир&ное начертание к первому слову всех абзацев доку&мента Word

Один из наиболее быстрых способов изменения форматирования абзаца

заключается в применении к нему другого стиля. Следующий макрос изменяY

ет стиль абзацев документа Word с Обычный на Заголовок 1.

Sub ChangeStyle() Dim wdApp As Word.Application Dim wdRng As Word.Range Dim count As Integer On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 InsertText InsertText InsertText With wdApp.ActiveDocument For count = 1 To .Paragraphs.count Set wdRng = .Paragraphs(count).Range With wdRng If .Style = "Обычный" Then .Style = "Заголовок 1" .Collapse End If End With Next count End With

Page 453: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 453

Set wdApp = Nothing Set wdRng = NothingEnd Sub

Результат выполнения макроса ChangeStyle показан на рис. 16.8.

Рис. 16.8. Макрос ChangeStyle изменяет стиль абзацев документа сОбычный на Заголовок 1

Закладки

Закладки предназначены для упрощения навигации по документу Word.

Объект Bookmarks доступен в виде свойства объектов Document, Selec-tion и Range.

На заметку Закладки можно создать непосредственно в программном коде.

Закладка, назначенная некоторой позиции в документе Word, имеет

IYобразный вид. Чтобы отобразить закладки, выберите в меню Word команду

Сервис Параметры (Tools Options) и установите флажок Закладки(Bookmarks), расположенный во вкладке Вид (View) (рис. 16.9).

Следующий макрос создает закладки Кому, Копия, От и Тема, а затем поY

мещает после каждой из них соответствующий текст.

Page 454: ? Применение VBA и макросов в Microsoft® Excel

454 Часть II Автоматизация Excel

Рис. 16.9. Чтобы отобразить закладки, установите флажокЗакладки

Sub UseBookmarks() Dim myArray() Dim wdBkmk As String Dim wdApp As Word.Application Dim wdRng As Word.Range Dim wdSln As Selection

myArray = Array("Кому", "Копия", "От", "Тема")

On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp .Documents.Add .Visible = True End With End If On Error GoTo 0 Set wdSln = wdApp.Selection With wdSln .TypeText "Кому: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Кому", wdRng .TypeText vbCrLf .TypeText "Копия: "

Page 455: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 455

Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Копия", wdRng .TypeText vbCrLf .TypeText "От: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "От", wdRng .TypeText vbCrLf .TypeText "Тема: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Тема", wdRng End With

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(0)).Range wdRng.InsertBefore ("Билл Джелен")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(1)).Range wdRng.InsertBefore ("Трейси Сирстад")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(2)).Range wdRng.InsertBefore ("MrExcel")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(3)).Range wdRng.InsertBefore ("Продажи фруктов")

Set wdApp = Nothing Set wdRng = NothingEnd Sub

Результат выполнения макроса UseBookmarks показан на рис. 16.10.

Рис. 16.10. Закладки существенно упро&щают перемещение по документу Word

Закладки можно использовать не только для вставки текста, но и для

вставки других объектов, таких как диаграммы.

Sub CreateMemo() Dim myArray() Dim wdBkmk As String Dim wdApp As Word.Application Dim wdRng As Word.Range

myArray = Array("Кому", "Копия", "От", "Тема", "Диаграмма")

On Error Resume Next Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", "Word.Application") End If If wdApp.ActiveDocument Is Nothing Then With wdApp

Page 456: ? Применение VBA и макросов в Microsoft® Excel

456 Часть II Автоматизация Excel

.Documents.Add .Visible = True End With End If On Error GoTo 0 Set wdSln = wdApp.Selection With wdSln .TypeText "Кому: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Кому", wdRng .TypeText vbCrLf .TypeText "Копия: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Копия", wdRng .TypeText vbCrLf .TypeText "От: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "От", wdRng .TypeText vbCrLf .TypeText "Тема: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Тема", wdRng .TypeText vbCrLf .TypeText "Диаграмма: " Set wdRng = wdApp.Selection.Range wdApp.ActiveDocument.Bookmarks.Add "Диаграмма", wdRng End With

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(0)).Range wdRng.InsertBefore ("Билл Джелен")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(1)).Range wdRng.InsertBefore ("Трейси Сирстад")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(2)).Range wdRng.InsertBefore ("MrExcel")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(3)).Range wdRng.InsertBefore ("Продажи овощей и фруктов")

Set wdRng = wdApp.ActiveDocument.Bookmarks(myArray(4)).Range ActiveSheet.ChartObjects("Chart 2").Copy wdRng.Select wdRng.Application.Selection.PasteAndFormat Type:=2

wdApp.Activate

Set wdApp = Nothing Set wdRng = NothingEnd Sub

Результат выполнения макроса CreateMemo показан на рис. 16.11.

Page 457: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 457

Рис. 16.11. Закладки можно использовать для помещения в документ Word диаграммы

Практикум

Создание отчетов в Word с помощьюрасширенного фильтраВ главе 11, “Анализ данных с помощью расширенного фильтра”, рассматривалсямакрос, использующий расширенный фильтр для создания отчетов по каждомузаказчику и сохраняющий их в виде отдельных рабочих книг. Изменим условиезадачи, потребовав сохранения полученных отчетов в виде документов Word. Ни&же приведена последовательность действий, которые нужно выполнить для дос&тижения поставленной цели.1. Создайте новый документ Word. Добавьте в него закладки Заказчик и

Таблица, а также, при необходимости, дополнительный текст, который нужнопоместить в отчет. Сохраните документ в виде шаблона с именем SalesRe-port.dot.

2. Внесите изменения в макрос RunReportForEachCustomer (см. главу 11). По&сле применения расширенного фильтра для генерирования отчета в Excel соз&дайте документ Word на основе шаблона SalesReport.dot.

3. С помощью метода InsertBefore поместите имя заказчика в позицию за&кладки Заказчик в новом документе Word.

4. Поместите отчет в позицию закладки Таблица в новом документе Word. До&бавьте полужирное начертание к первой строке таблицы (строке заголовков).

Ниже приведен код макроса RunReportForEachCustomer со всеми необходи&мыми изменениями.Sub RunReportForEachCustomer() Dim IRange As Range Dim ORange As Range Dim CRange As Range Dim WBN As Workbook Dim WSN As Worksheet Dim WSO As Worksheet

Page 458: ? Применение VBA и макросов в Microsoft® Excel

458 Часть II Автоматизация Excel

Dim wdApp As Word.Application Dim wdDoc As Word.Document Dim wdRng As Word.Range

Application.ScreenUpdating = False

Set WSO = ActiveSheet

' Определение размера исходного диапазона данных. FinalRow = Cells(65536, 1).End(xlUp).Row NextCol = Cells(1, 255).End(xlToLeft).Column + 2

' Первый расширенный фильтр - создание' списка заказчиков в столбце J.' Определение целевого диапазона.' Копирование заголовка столбца A в ячейку J1. Range("A1").Copy Destination:=Cells(1, NextCol) Set ORange = Cells(1, NextCol)

' Определение исходного диапазона данных. Set IRange = Range("A1").Resize(FinalRow, NextCol - 2)

' Применение расширенного фильтра для отбора' уникальных значений из столбца A. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:="", CopyToRange:=ORange, Unique:=True FinalCust = Cells(65536, NextCol).End(xlUp).Row

' Цикл по списку заказчиков. For Each cell In Cells(2, NextCol).Resize(FinalCust - 1, 1) ThisCust = cell.Value

' Определение условия отбора. Cells(1, NextCol + 2).Value = Range("A1").Value Cells(2, NextCol + 2).Value = ThisCust Set CRange = Cells(1, NextCol + 2).Resize(2, 1)

' Определение целевого диапазона данных.' В целевой диапазон войдут столбцы B (Код),' C (Розничная цена), D (Продано) и E (Остаток). Cells(1, NextCol + 4).Resize(1, 4).Value = _Array(Cells(1, 2), Cells(1, 3), Cells(1, 4), Cells(1, 5)) Set ORange = Cells(1, NextCol + 4).Resize(1, 4)

' Второй расширенный фильтр - отбор строк,' удовлетворяющих заданному условию. IRange.AdvancedFilter Action:=xlFilterCopy, _CriteriaRange:=CRange, CopyToRange:=ORange

' Добавить итоговую строку. TotalRow = WSO.Cells(65536, _ORange.Columns(1).Column).End(xlUp).Row + 1 WSO.Cells(TotalRow, ORange.Columns(1).Column).Value = _"Всего" ' В англоязычной версии Excel: 'WSO.Cells(TotalRow, _ORange.Columns(2).Column).FormulaR1C1 = "=SUM(R2C:R[-1]C)"

Page 459: ? Применение VBA и макросов в Microsoft® Excel

Автоматизация Word Глава 16 459

WSO.Cells(TotalRow, _ORange.Columns(2).Column).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)" ' В англоязычной версии Excel: 'WSO.Cells(TotalRow, _ORange.Columns(4).Column).FormulaR1C1 = "=SUM(R2C:R[-1]C)" WSO.Cells(TotalRow, _ORange.Columns(4).Column).FormulaR1C1Local = "=СУММ(R2C:R[-1]C)"

' Создание нового документа Word. On Error Resume Next

Set wdApp = GetObject(, "Word.Application") If wdApp Is Nothing Then Set wdApp = GetObject("", _"Word.Application") Set wdDoc = wdApp.Documents.Add(Template:= _ThisWorkbook.Path & "\SalesTemplate.dot") wdDoc.Activate

' Создание заголовка отчета. wdDoc.Bookmarks("Заказчик").Range.InsertBefore (ThisCust)

' Копирование отчета с рабочего листа Excel в документ Word. WSO.Cells(1, NextCol + 4).CurrentRegion.Copy Set wdRng =wdApp.ActiveDocument.Bookmarks("Таблица").Range wdRng.Select

' Форматирование таблицы. With wdDoc.Application.Selection .Paste With wdDoc.Application.ActiveDocument.Tables(1) .Rows.Alignment = wdAlignRowCenter With .Rows(1) .HeadingFormat = True .Select wdApp.Selection.Font.Bold = True End With End With .HomeKey Unit:=wdStory, Extend:=Move End With

' Сохранение документа Word с последующим закрытием. wdDoc.SaveAs ThisWorkbook.Path & "\" & ThisCust & ".doc" wdDoc.Close savechanges:=False WSO.Select

Set wdApp = Nothing Set wdDoc = Nothing Set wdRng = Nothing

' Очистить область вставки результата' применения расширенных фильтров. Cells(1, NextCol + 2).Resize(1, 10).EntireColumn.Clear Next cell

Application.ScreenUpdating = True

Page 460: ? Применение VBA и макросов в Microsoft® Excel

460 Часть II Автоматизация Excel

Cells(1, NextCol).EntireColumn.Clear MsgBox FinalCust - 1 & " отчетов были успешно созданы!!"

Set wdRng = NothingEnd Sub

Результат выполнения макроса RunReportForEachCustomer показан нарис. 16.12.

Рис. 16.12. Пример создания отчета в Microsoft Word

Следующий шагСледующая глава посвящена многомерным массивам. Один из наиболее

эффективных способов ускорения обработки данных на рабочем листе заклюY

чается в их считывании в многомерный массив, проведении необходимых выY

числений и копировании полученных результатов обратно на рабочий лист.

Page 461: ? Применение VBA и макросов в Microsoft® Excel

IIIЧасть III

Удивительныевозможности Visual Basicfor Applications

17. Массивы ................................................................................463

18. Работа с текстовыми файлами ....................................... 473

19. Использование Microsoft Access .....................................489

20. Создание пользовательских объектов, типови коллекций ........................................................................ 505

21. Пользовательские формы — профессиональLный подход.......................................................................... 525

22. Интерфейс прикладного программирования(API) Windows ..................................................................... 547

23. Обработка ошибок .............................................................561

24. Создание пользовательских меню и панелейинструментов...................................................................... 575

25. Надстройки.......................................................................... 593

26. Практикум: создание приложения Excel“с нуля”................................................................................. 603

Page 462: ? Применение VBA и макросов в Microsoft® Excel
Page 463: ? Применение VBA и макросов в Microsoft® Excel

Объявление массива .................. 463Заполнение массива .................. 464Манипулированиеэлементами массива .................. 466Еще одно преимуществомассивов.........................................467Динамические массивы ............ 469Передача массива в качествепараметра..................................... 470Следующий шаг............................ 471

17Глава 17

Ìàññèâû

Массив YYYY это переменная специY

ального типа, которая может хранить

более одного элемента данных. Без

использования массива для запомиY

нания имени и адреса заказчика поY

требуется создать две обычные переY

менные. В то же время, для хранения

целого списка, состоящего из имен и

адресов сотен заказчиков, достаточно

одного массива.

Объявление массиваЧтобы объявить массив, укажите

число его элементов в скобках после

имени переменной, как показано

ниже:

Dim myArray(2)

Приведенный выше код создает

массив myArray, состоящий из трех

элементов. ДаYда, именно из трех,

потому что по умолчанию первый

элемент массива имеет индекс 0:

myArray(0) = 10myArray(1) = 20myArray(2) = 30

Чтобы назначить первому элеменY

ту массива индекс 1, воспользуйтесь

выражением Option Base 1. ВыY

ражение Option Base размещается

в разделе объявлений модуля:

Option Base 1Dim myArray(2)

Теперь массив myArray будет соY

стоять из двух элементов.

При создании массива можно заY

дать как верхнюю, так и нижнюю его

границу:

Page 464: ? Применение VBA и макросов в Microsoft® Excel

464 Часть III Удивительные возможности Visual Basic for Applications

Dim myArray(1 to 10)Dim BigArray(100 to 200)

Узнать верхнюю и нижнюю границу массива можно с помощью функций

UBound и LBound, соответственно. Выражение Dim myArray(2) определяет

только верхнюю границу массива, в то время как выражение Dim myArray(1 to 10) — как верхнюю (10), так и нижнюю (1) границы.

Многомерные массивыРассмотренные выше массивы являются одномерными массивами, положеY

ние элементов которых определяется всего одним числом. Одномерный масY

сив можно представить в виде строки данных, единственной значимой коорY

динатой которой является номер столбца. Ниже приведен пример обращения

ко второму элементу одномерного массива (Option Base 0):

myArray(1)

Во многих ситуациях для представления данных используются многомерныемассивы, положение элементов которых определяется несколькими числами

(например, двумерный массив можно сравнить с набором строк, значимыми

координатами которого являются номер столбца и номер строки).

На заметку Двумерный массив часто называют матрицей, что по своей сути близко к понятиюэлектронной таблицы. Действительно, объект Cells определяет положение эле&мента таблицы, т.е. номер его строки и столбца.

Ниже приведен пример создания двумерного массива, состоящего из

10 строк и 20 столбцов:

Dim myArray(1 to 10, 1 to 20)

Следующий код заполняет элементы первой строки массива myArray:

myArray(1, 1) = 10myArray(1, 2) = 20

Аналогичным образом заполняются элементы второй строки массива:

myArray(2, 1) = 20myArray(2, 2) = 40

Конечно же, существуют и более эффективные способы заполнения масY

сива, которые рассматриваются далее в этой главе.

Заполнение массиваСамый простой способ заполнения массива был продемонстрирован в

предыдущем разделе. Существуют гораздо более эффективные методы выполY

нения аналогичной операции, один из которых приведен ниже:

Option Base 1

Sub ColumnHeaders()

Page 465: ? Применение VBA и макросов в Microsoft® Excel

Массивы Глава 17 465

Dim myArray As Variant Dim myCount As Integer' Заполнить массив. myArray = Array("Имя", "Адрес", "Телефон", "Адрес эл. почты")' Скопировать содержимое массива на рабочий лист. With Worksheets("Заполнение массива") For myCount = 1 To UBound(myArray) .Cells(1, myCount).Value = myArray(myCount) Next myCount End WithEnd Sub

Результат выполнения макроса ColumnHeaders показан на рис. 17.1.

Обратите внимание, что в приведенном выше коде для создания массива

была использована переменная myArray типа Variant, которая может храY

нить информацию любого рода. Переменная myArray принимает свойства

массива после присвоения ей соответствующего значения:

myArray = Array("Имя", "Адрес", "Телефон", "Адрес эл. почты")

Ниже приведен пример заполнения массива данными, взятыми с рабочего

листа Excel (см. рис. 17.2):

Dim myArray As VariantmyArray = Worksheets("Sheet1").Range("B2:C17")

Рис. 17.1. Пример использования массивадля создания строки заголовков

Рис. 17.2. Массив можно за&полнить данными, взятыми срабочего листа Excel

Следующий макрос заполняет массив данными, взятыми с рабочего листа

Excel через одну строку:

Sub EveryOtherRow() Dim myArray(1 To 8, 1 To 2) Dim i As Integer, j As Integer, myCount As Integer

' Заполнить массив данными, взятыми' с рабочего листа Excel через одну строку. For i = 1 To 8

Page 466: ? Применение VBA и макросов в Microsoft® Excel

466 Часть III Удивительные возможности Visual Basic for Applications

For j = 1 To 2 myArray(i, j) = _Worksheets("Через один").Cells(i * 2, j + 1).Value Next j Next i

' Скопировать содержимое массива на рабочий лист. For myCount = LBound(myArray) To UBound(myArray) Worksheets("Через один").Cells(myCount * 2, 4) = _WorksheetFunction.Sum(myArray(myCount, 1), myArray(myCount, 2)) Next myCountEnd Sub

Результат выполнения макроса EveryOtherRow показан на рис. 17.3.

Рис. 17.3. Макрос EveryOtherRowподсчитывает сумму данных, взя&тых с рабочего листа Excel через од&ну строку

Манипулирование элементами массиваОдно из основных предназначений массива заключается в манипулироваY

нии его элементами. Следующий макрос вычисляет наибольший элемент масY

сива, заполненного данными, взятыми с рабочего листа Excel.

Sub QuickFillMax() Dim myArray As Variant myArray = Worksheets("Через один").Range("B2:C17") MsgBox "Максимальное целое число в диапазоне B2:C17 равно " _& WorksheetFunction.Max(myArray)End Sub

Результат выполнения макроса QuickFillMax показан на рис. 17.4.

Зачастую результат манипулирования элементами массива помещается на

рабочий лист Excel. Следующий макрос вычисляет среднее значение каждой

строки массива и помещает полученный результат на рабочий лист.

Page 467: ? Применение VBA и макросов в Microsoft® Excel

Массивы Глава 17 467

Рис. 17.4. Макрос QuickFillMax вычисляетнаибольшее значение в диапазоне B2:C17

Sub QuickFillAverage() Dim myArray As Variant Dim myCount As Integer

myArray = Worksheets("Через один").Range("B2:C17") For myCount = LBound(myArray) To UBound(myArray) Worksheets("Через один").Cells(myCount + 1, 5).Value = _WorksheetFunction.Average(myArray(myCount, 1), myArray(myCount, 2)) Next myCountEnd Sub

На заметку При помещении данных на рабочий лист Excel в качестве адреса строки использу&ется значение myCount + 1. Это обусловлено тем, что нижняя граница массива(LBound) равна 1 (Option Base 1), а данные на рабочем листе размещаются на&чиная со второй строки.

Результат выполнения макроса QuickFillAverage показан на рис. 17.5.

Еще одно преимущество массивовНеужели все преимущество массивов сводится к упрощению манипулироY

вания данными рабочего листа? Конечно же, нет. Основная выгода, получаеY

мая от использования массивов, заключается в существенном повышении ско*рости выполнения программного кода.

Page 468: ? Применение VBA и макросов в Microsoft® Excel

468 Часть III Удивительные возможности Visual Basic for Applications

Рис. 17.5. Макрос QuickFillAverage вы&числяет среднее значение строк массива ипомещает полученные результаты на рабо&чий лист Excel

Следующий макрос вычисляет среднее значение столбцов B и C без исY

пользования массива.

Sub SlowAverage() Dim myCount As Integer, LastRow As Integer LastRow = Worksheets("Через один").Range("A65536").End(xlUp).Row For myCount = 2 To LastRow With Worksheets("Через один") .Cells(myCount, 5).Value = _WorksheetFunction.Average(.Cells(myCount, 2), .Cells(myCount, 3)) End With Next myCountEnd Sub

Макрос SlowAverage обрабатывает каждую строку в области данных раY

бочего листа, вычисляя среднее столбцов B и C и помещая полученный реY

зультат в столбец E. Не проще ли работать с данными как с единым целым,

обращаясь к ячейкам рабочего листа только для заполнения массива и помеY

щения на рабочий лист полученного результата?

При заполнении массива рекомендуется использовать именованный диаY

пазон ячеек, так как это позволяет создавать более универсальный код.

Ниже приведены примеры заполнения массива с помощью обычного и

именованного диапазона ячеек.

myArray = Range("B2:C17")myArray = Range("myData")

Совет Присвоение переменной типа Variant содержимого столбца рабочего листа Ex&cel приведет к созданию двумерного массива, для обращения к элементам кото&рого необходимо указывать номер строки и номер столбца.

Page 469: ? Применение VBA и макросов в Microsoft® Excel

Массивы Глава 17 469

Чтобы упростить работу с подобным массивом, транспонируйте столбец с помо&щью функции Transpose, превратив его тем самым в строку. Присвоение пере&менной типа Variant содержимого строки рабочего листа Excel приведет к соз&данию одномерного массива, что наглядно демонстрирует следующий код. Sub TransposeArray() Dim myArray As Variant

myArray = WorksheetFunction.Transpose(Range("myTran"))

' Узнать значение 5-го элемента массива. MsgBox "5-й элемент массива равен " & myArray(5)End Sub

Результат выполнения макроса TransposeArray показан на рис. 17.6.

Рис. 17.6. Чтобы создать одномерный массив,

преобразуйте столбец в строку с помощьюфункции Transpose

Динамические массивыОчень часто размер массива заранее неизвестен. Теоретически можно созY

дать массив очень большого размера ‘‘на все случаи жизни’’, однако это решение

приведет к напрасной трате ресурсов и не гарантирует 100%Yго результата. ВыY

ходом из подобной ситуации является использование динамического массива.

Объявление динамического массива аналогично объявлению обычного

массива без указания размера последнего:

Dim myArray()

Page 470: ? Применение VBA и макросов в Microsoft® Excel

470 Часть III Удивительные возможности Visual Basic for Applications

Когда размер динамического массива станет известен, инициализируйте

его с помощью выражения ReDim:

Sub MySheets() Dim myArray() As String Dim myCount As Integer, NumShts As Integer

NumShts = ActiveWorkbook.Worksheets.Count' Инициализация динамического массива. ReDim myArray(1 To NumShts) For myCount = 1 To NumShts myArray(myCount) = ActiveWorkbook.Sheets(myCount).Name Next myCount Worksheets("Через один").Range("J33").Resize(, _NumShts).Value = myArray

End Sub

Повторная инициализация массива с помощью выражения ReDim привоY

дит к полному уничтожению его предыдущего содержимого. Чтобы предотY

вратить потерю текущих значений элементов массива, воспользуйтесь ключеY

вым словом Preserve. Следующий макрос создает массив, состоящий из

имен файлов рабочих книг Excel, находящихся в заданной папке.

Sub XLFiles() Dim FName As String Dim arNames() As String Dim myCount As Integer

FName = Dir(ThisWorkbook.Path & "\*.xls") Do Until FName = "" myCount = myCount + 1 ReDim Preserve arNames(1 To myCount) arNames(myCount) = FName FName = Dir Loop On Error Resume Next Worksheets("Через один").Range("J38").Resize(, _myCount).Value = arNamesEnd Sub

Внимание При работе с большими объемами данных использование ключевого слова Pre-serve внутри цикла приводит к замедлению выполнения программного кода. Ес&ли это возможно, постарайтесь определить размер динамического массива довхождения в цикл.

Передача массива в качестве параметраМассив можно передавать в качестве параметра, подобно обычной переY

менной. Это повышает эффективность и читабельность кода. Следующий

макрос передает массив myArray в качестве параметра функции Region-Sales, которая подсчитывает сумму элементов массива и возвращает полуY

ченный результат.

Page 471: ? Применение VBA и макросов в Microsoft® Excel

Массивы Глава 17 471

Sub PassAnArray() Dim myArray() As Variant Dim myRegion As String

myArray = Range("mySalesData") myRegion = InputBox("Введите регион - Запад, Центр или Восток") MsgBox "Продажи в регионе " & myRegion & " составили " &Format(RegionSales(myArray, _ myRegion), "$#,#00.00 ")End Sub

Function RegionSales(ByRef BigArray As Variant, _sRegion As String) As Long Dim myCount As Integer

RegionSales = 0 For myCount = LBound(BigArray) To UBound(BigArray) If BigArray(myCount, 1) = sRegion Then RegionSales = BigArray(myCount, _4) * BigArray(myCount, 3) + RegionSales End If Next myCountEnd Function

Результат выполнения макроса PassAnArray показан на рис. 17.7.

Рис. 17.7. Массив можно передавать в качествепараметра функции или процедуре

Следующий шагМассив YYYY это переменная специального типа, которая может хранить неY

сколько элементов данных. Основное предназначение массива заключается в

упрощении обработки данных и повышении скорости выполнения проY

граммного кода. Следующая глава посвящена работе с текстовыми файлами.

Экспортирование данных в текстовый файл может понадобиться для передачи

информации в другую систему или создания HTMLYфайла.

Page 472: ? Применение VBA и макросов в Microsoft® Excel
Page 473: ? Применение VBA и макросов в Microsoft® Excel

Импорт данных из текстовогофайла ..............................................473Экспорт данных в текстовыйфайл ............................................... 486Следующий шаг........................... 487

18Глава 18

Ðàáîòàñ òåêñòîâûìèôàéëàìè

Прежде чем формат XML окончаY

тельно утвердится в качестве станY

дартного формата файлов, некоторое

время наряду с форматом XML шиY

рокое распространение будут иметь

форматы CSV и TXT.

В этой главе рассматривается имY

порт и экспорт текстовых файлов поY

средством VBA. Экспорт данных в

текстовый файл может понадобиться

для передачи информации в другую

систему или создания HTMLYфайла.

Импорт данных изтекстового файла

Рассмотрим три сценария имY

порта данных из текстовых файлов.

Если в файле содержится менее

65 536 записей, его можно импорY

тировать с помощью метода Work-books.OpenText. Если в файле

содержится более 65 536 записей, но

менее 98 304 записей, его можно имY

портировать с помощью двух вызовов

метода Workbooks.OpenText. Если

же в файле содержится более

98 304 записей, его придется имY

портировать путем последовательY

ного считывания строк.

Page 474: ? Применение VBA и макросов в Microsoft® Excel

474 Часть III Удивительные возможности Visual Basic for Applications

Импорт текстовых файлов, содержащих менее65 536 записей

Существует два основных формата текстовых файлов. Первый формат

предполагает разделение полей каждой записи с помощью некоторого симвоY

ла, например, запятой, точки с запятой, знака табуляции и т.п. Второй формат

подразумевает наличие фиксированной ширины полей каждой записи.

Excel одинаково успешно справляется с файлами обоих форматов с помоY

щью метода OpenText. При разработке программного кода рекомендуется

записать макрос и использовать уже готовые фрагменты кода.

Импорт текстового файла с полями фиксированной ширины

На рис. 18.1 показан пример текстового файла с полями фиксированной

ширины.

Рис. 18.1. При открытии текстового файла с полями фиксированной ши&рины необходимо указать точный размер полей

При открытии подобного файла необходимо указать точный размер его

полей. Чтобы создать соответствующий программный код, воспользуемся

средством записи макросов.

Начните запись макроса, выбрав в меню Excel команду Сервис МакросНачать запись (Tools Macros Record New Macro). Выберите команду ФайлОткрыть (File Open) и откройте нужный файл с помощью диалогового окна

Открытие документа (Open).

Page 475: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 475

В диалоговом окне Мастер текстов (импорт) — шаг 1 из 3 (Text Import

Wizard YYYY Step 1 of 3) установите переключатель Фиксированной ширины(Fixed width) и щелкните на кнопке Далее (Next).

На рис. 18.2 показан результат попытки автоматического определения шиY

рины полей текстового файла.

Рис. 18.2. Результат попытки автоматического определения ширины по&лей текстового файла. Очевидно, что Excel затрудняется определитьширину соприкасающихся полей

Excel затрудняется определить ширину соприкасающихся полей, таких как

Дата и Заказчик.

Добавьте требуемые линии, обозначающие конец поля, в области Образецразбора данных (Data preview) диалогового окна Мастер текстов (импорт) —шаг 2 из 3 (Text Import Wizard YYYY Step 2 of 3). Чтобы добавить линию, щелкниY

те в нужной позиции в области Образец разбора данных. Чтобы переместить

линию, щелкните на ней и перетащите в требуемое место. Чтобы удалить лиY

нию, дважды щелкните на ней. Конечный результат определения ширины поY

лей текстового файла показан на рис. 18.3.

Обратите внимание на линейку, расположенную над областью Образецразбора данных. Каждое ее деление соответствует одному символу в текстоY

вом файле. К примеру, поле Заказчик начинается с 25Yй позиции и имеет

длину 11 символов.

По умолчанию Excel предполагает, что все поля текстового файла имеют

формат Общий (General). Измените формат полей, требующих особой обраY

ботки. Для этого щелкните на столбце и выберите требуемый формат с помоY

щью области Формат данных столбца (Column data format) диалогового окна

Мастер текстов (импорт) — шаг 3 из 3 (Text Import Wizard YYYY Step 3 of 3), как

показано на рис. 18.4.

Page 476: ? Применение VBA и макросов в Microsoft® Excel

476 Часть III Удивительные возможности Visual Basic for Applications

Рис. 18.3. Образец разбора данных после добавления двух линий, обо&значающих конец поля, и перемещения линии, разграничивающей по&ля Товар и Дата

Рис. 18.4. Измените тип столбца Дата на МДГ (MDY). Откажитесь отимпорта столбцов С-ть и Пр-ль, изменив их тип на Пропустить(Skip). Чтобы определить разделитель целой и дробной части, а такжеразделитель разрядов, щелкните на кнопке Подробнее (Advanced)

Например, чтобы изменить тип столбца Дата, щелкните на нем и установите

переключатель Дата (Date) в области Формат данных столбца. Укажите формат

даты (например, ‘‘деньYYмесяцYYгод’’ или ‘‘месяцYYденьYYгод’’) с помощью раскрыY

вающегося списка, расположенного справа от переключателя Дата.

Чтобы отказаться от импорта определенного столбца, щелкните на нем и

установите переключатель Пропустить столбец (Do not import column (skip)).

Page 477: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 477

Пропуск столбцов может пригодиться при импортировании текстового файY

ла, содержащего нежелательную для разглашения информацию (например,

себестоимость товара и прибыль, получаемая от его продажи). Иногда текY

стовый файл с полями фиксированной ширины содержит также символыY

разделители. Установите переключатель Пропустить столбец для всех столбY

цов, содержащих символыYразделители, как показано на рис. 18.5.

Рис. 18.5. Переключатель Пропустить столбец рекомендуется устано&вить для всех столбцов текстового файла с полями фиксированной ши&рины, содержащих символы&разделители

Полям, содержащим алфавитные символы, можно назначить тип Общий.

Назначьте тип Текст (Text) числовым полям, значения которых необходимо

импортировать как текст. Примером таких полей является поле почтового инY

декса и поле номера банковского счета (оба поля могут содержать значения с

ведущими нулями, например, 01234).

Внимание Excel воспринимает формулу, введенную в столбец текстового формата, как обыч&ную строку. Чтобы ввести формулу, формат столбца придется изменить на Общий(General).

Ниже приведен код импорта текстового файла с полями фиксированной

ширины, сгенерированный средством записи макросов.

Workbooks.OpenText Filename:="sales.prn", Origin:=1251, _StartRow:=1, DataType:=xlFixedWidth, FieldInfo:=Array( _Array(0, 2), Array(8, 1), Array(17, 3), Array(25, 1), _Array(36, 1), Array(46, 1), Array(56, 9), Array(61, 9)), _TrailingMinusNumbers:=True

Page 478: ? Применение VBA и макросов в Microsoft® Excel

478 Часть III Удивительные возможности Visual Basic for Applications

Значение параметра FieldInfo представляет массив двухэлементных

массивов, определяющих позицию первого символа поля (с отсчетом от нуля)

и его тип.

Тип поля представлен числом, соответствующим одной из констант Excel

xlColumnDataType (табл. 18.1). Например, массив Array(0, 1) определяY

ет поле общего формата, отстающее от начала строки на 0 символов (поле

Регион), массив Array(8, 1) — поле общего формата, отстающее от начала

строки на 8 символов (поле Товар), а массив Array(17, 3) — поле даты в

формате ‘‘месяцYYденьYYгод’’, отстающее от начала строки на 17 символов (поле

Дата).

Таблица 18.1. Значения констант xlColumnDataType

Значение Константа Тип данных

1 xlGeneralFormat Общий

2 xlTextFormat Текстовый

3 xlMDYFormat Дата в формате ‘‘месяцYYденьYYгод’’

4 xlDMYFormat Дата в формате ‘‘деньYYмесяцYYгод’’

5 xlYMDFormat Дата в формате ‘‘годYYмесяцYYдень’’

6 xlMYDFormat Дата в формате ‘‘месяцYYгодYYдень ’’

7 xlDYMFormat Дата в формате ‘‘деньYYгодYYмесяц’’

8 xlYDMFormat Дата в формате ‘‘годYYденьYYмесяц’’

9 xlSkipColumn Пропуск столбца

10 xlEMDFormat Дата в тайском летоисчислении

Ввиду относительной сложности кодирования параметра FieldInfo реY

комендуется записать макрос и скопировать автоматически сгенерированный

фрагмент кода.

Внимание Впервые параметр TrailingMinusNumbers был представлен в Excel 2002. Не ис&пользуйте его в макросах, которые могут выполняться в более ранних версиях Ex&cel, например, Excel 97 или Excel 2000, так как это приведет к возникновениюошибки компиляции. Отсутствие параметра TrailingMinusNumbers не скажетсяна результате выполнения макроса в новых версиях Excel.

Импорт текстового файла с символамиLразделителями

На рис. 18.6 показан текстовый файл с разделителямиYзапятыми.

При открытии подобного файла в Excel укажите используемый символY

разделитель и, при необходимости, способ обработки полей. В рассматриваеY

Page 479: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 479

мом примере значение третьего поля должно быть интерпретировано как дата

в формате ‘‘месяцYYденьYYгод’’.

Рис. 18.6. При открытии текстового файла с символами&разделителямиукажите используемый символ&разделитель (в данном случае это запя&тая) и, при необходимости, способ обработки полей

Внимание При открытии текстового файла с расширением .csv, содержащего разделители&запятые, средство записи макросов Excel создаст код, вызывающий метод Work-books.Open. Чтобы иметь возможность указать способ обработки полей, изме&ните расширение файла на .txt.

Начните запись макроса, выбрав в меню Excel команду Сервис МакросНачать запись (Tools Macros Record New Macro). Выберите команду

Файл Открыть (File Open) и откройте нужный файл с помощью диалогоY

вого окна Открытие документа (Open).

В диалоговом окне Мастер текстов (импорт) — шаг 1 из 3 (Text Import

Wizard YYYY Step 1 of 3) установите переключатель С разделителями (Delimited)

и щелкните на кнопке Далее (Next).

Первоначальный результат автоматического разбора данных, показанный

в области Образец разбора данных (Data preview) диалогового окна Мастертекстов (импорт) — шаг 2 из 3 (Text Import Wizard YYYY Step 2 of 3), будет выY

глядеть крайне непривлекательно. Это вызвано тем, что Excel по умолчанию

использует в качестве символаYразделителя знак табуляции (рис. 18.7).

Page 480: ? Применение VBA и макросов в Microsoft® Excel

480 Часть III Удивительные возможности Visual Basic for Applications

Рис. 18.7. Результат первоначального разбора данных выглядит как чья&то неудавшаяся шутка. А все из&за того, что Excel по умолчанию исполь&зует в качестве символа&разделителя знак табуляции

Сбросьте флажок Знак табуляции (Tab) и установите флажок, соответствуюY

щий требуемому символуYразделителю (в данном случае это флажок Запятая(Comma)). Результат повторного разбора данных показан на рис. 18.8.

Рис. 18.8. Результат повторного разбора данных после изменения ис&пользуемого символа&разделителя не вызывает никаких нареканий.В целом, разбор текстового файла с символами&разделителями требуетвыполнения меньшего количества действий, чем разбор текстовогофайла с полями фиксированной ширины

Задайте формат полей, требующих особой обработки, с помощью диалогоY

вого окна Мастер текстов (импорт) — шаг 3 из 3 (Text Import Wizard YYYY Step 3

Page 481: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 481

of 3). Ниже приведен код импорта текстового файла с символамиY

разделителями, сгенерированный средством записи макросов.

Workbooks.OpenText Filename:="sales.csv.txt", Origin:=1251, _StartRow:=1, DataType:=xlDelimited, TextQualifier:= _xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _Semicolon:=False, Comma:=True, Space:=False, Other:=False, _FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 3), _Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), _Array(8, 1)), TrailingMinusNumbers:=True

Несмотря на то что этот код длиннее кода импорта текстового файла с поY

лями фиксированной ширины, он менее сложен для восприятия. Параметр

FieldInfo представляет массив двухэлементных массивов, определяющих

порядковый номер поля (с отсчетом от единицы) и его тип (см. табл. 18.1).

Например, массив Array(2, 1) определяет второе поле как поле общего

формата, а массив Array(3, 3) — третье поле как поле даты в формате

‘‘месяцYYденьYYгод’’. Длина кода обусловлена явным заданием значений всех

параметров, определяющих символыYразделители. Поскольку по умолчанию

значение этих параметров равно False, код можно оптимизировать, как поY

казано ниже:

Workbooks.OpenText Filename:="sales.csv.txt", Origin:=1251, _StartRow:=1, DataType:=xlDelimited, Comma:=True, _FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 3), _Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), Array(8, 1))

Чтобы сделать код более удобочитаемым, числовые значения, определяюY

щие тип поля, можно заменить соответствующими константами:

Workbooks.OpenText Filename:="sales.csv.txt", Origin:=1251, _StartRow:=1, DataType:=xlDelimited, Comma:=True, _FieldInfo:=Array(Array(1, xlGeneralFormat), Array(2, _xlGeneralFormat), Array(3, xlMDYFormat), Array(4, _xlGeneralFormat), Array(5, xlGeneralFormat), Array(6, _xlGeneralFormat), Array(7, xlGeneralFormat), Array(8, _xlGeneralFormat))

Внимание Значения параметров, определяющих символы&разделители, остаются действи&тельными на протяжении всего сеанса работы с Excel. При вставке текстовых дан&ных, содержащихся в буфере обмена, Excel осуществит их разбор в соответствиисо значениями параметров, заданными во время последнего вызова методаOpenText. К примеру, название фирмы заказчика “ABC, Inc.” будет разбито надве части (“ABC” и “Inc.”) и помещено в два соседних столбца, если в качествесимвола&разделителя использовалась запятая.

Excel позволяет использовать любой символYразделитель, а не только симY

вол табуляции, запятую, точку с запятой и пробел. Чтобы указать на необхоY

димость использования в качестве символаYразделителя знака перенаправлеY

ния (|), установите значение параметра Other метода OpenText равным

True, а значение параметра OtherChar равным "|", как показано далее:

Page 482: ? Применение VBA и макросов в Microsoft® Excel

482 Часть III Удивительные возможности Visual Basic for Applications

Workbooks.OpenText Filename:="sales.csv.txt", Origin:=1251, _StartRow:=1, DataType:=xlDelimited, Other:=True, OtherChar:="|" _FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 3), _Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), Array(8, 1))

Импорт текстовых файлов, содержащих более65 536 записей

Импорт файла, содержащего более 65 536 записей, с помощью мастера текY

стов завершится выдачей сообщения об ошибке Файл загружен неполностью (File not loaded completely) и загрузкой первых 65 536 строк.

Импорт того же файла с помощью метода Workbooks.OpenText заверY

шится загрузкой первых 65 536 строк без уведомления о внештатной ситуации.

Проверьте содержимое ячейки A65536 после импорта файла. Если эта ячейка

не пуста, вероятно, файл был загружен некорректно.

Импорт текстового файла, содержащего не более 98 304 записей

На самом деле, Excel позволяет импортировать текстовый файл, содержаY

щий более 65 536 записей. В диалоговом окне Мастер текстов (импорт) —шаг 1 из 3 (Text Import Wizard YYYY Step 1 of 3) есть счетчик Начать импорт состроки (Start Import At Row), являющийся аналогом параметра StartRow меY

тода OpenText. Казалось бы, достаточно присвоить параметру StartRowзначение 65 537 и продолжить импорт файла. Как бы не так! Попытка присвоY

ить параметру StartRow значение, превышающее 32 767, завершится ошибY

кой времени выполнения 1004. Дело в том, что в ранних версиях Excel для

хранения значения параметра StartRow использовалась переменная типа

Integer, максимально допустимое значение которой составляло 32 767.

Складывается впечатление, что Microsoft не проводила генеральную ревизию

кода импорта текстовых файлов со времен, когда рабочий лист Excel был споY

собен вмещать чуть более 16 000 строк!

Рассмотрим задачу импорта текстового файла, содержащего сведения о

складских запасах 35 магазинов розничной торговли. Известно, что перечень

наименований товаров в каждом из магазинов не превышает 2000 позиций.

Следовательно, максимальное число записей импортируемого файла составY

ляет 70 000. Ниже приведен код импорта текстового файла, содержащего не

более 98 304 записей.

Sub ImportFile() Dim WBO As Workbook Dim WBC As Workbook

Set WBO = ActiveWorkbook ChDir ThisWorkbook.Path ThisFile = "inventory.txt" Workbooks.OpenText Filename:=ThisFile Set WBC = ActiveWorkbook WBO.Worksheets("Данные").Cells.Clear Cells.Copy WBO.Worksheets("Данные").Range("A1")

Page 483: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 483

WBC.Close False

If WBO.Worksheets("Данные").Cells(65536, 1).Value <> "" Then' Файл содержит более 65536 записей.' Импортировать заново, начиная со строки 32767. Workbooks.OpenText Filename:=ThisFile, StartRow:=32767 Set WBC = ActiveWorkbook

' Некоторые строки (а именно строки 32767-65536)' будут скопированы повторно.' Первые 32770 строк нужно удалить. RowsToSkip = Application.Rows.Count + 1 - 32767 Cells(1, 1).Resize(RowsToSkip, 1).EntireRow.Delete FinalRow = Cells(65536, 1).End(xlUp).Row Cells(1, 1).Resize(FinalRow, 1).Copy _WBO.Worksheets("Данные").Range("AA1") WBC.Close False

End IfEnd Sub

Импорт текстового файла построчно

Изменим условие задачи, увеличив число розничных магазинов до 50. При

этом максимальный размер импортируемого файла возрастет до 100 000 записей и

его придется загружать построчно.

Импорт текстового файла, содержащего менее 65 536 записей, построчноОткройте файл для чтения с помощью выражения Input As #1. Чтобы

считать строку файла в переменную, воспользуйтесь выражением Line In-put #1, имя_переменной. Следующий макрос открывает файл inven-tory.txt, считывает первые 10 строк, помещая их содержимое в ячейки раY

бочего листа, после чего закрывает файл.

Sub Import10() ChDir ThisWorkbook.Path ThisFile = "inventory.txt" Open ThisFile For Input As #1 For i = 1 To 10 Line Input #1, Data Cells(i, 1).Value = Data Next i Close #1End Sub

Чтобы считать все содержимое файла, воспользуйтесь циклом

Do...While и функцией EOF. Значение выражения EOF(1) позволяет опреY

делить, был ли достигнут конец файла с номером #1. Следующий макрос поY

строчно импортирует содержимое файла inventory.txt (чтобы обеспечить

корректное выполнение макроса ImportAll, файл inventory.txt не долY

жен содержать более 65 536 записей).

Sub ImportAll() ThisFile = "inventory.txt" Open ThisFile For Input As #1

Page 484: ? Применение VBA и макросов в Microsoft® Excel

484 Часть III Удивительные возможности Visual Basic for Applications

Ctr = 0 Do Line Input #1, Data Ctr = Ctr + 1 Worksheets("Данные").Cells(Ctr, 1).Value = Data Loop While EOF(1) = False Close #1 Worksheets("Данные").SelectEnd Sub

Результат импорта текстового файла описанным выше способом показан

на рис. 18.9.

Рис. 18.9. Построчное считывание текстового файла требует последующей обработки данныхна рабочем листе

Очевидным недостатком такого подхода является помещение содержимого

каждой строки файла в ячейку столбца A.

Чтобы провести разбор импортированных данных, воспользуйтесь метоY

дом TextToColumns. Параметры метода TextToColumns практически иденY

тичны параметрам метода OpenText.

Cells(1, 1).Resize(Ctr, 1).TextToColumns Destination:= _Range("A1"), DataType:=xlDelimited, comma:=True, FieldInfo:= _Array(Array(1, xlGeneralFormat), Array(2, xlGeneralFormat), _Array(3, xlGeneralFormat), Array(4, xlMDYFormat))

Page 485: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 485

Вместо жесткой привязки к конкретному номеру файла рекомендуется исY

пользовать функцию FreeFile. Функция FreeFile возвращает целое число,

представляющее номер файла, доступный для использования в выражении

Open. Ниже приведен полный код макроса, считывающего текстовый файл с

менее чем 65 536 записями, построчно.

Sub ImportAllAndParse() ThisFile = "inventory.txt" FileNumber = FreeFile

Open ThisFile For Input As #FileNumber Ctr = 0 Do Line Input #FileNumber, Data Ctr = Ctr + 1 Worksheets("Данные").Cells(Ctr, 1).Value = Data Loop While EOF(FileNumber) = False Close #FileNumber Worksheets("Данные").Select' Провести разбор данных. Cells(1, 1).Resize(Ctr, 1).TextToColumns Destination:= _Range("A1"), DataType:=xlDelimited, comma:=True, FieldInfo:= _Array(Array(1, xlGeneralFormat), Array(2, xlGeneralFormat), _Array(3, xlGeneralFormat), Array(4, xlMDYFormat))End Sub

Импорт текстового файла, содержащего более 65 536 записей, построчноДля построчного импорта текстового файла, содержащего более

65 536 записей, можно использовать уже знакомое выражение Line Input.

Считаем часть файла в ячейки A1:A65534, продолжив считывание оставшихY

ся строк, начиная с ячейки AA2 (первая строка отводится для размещения заY

головков столбцов). Если и этого окажется недостаточно, продолжим считыY

вание, начиная с ячейки BA2, CA2 и т.д. Наличие двух пустых строк в конце

каждого столбца с данными обеспечивает корректное определение номера поY

следней строки с помощью выражения Range("A65536").End(xlUp).Row.

Sub ReadLargeFile() ThisFile = "inventory.txt" FileNumber = FreeFile

Open ThisFile For Input As #FileNumber NextRow = 1 NextCol = 1' Добавлено для увеличения скорости выполнения макроса. Application.ScreenUpdating = False Application.StatusBar = "Считывание данных из текстового файла" Do While Not EOF(FileNumber) Line Input #FileNumber, Data Cells(NextRow, NextCol).Value = Data NextRow = NextRow + 1 If NextRow = 65535 Then' Провести разбор данных. Application.StatusBar = "Разбор данных" Range(Cells(1, NextCol), Cells(65536, _NextCol)).TextToColumns Destination:=Cells(1, NextCol), _

Page 486: ? Применение VBA и макросов в Microsoft® Excel

486 Часть III Удивительные возможности Visual Basic for Applications

DataType:=xlDelimited, comma:=True, FieldInfo:=Array(Array(1, _xlGeneralFormat), Array(2, xlGeneralFormat), Array(3, _xlGeneralFormat), Array(4, xlMDYFormat))' Скопировать заголовки столбцов. If NextCol > 1 Then Range("A1:D1").Copy Destination:=Cells(1, NextCol) End If' Начать считывание следующего набора данных. NextCol = NextCol + 26 NextRow = 2 Application.StatusBar = "Считывание следующего _набора данных"

End If Loop Close #FileNumber' Разбор последнего набора данных. FinalRow = NextRow - 1 If FinalRow = 1 Then' Обработка файла, содержащего ровно 65534 строки. NextCol = NextCol - 26 Else Application.StatusBar = "Разбор последнего набора данных" Range(Cells(2, NextCol), Cells(FinalRow, _NextCol)).TextToColumns Destination:=Cells(2, NextCol), _DataType:=xlDelimited, comma:=True, FieldInfo:=Array(Array(1, _xlGeneralFormat), Array(2, xlGeneralFormat), Array(3, _xlGeneralFormat), Array(4, xlMDYFormat)) If NextCol > 1 Then Range("A1:D1").Copy Destination:=Cells(1, NextCol) End If End If Cells(1, NextCol).Select

DataSets = (NextCol - 1) / 26 + 1 Application.StatusBar = False Application.ScreenUpdating = True

End Sub

Число наборов данных, созданных в результате выполнения макроса

ReadLargeFile, хранится в переменной DataSet.

Описанный выше метод позволяет разместить на рабочем листе более

655 000 строк, импортированных из текстового файла. Чтобы применить фильтр

или создать отчет на основе нескольких наборов данных, в код макросов, рассмотY

ренных в предыдущих главах, потребуется внести соответствующие изменения.

Например, можно создать по одной сводной таблице для каждого набора данных,

подытожив полученные результаты с помощью еще одной сводной таблицы.

Экспорт данных в текстовый файлЧтобы экспортировать данные в текстовый файл, откройте его для записи с

помощью выражения Output As #1. Сохраните все требуемые строки в

файле с помощью выражения Print #1.

Page 487: ? Применение VBA и макросов в Microsoft® Excel

Работа с текстовыми файлами Глава 18 487

Прежде чем открыть файл для записи, убедитесь, что на диске не существуY

ет копии этого файла. Для этого попытайтесь удалить файл с помощью выраY

жения Kill. Чтобы проигнорировать сообщение об ошибке, которое будет

сгенерировано, если файл с заданным именем не существует, воспользуйтесь

выражением On Error Resume Next.

Следующий макрос экспортирует данные рабочего листа в текстовый файл

Results.txt.

Sub WriteFile() ThisFile = ThisWorkbook.Path & Application.PathSeparator & _"Results.txt"' Удалить копию файла. On Error Resume Next Kill (ThisFile) On Error GoTo 0' Открыть файл. Open ThisFile For Output As #1 FinalRow = Range("A65536").End(xlUp).Row' Экспортировать в файл данные рабочего листа. For j = 1 To FinalRow Print #1, Cells(j, 1).Value Next j Close #1 MsgBox "Файл " & ThisFile & " успешно сохранен."End Sub

Аналогичный способ экспорта данных в текстовый файл применялся в

главе 14, ‘‘Взаимодействие с Internet’’, при создании WebYстраниц.

Следующий шагСкорость импорта и экспорта текстовых файлов оставляет желать лучшего.

В следующей главе рассматривается использование Microsoft Access для обесY

печения быстрого доступа к данным, предусматривающего индексацию и

многопользовательский режим.

Page 488: ? Применение VBA и макросов в Microsoft® Excel
Page 489: ? Применение VBA и макросов в Microsoft® Excel

ADO и DAO .................................... 490Объекты ADO ............................... 492Добавление записи втаблицу Access ............................. 493Извлечение записей изтаблицы Access ............................ 494Обновление записей таблицыAccess ............................................. 496Удаление записей таблицыAccess ............................................. 499Создание итоговыхзапросов ........................................ 499Несколько полезныхмакросов ....................................... 500Следующий шаг........................... 503

19Глава 19

ÈñïîëüçîâàíèåMicrosoft Access

В предыдущей главе был предлоY

жен метод, позволяющий хранить на

одном рабочем листе Excel свыше

650 000 строк данных. Тем не менее,

на некотором этапе становится очеY

видно, что для хранения больших

объемов данных следует применять

специализированный инструмент,

такой как Microsoft Access. ОсновY

ным форматом файлов Microsoft AcY

cess является формат MDB (MulY

tidimensional Database — многомерY

ная база данных).

Использование MDBYфайлов моY

жет быть оправдано необходимостью

обеспечения совместного доступа к

данным. Предоставление общего досY

тупа к рабочей книге связано с множеY

ством ограничений. В частности, досY

туп к следующим функциям возможен

только при запрете совместного досY

тупа к книге:

автоматическая вставка проY

межуточных итогов;

создание сводных таблиц;

группировка и структурироваY

ние данных;

создание, изменение и проY

смотр сценариев;

защита листов и книг, а также

снятие защиты;

добавление и изменение усY

ловного форматирования;

вставка и изменение рисунков

и других объектов;

Page 490: ? Применение VBA и макросов в Microsoft® Excel

490 Часть III Удивительные возможности Visual Basic for Applications

создание и изменение диаграмм или отчетов сводных диаграмм;

удаление рабочих листов.

Применение Excel в качестве пользовательского интерфейса, а MDBY

файла YYYY в качестве базы данных позволяет добиться оптимального использоY

вания возможностей обоих программ.

На заметку Формат файлов MDB является официальным форматом файлов как Microsoft Ac&cess, так и Microsoft Visual Basic for Applications. Это позволяет разрабатыватьMDB&ориентированные макросы, предназначенные для выполнения на компью&терах без установленной копии Microsoft Access. Тем не менее, создание таблиц изапросов Access возможно только с помощью пользовательского интерфейса этойпрограммы.

ADO и DAOНа протяжении нескольких лет для доступа к данным, хранящимся во

внешних источниках, Microsoft рекомендовала использовать объекты DAO

(Data Access Objects — объекты доступа к данным). Начиная с Excel 2000 и

VBA 6 Microsoft смещает акцент на объекты ADO (ActiveX Data Objects —

объекты данных ActiveX), при этом продолжая обеспечивать поддержку DAO.

Обе парадигмы доступа к данным весьма похожи и имеют незначительно отY

личающийся синтаксис. Во всех примерах этой главы доступ к данным будет

осуществляться с помощью объектов ADO. Более подробно отличия между

ADO и DAO рассматриваются в статье базы знаний Microsoft, которую вы

найдете по адресу:

http://support.microsoft.com/default.aspx?scid=KB;EN-US;q225048&

Прежде чем перейти к созданию макросов, использующих ADO, выберите

в меню редактора Visual Basic команду Tools References (Сервис Ссылки) и

установите флажок, соответствующий библиотеке Microsoft ActiveX Data ObY

jects, как показано на рис. 19.1. Щелкните на кнопке OK, чтобы закрыть диаY

логовое окно References (Ссылки).

Практикум

Совместный доступ к MDB-файлуРассмотрим следующую задачу. Предположим, что пользователь А и пользова&тель Б ответственны за закупку товаров для сети розничных магазинов. Каждое ут&ро они импортируют данные из журнала кассовых операций, чтобы получить ин&формацию о вчерашних продажах и, при необходимости, перераспределить ос&таток товаров между магазинами. Необходимо сделать так, чтобы пользователь Амог видеть перемещения товаров, инициированные пользователем Б, и наоборот.

Page 491: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 491

Рис. 19.1. Для доступа к содержимому MDB&файла с по&мощью объектов ADO используется библиотека Micro&soft ActiveX Data Objects

На компьютерах обоих пользователей установлена копия Excel с поддержкой VBA.Импортированные данные обрабатываются макросами, в результате выполнениякоторых создаются сводные таблицы, облегчающие принятие решений о необхо&димости закупки товаров.Попытка хранения данных о перемещениях товаров в рабочей книге Excel обрече&на на провал. Монопольный режим доступа не позволяет изменять файл рабочейкниги нескольким пользователям одновременно. С другой стороны, режим со&вместного доступа исключает возможность создания сводных таблиц.Следует отметить, что на компьютерах обоих пользователей нет установленнойкопии Microsoft Access.Решение поставленной задачи приведено ниже.1. С помощью копии Microsoft Access, установленной на другом компьютере, создайте

базу данных Transfers.mdb и добавьте в нее таблицу tblTransfer, как показанона рис. 19.2.

2. Разместите файл Transfers.mdb на сетевом диске, доступном с компьютеровобоих пользователей.

3. Подключите библиотеку Microsoft ActiveX Data Objects на компьютерах обоихпользователей.

4. Поместите путь к файлу Transfers.mdb в рабочие книги пользователей А и Б,присвоив соответствующей ячейке имя TPath.

5. Для работы с данными, хранящимися в таблице tblTransfer, используйтекод, приводящийся в следующих разделах этой главы.

Access поддерживает общий доступ к данным. Это означает, что пользователь А ипользователь Б могут просматривать или изменять таблицу tblTransfer одно&временно. Единственным условием для возникновения конфликтной ситуации яв&

Page 492: ? Применение VBA и макросов в Microsoft® Excel

492 Часть III Удивительные возможности Visual Basic for Applications

ляется попытка совместного изменения пользователями А и Б одной и той же за&писи таблицы.

Рис. 19.2. Таблица tblTransfer предназначена для хранения информации о перемещени&ях товаров и будет доступна для изменения несколькими пользователями одновременно

Объекты ADOДвумя основными объектами ADO являются объект соединения Connec-

tion и объект набора данных Recordset.

Объект соединения определяет путь к базе данных и ее тип. База данных

Microsoft Access основана на ядре Microsoft Jet.

Объект набора данных создается на основе существующего объекта соедиY

нения для представления таблицы, некоторого ее подмножества или предоY

пределенного запроса базы данных Access. Помимо объекта соединения, при

создании объекта набора данных указываются такие параметры, как Cur-sorType, CursorLocation, LockType и Options. Для обеспечения одноY

временного доступа к базе данных двух пользователей рекомендуется примеY

нять динамический курсор и оптимистическую блокировку. При работе с

большими объемами данных установите значение параметра CursorLoca-tion равным adUseServer, что позволит обрабатывать записи в оперативY

ной памяти сервера. В противном случае установите значение параметра Cur-sorLocation равным adUseClient. При создании объекта набора данных

все записи будут скопированы в оперативную память компьютера пользоватеY

ля, что способно существенно ускорить их обработку.

Page 493: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 493

Чтобы скопировать записи из таблицы Access на рабочий лист Excel, восY

пользуйтесь методом Excel VBA CopyFromRecordset.

Чтобы добавить новую запись в таблицу Access, воспользуйтесь методом

AddNew объекта Recordset. Укажите значение каждого поля таблицы и выY

зовите метод Update объекта Recordset для внесения изменений в базу

данных.

Чтобы удалить запись из таблицы Access, отправьте запрос на удаление заY

писи, удовлетворяющий заданному критерию.

Кроме того, средства VBA позволяют проверить существование таблицы

или ее поля, а также добавить новые поля к существующей таблице.

Добавление записи в таблицу AccessПользователи А и Б вводят информацию о перемещениях товаров в форму.

Фактическое добавление записи в таблицу Access возложено на макрос

AddTransfer.

При добавлении записи в таблицу Access макрос AddTransfer выполняет

следующую последовательность действий.

1. Создание объекта соединения.

2. Создание объекта набора данных для обращения к таблице tblTransfer.

3. Вызов метода AddNew для добавления новой записи в таблицу

tblTransfer.

4. Установка значения каждого поля новой записи таблицы tblTransfer.

5. Вызов метода Update для внесения изменений в базу данных.

6. Закрытие объектов набора данных и соединения.

Ниже приведен код метода AddTransfer.

Sub AddTransfer(Style As Variant, FromStore As Variant, _ToStore As Variant, Qty As Integer) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset

MyConn = ThisWorkbook.Path & Application.PathSeparator & _"transfers.mdb"

' Открыть соединение. Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With

' Создать объект набора данных. Set rst = New ADODB.Recordset rst.CursorLocation = adUseServer

Page 494: ? Применение VBA и макросов в Microsoft® Excel

494 Часть III Удивительные возможности Visual Basic for Applications

' Открыть набор данных. rst.Open Source:="tblTransfer", _ ActiveConnection:=cnn, _ CursorType:=adOpenDynamic, _ LockType:=adLockOptimistic, _ Options:=adCmdTable

' Добавить новую запись. rst.AddNew

' Определить значения полей новой записи. Первые 4 поля' задаются пользователем с помощью формы. В поле "Дата"' вносится текущее значение даты. rst("Товар") = Style rst("ИзМагазина") = FromStore rst("ВМагазин") = ToStore rst("Количество") = Qty rst("Дата") = Date rst("Отправлен") = False rst("Получен") = False

' Внести изменения в базу данных. rst.Update

' Закрыть объекты набора данных и соединения. rst.Close cnn.CloseEnd Sub

Извлечение записей из таблицы AccessЧтобы извлечь записи из таблицы Access, определите набор данных, указав в

качестве источника строку SQLYзапроса, задающую требуемый критерий отбора.

Скопировать записи из таблицы Access на рабочий лист Excel поможет меY

тод Excel VBA CopyFromRecordset.

Следующий макрос извлекает из таблицы tblTransfer все записи, в коY

торых значение поля Отправлен равно False, и помещает их на рабочий

лист. Строка frmTransConf.Show выводит на экран пользовательскую форY

му, которая применяется для обновления записей и рассматривается в слеY

дующем разделе.

Sub GetUnsentTransfers() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim WSOrig As Worksheet Dim WSTemp As Worksheet Dim sSQL As String Dim FinalRow As Long

Set WSOrig = ActiveSheet

' Создать SQL-запрос для извлечения записей,' соответствующих неотправленным товарам. sSQL = "SELECT Идентификатор, Товар, ИзМагазина, ВМагазин, _

Page 495: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 495

Количество, Дата FROM tblTransfer" sSQL = sSQL & " WHERE Отправлен=FALSE"

' Задать путь к файлу Transfers.mdb. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With Set rst = New ADODB.Recordset rst.CursorLocation = adUseServer rst.Open Source:=sSQL, ActiveConnection:=cnn, _ CursorType:=AdForwardOnly, LockType:=adLockOptimistic, _ Options:=adCmdText

' Создать новый рабочий лист. Set WSTemp = Worksheets.Add WSTemp.Select Range("A1:F1").EntireColumn.Clear

' Создать строку заголовков. Range("A1:F1").Value = Array("Идентификатор", "Товар", _"ИзМагазина", "ВМагазин", "Количество", "Дата")

' Скопировать записи из набора данных на рабочий лист. Range("A2").CopyFromRecordset rst

' Закрыть набор данных и соединение. rst.Close cnn.Close

' Отформатировать отчет. FinalRow = Range("A65536").End(xlUp).Row

' Удалить временный рабочий лист, если в результате' запроса было возвращено пустое множество записей. If FinalRow = 1 Then Application.DisplayAlerts = False WSTemp.Delete Application.DisplayAlerts = True WSOrig.Activate MsgBox "Неподтвержденных перемещений товаров нет" Exit Sub End If

' Задать формат ячеек столбца F как М.Д.ГГ. Range("F2:F" & FinalRow).NumberFormat = "m/d/y"

' Отобразить форму. frmTransConf.Show

' Удалить временный рабочий лист. Application.DisplayAlerts = False WSTemp.Delete

Page 496: ? Применение VBA и макросов в Microsoft® Excel

496 Часть III Удивительные возможности Visual Basic for Applications

Application.DisplayAlerts = True

End Sub

Метод CopyFromRecordset копирует на рабочий лист Excel только строY

ки с данными, а строку заголовка необходимо создавать вручную. Результат

выполнения макроса GetUnsentTransfers до отображения пользовательY

ской формы показан на рис. 19.3.

Рис. 19.3. Метод CopyFromRecordset копи&рует на рабочий лист Excel результат извлече&ния записей из таблицы tblTransfer

Обновление записей таблицы AccessЧтобы обновить существующую запись таблицы Access, создайте набор

данных, содержащий однуYединственную запись. Обычно для этого необхоY

димо, чтобы пользователь выбрал требуемую запись (а значит и ее уникальY

ный идентификатор YYYY ключ) с помощью формы. Измените значение требуеY

мого поля с помощью свойства Fields и внесите обновленную запись в базу

данных с помощью метода Update.

Рассмотренный ранее макрос GetUnsentTransfers помещает записи

таблицы tblTransfer на рабочий лист, а затем выводит на экран пользоваY

тельскую форму frmTransConf. Метод инициализации формы User-Form_Initialize загружает все записи с текущего рабочего листа в список,

Page 497: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 497

поддерживающий множественный выбор (значение свойства MultiSelectравно True):

Private Sub UserForm_Initialize() OrigBook = ActiveWorkbook.Name

' Загрузить записи в список. FinalRow = Cells(65536, 1).End(xlUp).Row If FinalRow > 1 Then Me.lbXlt.RowSource = "A2:F" & FinalRow End IfEnd Sub

Форма, показанная на рис. 19.4, отображает записи, соответствующие неY

отправленным товарам. Чтобы изменить значение поля Отправлен требуеY

мых записей с False на True, выделите их и щелкните на кнопке

Подтвердить.

Рис. 19.4. Пользовательская форма отобра&жает записи, соответствующие неотправлен&ным товарам (значение поля Отправленравно False). Чтобы отразить факт отправкитоваров в базе данных, выделите требуемыезаписи и щелкните на кнопке Подтвердить

Ниже приведен код, выполняющийся в результате щелчка на кнопке

Подтвердить. Ключевым фрагментом этого кода является создание SQLY

запроса, использующегося для отбора единственной записи таблицы

tblTransfer с помощью поля Идентификатор.

Page 498: ? Применение VBA и макросов в Microsoft® Excel

498 Часть III Удивительные возможности Visual Basic for Applications

Private Sub cbConfirm_Click() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset

' Если в списке не содержится' ни одной записи, вывести сообщение. CountSelect = 0 For x = 0 To Me.lbXlt.ListCount - 1 If Me.lbXlt.Selected(x) Then CountSelect = CountSelect + 1 End If Next x

If CountSelect = 0 Then MsgBox "Перемещаемых товаров нет. Чтобы закрыть форму, _щелкните на кнопке Выход." Exit Sub End If

' Установить соединение с базой данных transfers.mdb. MyConn = ThisWorkbook.Path & Application.PathSeparator & _"transfers.mdb"

Set cnn = New ADODB.Connection

With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With

' Обновить записи таблицы tblTransfer. For x = 0 To Me.lbXlt.ListCount - 1 If Me.lbXlt.Selected(x) Then ThisID = Cells(2 + x, 1).Value' Обновить запись с идентификатором ThisID.' Создать SQL-запрос. sSQL = "SELECT * FROM tblTransfer Where _Идентификатор=" & ThisID Set rst = New ADODB.Recordset With rst .Open Source:=sSQL, ActiveConnection:=cnn, _CursorType:=adOpenKeyset, LockType:=adLockOptimistic' Обновить поле. .Fields("Отправлен").Value = True .Update .Close End With End If Next x

' Закрыть объекты набора данных и соединения. cnn.Close Set rst = Nothing Set cnn = Nothing

' Закрыть пользовательскую форму. Unload Me

End Sub

Page 499: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 499

Удаление записей таблицы AccessЧтобы удалить существующую запись таблицы Access, создайте SQLYкод,

удаляющий запись на основе значения ее уникального идентификатора. УстаY

новите соединение с базой данных и выполните SQLYкод с помощью метода

Execute, как показано ниже:

Public Sub DeleteRecord(RecID)' Установить соединение с базой данных transfers.mdb. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

With New ADODB.Connection .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn .Execute "Delete From tblTransfer Where _Идентификатор = " & RecID .Close End WithEnd Sub

Создание итоговых запросовОдна из многочисленных возможностей Access заключается в создании

итоговых запросов с объединением записей с одинаковыми значениями в укаY

занном списке полей в одну запись. Попробуйте создать итоговый запрос и

просмотрите полученный SQLYкод. Аналогичный запрос можно создать с поY

мощью Excel VBA и передать его на обработку Access с помощью средств бибY

лиотеки ADO.

Следующий макрос выполняет сложный SQLYзапрос, возвращающий чисY

тый итог перемещения товара B10894 по магазинам.

Sub NetTransfers(Style As Variant)' Этот макрос подсчитывает чистый итог' перемещения заданного товара по магазинам. Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset

' Создать сложный SQL-запрос.' Логика запроса: объединить результаты запроса, возвращающего' сумму входящих перемещений указанного товара по магазинам,' с результатами запроса, возвращающего отрицательную сумму' исходящих перемещений указанного товара по магазинам. sSQL = "Select Магазин, Sum(Количество), Min(мДата) From _(SELECT ВМагазин AS Магазин, Sum(Количество) AS Количество, _Min(Дата) AS мДата FROM tblTransfer where Товар='" & Style & "' _AND Получен=FALSE GROUP BY ВМагазин " sSQL = sSQL & " Union All SELECT ИзМагазина AS Магазин, _Sum(-1*Количество) AS Количество, Min(Дата) AS мДата FROM _tblTransfer where Товар='" & Style & "' AND Отправлен=FALSE _GROUP BY ИзМагазина)" sSQL = sSQL & " Group by Магазин"

Page 500: ? Применение VBA и макросов в Microsoft® Excel

500 Часть III Удивительные возможности Visual Basic for Applications

MyConn = ThisWorkbook.Path & Application.PathSeparator & _"transfers.mdb"

' Открыть соединение. Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With Set rst = New ADODB.Recordset rst.CursorLocation = adUseServer

' Выполнить SQL-запрос. rst.Open Source:=sSQL, _ ActiveConnection:=cnn, _ CursorType:=AdForwardOnly, _ LockType:=adLockOptimistic, _ Options:=adCmdText Range("A1:C1").Value = Array("Магазин", "Количество", "Дата")

' Скопировать результаты запроса на рабочий лист. Range("A2").CopyFromRecordset rst

rst.Close cnn.CloseEnd Sub

Несколько полезных макросовВ оставшихся разделах главы рассматриваются несколько полезных функY

ций и макросов, использующих возможности библиотеки ADO. Как отмечаY

лось ранее, пользователи А и Б имеют доступ к базе данных Access, располоY

женной на сетевом диске, но не имеют установленной копии Microsoft Access.

В связи с этим возникает потребность обновления базы данных средствами

VBA, что удобно осуществлять при открытии рабочей книги Excel. Макрос

обновления базы данных можно разместить в надстройке и выполнить при

открытии рабочей книги с помощью обработчика события Workbook_Open(см. главу 25, “Надстройки”).

Проверка существования таблицы в базе данных Access

В одном из следующих разделов рассматривается добавление новой таблиY

цы в существующую базу данных Access. Естественно, что добавить новую

таблицу сможет только один пользователь, тот, кто первым откроет рабочую

книгу и тем самым инициирует выполнение соответствующего макроса.

Функция TableExists проверяет существование таблицы с указанным

именем в базе данных Transfers.mdb с помощью метода OpenSchema.

Function TableExists(WhichTable) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim fld As ADODB.Field

Page 501: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 501

TableExists = False

' Задать путь к базе данных Transfers.mdb. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With

Set rst = cnn.OpenSchema(adSchemaTables)

Do Until rst.EOF If LCase(rst!Table_Name) = LCase(WhichTable) Then TableExists = True GoTo ExitMe End If rst.MoveNext Loop

ExitMe: rst.Close Set rst = Nothing

' Закрыть соединение. cnn.CloseEnd Function

Проверка существования поля в таблицебазы данных Access

В одном из следующих разделов рассматривается добавление нового поля в

таблицу базы данных Access. Функция ColumnExists проверяет существоваY

ние поля с указанным именем в заданной таблице базы данных Trans-fers.mdb.

Function ColumnExists(WhichColumn, WhichTable) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim WSOrig As Worksheet Dim WSTemp As Worksheet Dim fld As ADODB.Field ColumnExists = False

' Задать путь к базе данных Transfers.mdb. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With

Page 502: ? Применение VBA и макросов в Microsoft® Excel

502 Часть III Удивительные возможности Visual Basic for Applications

Set rst = cnn.OpenSchema(adSchemaColumns)

Do Until rst.EOF If LCase(rst!Column_Name) = LCase(WhichColumn) And _ LCase(rst!Table_Name) = LCase(WhichTable) Then ColumnExists = True GoTo ExitMe End If rst.MoveNext Loop

ExitMe: rst.Close Set rst = Nothing' Закрыть соединение. cnn.CloseEnd Function

Добавление таблицы в базу данных Access

Следующий макрос добавляет таблицу tblReplenish в базу данных

Transfers.mdb с помощью команды SQL CREATE TABLE.

Sub ADOCreateReplenish()' Этот макрос создает таблицу tblReplenish' в базе данных Transfers.mdb.' Таблица tblReplenish имеет 5 полей.' 1. Товар.' 2. Кат1 - минимальный уровень запасов товара' магазинов 1-й категории.' 3. Кат2 - минимальный уровень запасов товара' магазинов 2-й категории.' 4. Кат3 - минимальный уровень запасов товара' магазинов 3-й категории.' 5. Активна - поле "Да/Нет". Dim cnn As ADODB.Connection Dim cmd As ADODB.Command

' Задать путь к базе данных. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

' Открыть соединение. Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With Set cmd = New ADODB.Command Set cmd.ActiveConnection = cnn

' Создать таблицу. cmd.CommandText = "CREATE TABLE tblReplenish (Товар Char(10) _Primary Key, Кат1 int, Кат2 int, Кат3 Int, Активна YesNo)" cmd.Execute , , adCmdText Set cmd = Nothing

Page 503: ? Применение VBA и макросов в Microsoft® Excel

Использование Microsoft Access Глава 19 503

Set cnn = Nothing Exit SubEnd Sub

Добавление поля в таблицу базы данных Access

Следующий макрос добавляет поле Группа в таблицу tblReplenish баY

зы данных Transfers.mdb с помощью команды SQL ALTER TABLE.

Sub ADOAddField()' Этот макрос добавляет поле Группа к таблице tblReplenish. Dim cnn As ADODB.Connection Dim cmd As ADODB.Command' Задать путь к базе данных. MyConn = ThisWorkbook.Path & Application.PathSeparator _& "transfers.mdb"

' Открыть соединение. Set cnn = New ADODB.Connection With cnn .Provider = "Microsoft.Jet.OLEDB.4.0" .Open MyConn End With

Set cmd = New ADODB.Command Set cmd.ActiveConnection = cnn' Добавить поле в таблицу tblReplenish. cmd.CommandText = "ALTER TABLE tblReplenish Add Column _Группа Char(25)" cmd.Execute , , adCmdText Set cmd = Nothing Set cnn = NothingEnd Sub

Следующий шагСледующая глава посвящена созданию модулей классов, предназначенных

для размещения пользовательских объектов.

Page 504: ? Применение VBA и макросов в Microsoft® Excel
Page 505: ? Применение VBA и макросов в Microsoft® Excel

Создание модуля класса ........... 506Обработка событий уровняприложения и встроеннойдиаграммы ................................... 506Создание пользовательскогообъекта ........................................... 510Применениепользовательского объектана практике ....................................511Использование выраженийProperty Let и Property Get.......... 513Коллекции ..................................... 515Создание пользовательскихтипов .............................................. 520Следующий шаг........................... 524

20Глава 20

Ñîçäàíèåïîëüçîâàòåëü-ñêèõ îáúåêòîâ,òèïîâè êîëëåêöèé

Несмотря на все разнообразие

встроенных объектов Excel, в некоY

торых ситуациях наиболее оптиY

мальным решением является создаY

ние собственного объекта, преднаY

значенного для выполнения узкоY

специализированной задачи. Excel

поддерживает создание пользоваY

тельских объектов в так называеY

мых модулях классов.

Ранее в этой книге рассматриваY

лись ‘‘улучшенные’’ модули классов,

такие как модуль рабочей книги, раY

бочего листа, диаграммы и пользоваY

тельской формы. Каждому из этих

модулей свойственны характеристиY

ки, уникальные для соответствуюY

щего типа объектов. В частности, это

касается обработчиков событий.

Кроме размещения пользовательY

ских объектов с соответствующими

свойствами и методами, классы моY

дулей могут включать в себя код обY

работчиков событий уровня прилоY

жения, встроенной диаграммы, элеY

мента управления ActiveX и др.

Page 506: ? Применение VBA и макросов в Microsoft® Excel

506 Часть III Удивительные возможности Visual Basic for Applications

Создание модуля класса Чтобы добавить модуль класса к текущему проекту, выберите в меню реY

дактора Visual Basic команду Insert Class Module (Вставить Модуль класса).

Excel добавит новый модуль класса Class1, разместив его в папке ClassModules (Модули классов) текущего проекта, как показано на рис. 20.1.

Рис. 20.1. Пользовательские объектыразмещаются в модулях классов

При работе с пользовательскими объектами необходимо помнить следуюY

щие ключевые моменты.

Каждый пользовательский объект должен размещаться в отдельном

модуле класса. (Обработчики событий пользовательских объектов моY

гут размещаться в одном модуле класса.)

Модуль класса необходимо переименовать в соответствии с именем

размещенного в нем пользовательского объекта.

Обработка событий уровня приложенияи встроенной диаграммы

В главе 8, ‘‘События’’, рассматривалась обработка событий уровня рабочей

книги, рабочего листа и листа диаграммы. Там же описывалось создание моY

дуля класса для размещения кода обработки событий приложения и встроенY

ной диаграммы. Более подробно тема обработки событий уровня приложения

и встроенной диаграммы рассматривается в следующих разделах.

Page 507: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 507

События уровня приложения

Событие уровня рабочей книги Workbook_BeforePrint срабатывает при

попытке печати конкретной рабочей книги. Чтобы обеспечить одинаковую

обработку события Workbook_BeforePrint в нескольких рабочих книгах,

скопируйте соответствующий программный код в каждую книгу или воспольY

зуйтесь событием уровня приложения WorkbookBeforePrint.

События уровня приложения охватывают все рабочие книги, открытые в

рамках текущего сеанса работы с Excel. Для доступа к событиям уровня приY

ложения необходимо использовать модуль класса, как показано ниже.

1. Добавьте модуль класса к текущему проекту. Присвойте модулю какоеY

нибудь значащее имя, например, clsAppEvents.

На заметку Чтобы переименовать модуль, выберите в меню редактора Visual Basic командуView Properties Window (Вид Окно свойств).

2. Разместите в модуле класса следующую строку кода:

Public WithEvents xlApp As Application

Имя используемой переменной (в данном случае xlApp) может быть

любым. Ключевое слово WithEvents делает доступными события

объекта Application на уровне модуля clsAppEvents.

3. В результате выполнения предыдущего шага переменная xlApp станет

доступной из раскрывающегося списка Object (Объект) редактора Visual

Basic. После выбора переменной xlApp из раскрывающегося списка

Object в расположенном рядом раскрывающемся списке Procedure(Процедура) появятся события, соответствующие типу объекта этой пеY

ременной (в данном случае Application), как показано на рис. 20.2.

Рис. 20.2. Выбор объекта из раскрывающегося списка Object делает доступными соответст&вующие типу этого объекта события

См. также События уровня приложения рассматриваются в главе 8, “События”, на с. 208.

Page 508: ? Применение VBA и макросов в Microsoft® Excel

508 Часть III Удивительные возможности Visual Basic for Applications

Для каждого события, перечисленного в раскрывающемся списке Procedure,

можно создать собственный код обработки. Ниже приведен код обработки соY

бытия NewWorkbook, создающий нижний колонтитул рабочей книги. Код обY

работчика xlApp_NewWorkbook следует поместить в модуль класса clsApp-Events после строки, содержащей объявление переменной xlApp.

Private Sub xlApp_NewWorkbook(ByVal Wb As Workbook) Dim wks As Worksheet On Error Resume Next With Wb For Each wks In .Worksheets wks.PageSetup.LeftFooter = "Создано: " & _.Application.UserName wks.PageSetup.RightFooter = Now Next wks End WithEnd Sub

В отличие от обработчиков событий уровня рабочей книги или рабочего

листа, процедура, размещенная в модуле класса, не вызывается автоматичеY

ски. Создайте экземпляр класса clsAppEvents и установите значение его

свойства xlApp равным Application, как показано ниже.

Public myAppEvent As clsAppEvents

Sub TrapAppEvent() Set myAppEvent.xlApp = ApplicationEnd Sub

После выполнения процедуры TrapAppEvent обработчик xlApp_New-Workbook будет формировать нижний колонтитул для каждой новой рабочей

книги, созданной в рамках текущего сеанса работы с Excel (рис. 20.3).

Рис. 20.3. Обработка события уровня приложения NewWorkbook позволяет формироватьнижний колонтитул для каждой новой рабочей книги, созданной в рамках текущего сеан&са работы с Excel

Внимание Обработка событий уровня приложения может быть приостановлена вследствиевыполнения действий, приводящих к обнулению значений переменных модуля.В частности, к таким действиям относится изменение программного кода в ре&дакторе Visual Basic. Чтобы возобновить обработку событий уровня приложения,воссоздайте соответствующие объекты (в данном случае для этого достаточно вы&полнить процедуру TrapAppEvent).

Page 509: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 509

Объявление переменной myAppEvent, а также процедура TrapAppEventразмещены в стандартном модуле. Чтобы автоматизировать обработку собыY

тия уровня приложения, модули классов можно перенести в личную книгу мак*росов (PERSONAL.XLS), а вызов процедуры TrapAppEvent — в обработчик

события Workbook_Open. Объявление переменной myAppEvent должно остаY

ваться в стандартном модуле, чтобы переменная была доступна другим модулям.

События встроенной диаграммы

Обработка событий встроенной диаграммы аналогична обработке событий

уровня приложения. Добавьте модуль класса и разместите в нем объявление

общедоступной переменной типа Char. Затем создайте код обработки требуеY

мого события и разместите в стандартном модуле процедуру, инициирующую

обработку событий встроенной диаграммы.

На заметку Код обработки событий уровня приложения и событий встроенной диаграммыможно размещать в одном и том же модуле класса.

Разместите в модуле класса следующую строку кода:

Public WithEvents xlChart As Chart

Переменная xlChart станет доступной из раскрывающегося списка

Object (Объект) редактора Visual Basic. После выбора переменной xlChart из

раскрывающегося списка Object в расположенном рядом раскрывающемся

списке Procedure (Процедура) появятся события, соответствующие типу

объекта этой переменной (в данном случае Chart), как показано на рис. 20.4.

Рис. 20.4. Выбор переменной xlChart из раскрывающегося списка Object делает доступнымисобытия встроенной диаграммы

См. также События уровня листа диаграммы рассматриваются в главе 8, “События”, на с. 204.

Создадим обработчик события MouseDown, изменяющий масштаб диаY

граммы при щелчке на ее области кнопкой мыши. Для этого потребуется пеY

Page 510: ? Применение VBA и макросов в Microsoft® Excel

510 Часть III Удивительные возможности Visual Basic for Applications

реопределить стандартный способ обработки еще двух событий YYYY Before-RightClick и BeforeDoubleClick.

Следующий код предотвращает выполнение стандартных действий, предY

принимаемых при обработке двойного щелчка и щелчка правой кнопкой мыши:

Private Sub xlChart_BeforeDoubleClick(ByVal ElementID As Long, _ ByVal Arg1 As Long, ByVal Arg2 As Long, Cancel As Boolean) Cancel = TrueEnd Sub

Private Sub xlChart_BeforeRightClick(Cancel As Boolean) Cancel = TrueEnd Sub

Определим способ обработки события, срабатывающего в результате нажаY

тия любой кнопки мыши.

Private Sub xlChart_MouseDown(ByVal Button As Long, _ByVal Shift As Long, ByVal x As Long, ByVal y As Long) If Button = 1 Then ActiveChart.Axes(xlValue).MaximumScale = _ ActiveChart.Axes(xlValue).MaximumScale - 50 End If If Button = 2 Then ActiveChart.Axes(xlValue).MaximumScale = _ ActiveChart.Axes(xlValue).MaximumScale + 50 End IfEnd Sub

Создайте экземпляр класса clsChartEvents и установите значение его

свойства xlChart, как показано ниже (рис. 20.5).

Public myChartEvent As clsChartEvents

Sub TrapChartEvent() Set myChartEvent.xlChart = Worksheets("Встроенная _диаграмма").ChartObjects("Chart 1").ChartEnd Sub

Создание пользовательского объектаКроме кода обработчиков событий, модули классов могут содержать польY

зовательские объекты с определением соответствующих свойств и методов.

Создадим объект служащего с такими характеристиками, как имя, идентифиY

катор, тарифная ставка и количество рабочих часов.

Добавьте модуль класса и переименуйте его в clsEmployee. Ниже переY

числены свойства объекта clsEmployee.

EmpName — имя служащего;

EmpID — идентификатор служащего;

EmpRate — тарифная ставка;

EmpWeeklyHrs — количество рабочих часов в неделю.

Page 511: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 511

Рис. 20.5. Обработка событий встроенной диаграммы реализуется посредством использова&ния модуля класса

При объявлении свойств и переменных указывается область видимости YYYY

обычно Private или Public. Поскольку свойства объекта clsEmployeeдолжны быть доступны из стандартного модуля, сделайте их общими, размесY

тив следующие строки в начале модуля класса:

Public EmpName As StringPublic EmpID As StringPublic EmpRate As DoublePublic EmpWeeklyHrs As Double

Методы объекта YYYY это ‘‘действия’’, которые он может выполнять. В модуY

ле класса ‘‘действия’’ объекта представлены процедурами и функциями. СлеY

дующий метод подсчитывает недельную заработную плату служащего:

Public Function EmpWeeklyPay() As Double EmpWeeklyPay = EmpRate*EmpWeeklyHrsEnd Function

Создание объекта clsEmployee, содержащего четыре свойства и один меY

тод, можно считать завершенным. В следующем разделе рассматривается

применение пользовательского объекта на практике.

Применение пользовательского объектана практике

Пользовательский объект, корректно заданный в модуле класса, становитY

ся доступным для других модулей. Ниже приведен пример объявления переY

менной типа clsEmployee:

Dim Employee As clsEmployee

Следующий код создает экземпляр пользовательского объекта:

Set Employee = New clsEmployee

Page 512: ? Применение VBA и макросов в Microsoft® Excel

512 Часть III Удивительные возможности Visual Basic for Applications

При разработке программного кода Excel отображает динамические подY

сказки, упрощающие обращение к свойствам и методам пользовательского

объекта (рис. 20.6).

Рис. 20.6. В аспекте отображения динамическихподсказок пользовательские объекты ничем неотличаются от стандартных объектов Excel

Приведенный ниже код наглядно демонстрирует применение пользоваY

тельского объекта на практике.

Option Explicit

Dim Employee As clsEmployee

Sub EmpPay()

Set Employee = New clsEmployee

With Employee .EmpName = "Трейси Сирстад" .EmpID = "1651" .EmpRate = 25 .EmpWeeklyHrs = 40 MsgBox .EmpName & " зарабатывает в неделю " & _.EmpWeeklyPay & " долларов."End With

End Sub

Макрос EmpPay создает экземпляр пользовательского объекта clsEm-ployee и задает значения всех его свойств. После этого макрос выводит на

экран сообщение, содержащее сведения о недельной заработной плате слуY

жащего, как показано на рис. 20.7.

Page 513: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 513

Рис. 20.7. При подсчете недельной за&работной платы служащего использует&ся метод EmpWeeklyPay объекта cls-Employee

Использование выражений Property Letи Property Get

Значения общедоступных переменных (таких как EmpName, EmpID, Emp-Rate и EmpWeeklyHrs) можно считывать и изменять произвольным образом.

Если доступ к свойствам объекта необходимо ограничить, воспользуйтесь выY

ражениями Property Let и Property Get.

Выражение Property Let позволяет управлять изменением свойств объекY

та, а выражение Property Get — считыванием этих свойств. В рассмотренY

ном ранее примере для хранения информации о количестве рабочих часов в

неделю использовалась общедоступная переменная EmpWeeklyHrs, что не

позволяло вести учет сверхурочных часов.

Внесем изменения в модуль класса, добавив к объекту clsEmployee два

новых свойства YYYY EmpNormalHrs и EmpOverTimeHrs. Поскольку эти свойY

ства должны быть доступны только для чтения, их нельзя реализовать с поY

мощью переменных с областью видимости Public. Вместо этого воспользуY

емся выражением Property Get.

Установка значения свойств EmpNormalHrs и EmpOverTimeHrs будет

производиться с помощью свойства EmpWeeklyHrs, которое также нельзя

реализовать в виде общедоступной переменной. Создадим две закрытые переY

менные NormalHrs и OverHrs, доступные для считывания и изменения исY

ключительно в пределах модуля класса.

Public EmpName As StringPublic EmpID As StringPublic EmpRate As Double

Private NormalHrs As DoublePrivate OverHrs As Double

Выражение Property Let позволяет использовать свойство EmpWeek-lyHrs для установки значения закрытых переменных NormalHrs и OverHrs.

Property Let EmpWeeklyHrs(Hrs As Double) NormalHrs = WorksheetFunction.Min(40, Hrs) OverHrs = WorksheetFunction.Max(0, Hrs - 40)End Property

Page 514: ? Применение VBA и макросов в Microsoft® Excel

514 Часть III Удивительные возможности Visual Basic for Applications

Выражение Property Get EmpWeeklyHrs определяет результат считыY

вания значения свойства EmpWeeklyHrs как сумму переменных NormalHrsи OverHrs.

Property Get EmpWeeklyHrs() As Double EmpWeeklyHrs = NormalHrs + OverHrsEnd Property

Выражение Property Get используется для определения результатов

считывания значений свойств EmpNormalHrs и EmpOverTimeHrs, как покаY

зано ниже:

Property Get EmpNormalHrs() As Double EmpNormalHrs = NormalHrsEnd Property

Property Get EmpOverTimeHrs() As Double EmpOverTimeHrs = OverHrsEnd Property

Поскольку свойства EmpNormalHrs и EmpOverTimeHrs должны быть

доступны только для чтения, их значения устанавливаются неявно посредстY

вом свойства EmpWeeklyHrs.

Наконец, ниже приведен код обновленного метода EmpWeeklyPay:

Public Function EmpWeeklyPay() As Double EmpWeeklyPay = (EmpNormalHrs * EmpRate) + _(EmpOverTimeHrs * EmpRate * 1.5)End Function

Макрос EmpPayOverTime использует преимущества, полученные в реY

зультате внесения изменений в модуль класса.

Option Explicit

Dim Employee As clsEmployee

Sub EmpPayOverTime()

Set Employee = New clsEmployee

With Employee .EmpName = "Трейси Сирстад" .EmpID = "1651" .EmpRate = 25 .EmpWeeklyHrs = 45 MsgBox .EmpName & Chr(10) & Chr(9) & _ "Стандартные часы: " & .EmpNormalHrs & Chr(10) & Chr(9) & _ "Сверхурочные часы: " & .EmpOverTimeHrs & Chr(10) & Chr(9) & _ "Заработная плата за неделю (долларов): " & .EmpWeeklyPayEnd With

End Sub

Результат выполнения макроса EmpPayOverTime показан на рис. 20.8.

Page 515: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 515

Рис. 20.8. Выражения Property Let иProperty Get позволяют ограничитьдоступ к свойствам пользовательскогообъекта

КоллекцииКоллекция предназначена для представления нескольких экземпляров

объекта. Например, объект Worksheet входит в коллекцию Worksheets.

Коллекция позволяет обращаться к любому ее элементу, подсчитывать общее

количество элементов в коллекции, а также удалять и добавлять элементы.

Аналогичная функциональность доступна для пользовательских объектов.

Существует два способа создания коллекции: в стандартном модуле и в моY

дуле класса.

Создание коллекции в стандартном модуле

Самый простой способ создания коллекции заключается в ее размещении

в стандартном модуле и использовании встроенного объекта VBA Collec-tion. Это позволяет получить доступ к четырем основным методам и свойстY

вам коллекции: Add, Remove, Count и Item.

Следующий макрос считывает список служащих с рабочего листа и помеY

щает их в массив. В результате обработки полученного массива создается колY

лекция пользовательских объектов clsEmployee.

Sub EmpPayCollection() Dim colEmployees As New Collection Dim recEmployee As New clsEmployee Dim LastRow As Integer, myCount As Integer Dim EmpArray As Variant

LastRow = ActiveSheet.Range("A65536").End(xlUp).Row EmpArray = ActiveSheet.Range(Cells(1, 1), Cells(LastRow, 4))

For myCount = 1 To UBound(EmpArray) With recEmployee .EmpName = EmpArray(myCount, 1) .EmpID = EmpArray(myCount, 2) .EmpRate = EmpArray(myCount, 3) .EmpWeeklyHrs = EmpArray(myCount, 4) colEmployees.Add recEmployee, .EmpID End With Next myCount

Page 516: ? Применение VBA и макросов в Microsoft® Excel

516 Часть III Удивительные возможности Visual Basic for Applications

MsgBox "Общее число служащих: " & colEmployees.Count & _Chr(10) & "Имя 2-го служащего в коллекции: " & _colEmployees(2).EmpName

MsgBox "Недельная заработная плата Трейси (долларов): " & _colEmployees("1651").EmpWeeklyPay

Set recEmployee = Nothing

End Sub

Коллекция colEmployees создается как экземпляр объекта Collection,

а ее элементы (recEmployee) YYYY как экземпляры пользовательского объекта

clsEmployee.

После задания значений всех свойств объект recEmployee добавляется в

коллекцию. Второй параметр метода Add определяет уникальный ключ запиY

си в коллекции YYYY в данном случае это идентификатор служащего. Наличие

уникального ключа позволяет использовать сокращенную форму обращения к

записи, например, colEmployees("1651").EmpWeeklyPay (рис. 20.9).

Рис. 20.9. Уникальный ключ позволяет использо&вать сокращенную форму обращения к записи вколлекции

На заметку Уникальный ключ записи является необязательным параметром метода Add. В од&ной коллекции не могут существовать две записи с одинаковым значением уни&кального ключа. При попытке добавления записи, приводящей к дублированиюуникальных ключей, будет сгенерировано сообщение об ошибке.

Создание коллекции в модуле класса

При создании коллекции в модуле класса ее основные методы и свойства

(Add, Remove, Count и Item) необходимо определять самостоятельно. ПреY

имущества этого способа создания коллекции заключаются в размещении коY

да коллекции в одном модуле, возможности полного контроля над ее

‘‘поведением’’, а также возможности управления доступом к коллекции.

Добавьте к текущему проекту новый модуль класса и переименуйте его в

clsEmployees. Объявите закрытую переменную типа Collection, которая

будет использоваться только в пределах данного модуля класса.

Private AllEmployees As New Collection

Page 517: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 517

Определите основные свойства и методы коллекции. Для этого воспольY

зуйтесь соответствующими свойствами и методами объекта Collection,

доступными в пределах модуля clsEmployees.

Следующий код определяет метод добавления новых элементов в коллекY

цию Add.

Public Sub Add(recEmployee As clsEmployee) AllEmployees.Add recEmployee, recEmployee.EmpIDEnd Sub

Свойство Count возвращает общее число элементов в коллекции.

Public Property Get Count() As Long Count = AllEmployees.CountEnd Property

Свойство Items используется для обращения ко всей коллекции.

Public Property Get Items() As Collection Set Items = AllEmployeesEnd Property

Свойство Item предназначено для обращения к отдельному элементу колY

лекции.

Public Property Get Item(myItem As Variant) As clsEmployee Set Item = AllEmployees(myItem)End Property

Наконец, метод Remove предназначен для удаления из коллекции заданY

ного элемента.

Public Sub Remove(myItem As Variant) AllEmployees.Remove myItemEnd Sub

При необходимости функциональность основных методов коллекции

можно улучшить, например, реализовать автоматическое создание уникальY

ного ключа записи в методе Add.

Предназначенные только для чтения свойства Count, Items и Item опреY

деляются с помощью выражения Property Get. Свойство Item позволяет

обратиться к одному элементу коллекции, а свойство Items — ко всей колY

лекции целиком (в частности, это свойство удобно применять в цикле ForEach...Next).

Следующий макрос аналогичен рассмотренному ранее макросу EmpPayCol-lection за исключением того, что теперь коллекция пользовательских объектов

clsEmployee размещается не в стандартном модуле, а в модуле класса.

Sub EmpAddCollection() Dim colEmployees As New clsEmployees Dim recEmployee As New clsEmployee Dim LastRow As Integer, myCount As Integer Dim EmpArray As Variant

LastRow = ActiveSheet.Range("A65536").End(xlUp).Row EmpArray = ActiveSheet.Range(Cells(1, 1), Cells(LastRow, 4))

For myCount = 1 To UBound(EmpArray)

Page 518: ? Применение VBA и макросов в Microsoft® Excel

518 Часть III Удивительные возможности Visual Basic for Applications

With recEmployee .EmpName = EmpArray(myCount, 1) .EmpID = EmpArray(myCount, 2) .EmpRate = EmpArray(myCount, 3) .EmpWeeklyHrs = EmpArray(myCount, 4) End With colEmployees.Add recEmployee Next myCount

MsgBox "Общее число служащих: " & colEmployees.Count & _Chr(10) & "Имя 2-го служащего в коллекции: " & _colEmployees.Item(2).EmpName

MsgBox "Недельная заработная плата Трейси (долларов): " & _colEmployees.Item("1651").EmpWeeklyPay

For Each recEmployee In colEmployees.Items recEmployee.EmpRate = recEmployee.EmpRate * 1.5 Next recEmployee MsgBox "Недельная заработная плата Трейси с премиальными _(долларов): " & colEmployees.Item("1651").EmpWeeklyPayEnd Sub

Обратите внимание, что переменная colEmployees имеет тип clsEm-ployees, а не тип Collection. Способ заполнения массива и коллекции осY

тался прежним, а вот способ обращения к элементам коллекции претерпел

некоторые изменения. В частности, для обращения ко второму элементу колY

лекции необходимо использовать свойство Item. Сравните вызовы метода

MsgBox в макросах EmpPayCollection и EmpAddCollection.

Цикл For Each...Next используется для увеличения значения свойства

EmpRate всех записей коллекции в 1,5 раза. Результат последнего вызова меY

тода MsgBox в макросе EmpAddCollection показан на рис. 20.10.

Рис. 20.10. При создании коллекции в модуле класса ееметоды и свойства необходимо определять самостоятельно

Практикум

Кнопки получения справочной информацииРассмотрим задачу предоставления справочной информации по содержимомурабочего листа. Несмотря на то, что ее наиболее очевидное решение заключаетсяв использовании примечаний ячеек, это может смутить новичка Excel. Другой спо&

Page 519: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 519

соб состоит в создании кнопок, щелчок на каждой из которых приводит к отобра&жению формы, содержащей справочные сведения.Разместите на рабочем листе три небольшие надписи, содержащие знак вопроса(по одной надписи на строку). Внешний вид надписей, показанных на рис. 20.11,был достигнут за счет установки значения свойства надписи SpecialEffect рав&ным fmSpecialEffectRaised, а свойства BackColor — равным Button Face.Поместите текст справки на два столбца правее соответствующей этому текстукнопки (надписи), после чего скройте столбец справочной информации.

Рис. 20.11. Разместите на рабочем листе кнопки (надписи) и соответствующую им справоч&ную информацию

Создайте пользовательскую форму, содержащую надпись и кнопку Закрытьсправку, как показано на рис. 20.12.

Рис. 20.12. Создайте пользовательскую

форму, которая будет применяться длявывода справочной информации на экран

Переименуйте форму в HelpForm, кнопку — в CloseHelp, а надпись — вHelpText. Измените размер надписи таким образом, чтобы в ней мог поместить&ся текст справки. Следующий макрос выгружает форму HelpForm из памяти прищелчке на кнопке CloseHelp.Private Sub CloseHelp_Click() Unload MeEnd Sub

Добавьте к проекту модуль класса clsLabel. Объявите переменную Lbl для об&ращения к событиям объекта Label.Public WithEvents Lbl As MSForms.Label

Следующая процедура выводит на экран пользовательскую форму с соответст&вующим текстом справки.Private Sub Lbl_Click() Dim Rng As Range

Page 520: ? Применение VBA и макросов в Microsoft® Excel

520 Часть III Удивительные возможности Visual Basic for Applications

Set Rng = Lbl.TopLeftCell If Lbl.Caption = "?" Then HelpForm.Caption = "Надпись в ячейке " & Rng.Address(0, 0) HelpForm.HelpText.Caption = Rng.Offset(, 2).Value HelpForm.Show End IfEnd Sub

Разместите в модуле ЭтаКнига (ThisWorkbook) следующий код:Dim col As Collection

Private Sub DefineLabels() Dim WS As Worksheet Dim cLbl As clsLabel Dim OleObj As OLEObject

Set col = New Collection For Each WS In ThisWorkbook.Worksheets For Each OleObj In WS.OLEObjects If OleObj.OLEType = xlOLEControl Then If TypeName(OleObj.Object) = "Label" Then Set cLbl = New clsLabel Set cLbl.Lbl = OleObj.Object col.Add cLbl End If End If Next OleObj Next WSEnd Sub

Выполните процедуру DefineLabels для создания коллекции кнопок получениясправочной информации. Результат щелчка на одной из таких кнопок показан нарис. 20.13.

Рис. 20.13. Результат щелчка на кнопке получения справочной информации

Создание пользовательских типовВ отличие от пользовательских объектов, пользовательские типы не требуY

ют своего размещения в модуле класса. Модуль класса позволяет определить

свойства и методы объекта, тогда как пользовательский тип характеризуется

только свойствами.

Page 521: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 521

Пользовательский тип объявляется с помощью выражения Type...EndType и может быть общедоступным (Public) или закрытым (Private). ПоY

добно объекту, у пользовательского типа есть имя и свойства, которые задаются

с помощью переменных, объявленных внутри выражения Type...End Type.

Применение пользовательских типов на практике ничем не отличается от

применения стандартных типов VBA. Как показано на рис. 20.14, Excel отоY

бражает динамическую подсказку, упрощающую обращение к свойствам пеY

ременной пользовательского типа при наборе программного кода.

Рис. 20.14. Применение пользовательских ти&пов на практике ничем не отличается от приме&нения стандартных типов VBA

Рассмотрим применение двух пользовательских типов для создания отчета

о продажах товаров в сети розничных магазинов.

Тип Style используется для представления товара.

Public Type Style StyleName As String Price As Single UnitsSold As Long UnitsOnHand As LongEnd Type

Тип Store имеет два свойства YYYY имя магазина и массив товаров, каждый

из которых представлен переменной типа Style.

Public Type Store Name As String Styles() As StyleEnd Type

Следующий макрос создает итоговый отчет о продажах товаров в сети розY

ничных магазинов. В приведенном ниже коде используется только переменY

ная типа Store, так как этот тип включает в себя свойство типа Style.

Page 522: ? Применение VBA и макросов в Microsoft® Excel

522 Часть III Удивительные возможности Visual Basic for Applications

Sub UDTMain() Dim FinalRow As Long, ThisRow As Long, ThisStore As Long Dim CurrRow As Long, TotalDollarsSold As Long, _TotalUnitsSold As Long Dim TotalDollarsOnHand As Long, TotalUnitsOnHand As Long Dim ThisStyle As Long Dim StoreName As String' Объявление переменной пользовательского типа. ReDim Stores(0 To 0) As Store

FinalRow = Range("A65536").End(xlUp).Row' Следующий цикл For...Next заполняет два массива.' Внешний массив (массив переменных типа Store)' состоит из названий магазинов и перечня имеющихся в них товаров.' Внутренний массив (массив переменных типа Style)' состоит из подробных сведений о товарах. For ThisRow = 2 To FinalRow StoreName = Range("A" & ThisRow).Value' Проверить, есть ли во внешнем массиве хотя бы один элемент. If LBound(Stores) = 0 Then ThisStore = 1 ReDim Stores(1 To 1) As Store Stores(1).Name = StoreName ReDim Stores(1).Styles(0 To 0) As Style Else For ThisStore = LBound(Stores) To UBound(Stores) If Stores(ThisStore).Name = StoreName Then Exit For Next ThisStore If ThisStore > UBound(Stores) Then ReDim Preserve Stores(LBound(Stores) To _UBound(Stores) + 1) As Store Stores(ThisStore).Name = StoreName ReDim Stores(ThisStore).Styles(0 To 0) As Style End If End If With Stores(ThisStore) If LBound(.Styles) = 0 Then ReDim .Styles(1 To 1) As Style Else ReDim Preserve .Styles(LBound(.Styles) To _ UBound(.Styles) + 1) As Style End If With .Styles(UBound(.Styles)) .StyleName = Range("B" & ThisRow).Value .Price = Range("C" & ThisRow).Value .UnitsSold = Range("D" & ThisRow).Value .UnitsOnHand = Range("E" & ThisRow).Value End With End With Next ThisRow

' Создание отчета на новом рабочем листе. Sheets.Add Range("A1:E1").Value = Array("Магазин", "Продано (шт.)", _ "Продано (ден. ед.)", "Остаток (шт.)", "Остаток (ден. ед.)") CurrRow = 2 For ThisStore = LBound(Stores) To UBound(Stores) With Stores(ThisStore) TotalDollarsSold = 0

Page 523: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских объектов, типов и коллекций Глава 20 523

TotalUnitsSold = 0 TotalDollarsOnHand = 0 TotalUnitsOnHand = 0' Подсчет суммарных сведений о продажах товаров. For ThisStyle = LBound(.Styles) To UBound(.Styles) With .Styles(ThisStyle) TotalDollarsSold = TotalDollarsSold + _.UnitsSold * .Price TotalUnitsSold = TotalUnitsSold + .UnitsSold TotalDollarsOnHand = TotalDollarsOnHand + _.UnitsOnHand * .Price TotalUnitsOnHand = TotalUnitsOnHand + _.UnitsOnHand End With Next ThisStyle Range("A" & CurrRow & ":E" & CurrRow).Value = _ Array(.Name, TotalUnitsSold, TotalDollarsSold, _ TotalUnitsOnHand, TotalDollarsOnHand) End With CurrRow = CurrRow + 1 Next ThisStoreEnd Sub

Результат выполнения макроса UDTMain показан на рис. 20.15.

Рис. 20.15. Пользовательские типы позволяют упростить разработкудостаточно сложного программного кода. (Примечание: для наглядно&сти результаты выполнения макроса UDTMain совмещены с исходны&ми данными.)

Page 524: ? Применение VBA и макросов в Microsoft® Excel

524 Часть III Удивительные возможности Visual Basic for Applications

Следующий шагСледующая глава посвящена пользовательским формам. В ней описываютY

ся различные элементы управления, а также приемы программирования польY

зовательских форм.

Page 525: ? Применение VBA и макросов в Microsoft® Excel

Панель инструментовUserForm .........................................525Создание коллекцийэлементов управленияформы ........................................... 526Дополнительные элементыуправления формы..................... 528Немодальные формы ................. 531Гиперссылки в формах ............... 531Добавление элементовуправления на формуво время выполненияпрограммного кода.....................532Использование полосыпрокрутки для выборазначений ....................................... 539Добавление подсказки кэлементу управления..................541Порядок переноса фокуса..........541Изменение цвета фонаактивного элементауправления ................................... 542Использование эффектапрозрачности формы................. 545Следующий шаг........................... 546

21Глава 21

Ïîëüçîâàòåëü-ñêèå ôîðìû —ïðîôåññèîíàëü-íûé ïîäõîä

В главе 9, ‘‘Введение в пользоваY

тельские формы’’, рассматривались

основы создания пользовательских

форм. Продолжим знакомство с польY

зовательскими формами, уделив

особое внимание сложным элеменY

там управления, а также различным

приемам программирования польY

зовательских форм.

Панель инструментовUserForm

Чтобы отобразить панель инструY

ментов UserForm, выберите в меню

редактора Visual Basic команду ViewToolbars UserForm (Вид Панели

инструментов UserForm). Панель

инструментов UserForm содержит неY

сколько элементов управления, как поY

казано на рис. 21.1.

На передний планГруппировать

Выравнивание

На задний планОтменить группирование

Центрирование

Масштаб

Уравнять размеры

Рис. 21.1. Панель инструментов UserForm

Page 526: ? Применение VBA и макросов в Microsoft® Excel

526 Часть III Удивительные возможности Visual Basic for Applications

Кнопка Bring To Front (На передний план). Вынести выбранный элемент

управления поверх всех остальных элементов управления формы.

Кнопка Send To Back (На задний план). Спрятать выбранный элемент

управления за всеми остальными элементами управления формы.

Кнопка Group (Группировать). Объединить выбранные элементы управY

ления в группу.

Кнопка Ungroup (Отменить группирование). Отменить объединение выY

бранных элементов управления в группу.

Раскрывающийся список Align (Выравнивание). Выровнять выбранные

элементы управления по левому краю (Lefts), по центру (Centers), по

правому краю (Rights), по верхнему краю (Tops), посередине (Middles),

по нижнему краю (Bottoms) или по сетке (To Grid).

Раскрывающийся список Center (Центрирование). Центрировать выY

бранные элементы управления относительно формы по горизонтали

(Horizontally) или по вертикали (Vertically).

Раскрывающийся список Make Same Size (Уравнять размеры). Уравнять

ширину (Width), высоту (Height) или оба измерения (Both) выбранных

элементов управления.

Раскрывающийся список Zoom (Масштаб). Масштабировать элементы

управления формы.

Совет Чтобы выбрать несколько смежных элементов управления, щелкните на первом ина последнем из них, удерживая нажатой клавишу <Shift>. Чтобы выбрать не&сколько несмежных элементов управления, щелкните на каждом из них, удержи&вая нажатой клавишу <Ctrl>.

Создание коллекций элементовуправления формы

В главе 20, ‘‘Создание пользовательских объектов, типов и коллекций’’,

описывалось создание коллекции надписей, использующихся в качестве кноY

пок получения справочной информации. Рассмотрим пример создания колY

лекции других элементов управления формы YYYY флажков.

Разместите следующий код в модуле класса clsFormCtl.

Public WithEvents chb As MSForms.CheckBox

Public Sub SelectAll() chb.Value = TrueEnd Sub

Public Sub UnselectAll()

Page 527: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 527

chb.Value = FalseEnd Sub

Метод SelectAll выделяет флажок путем установки значения свойства

Value равным True. Метод UnselectAll отменяет выделение флажка путем

установки значения свойства Value равным False.

Объекты флажков помещаются в коллекцию при инициализации формы

frmSelectAll. Создание коллекции упрощается за счет того, что все флажки

являются частью панели frm_Selection.

Dim col_Selection As New Collection

Private Sub UserForm_Initialize() For Each ctl In frm_Selection.Controls Set clFormCtl = New clsFormCtl Set clFormCtl.chb = ctl col_Selection.Add clFormCtl Next ctlEnd Sub

Следующий код выделяет все флажки коллекции при щелчке на надписи

Выделить все.

Private Sub lbl_SelectAll_Click() For Each clFormCtl In col_Selection clFormCtl.SelectAll Next clFormCtlEnd Sub

Процедура lbl_UnselectAll_Click, выполняющаяся при щелчке на

кнопке Отменить выделение, отменяет выделение флажков коллекции.

Private Sub lbl_UnselectAll_Click() For Each clFormCtl In col_Selection clFormCtl.UnselectAll Next clFormCtlEnd Sub

Пользовательская форма frmSelectAll показана на рис. 21.2.

Рис. 21.2. Использование коллекций и панелей упро&щает работу с элементами управления формы

Page 528: ? Применение VBA и макросов в Microsoft® Excel

528 Часть III Удивительные возможности Visual Basic for Applications

На заметку Объединение флажков в коллекцию никоим образом не сказывается на их функ&циональности. Другими словами, флажки формы frmSelectAll по&прежнемуможно устанавливать/сбрасывать по отдельности.

На заметку Каждый элемент управления формы имеет свойство Tag типа String, содержа&щее дополнительную информацию об элементе управления. Это свойство можноиспользовать для неформального группирования элементов управления, входя&щих в другие группы.

Дополнительные элементы управления формыВ этом разделе продолжается рассмотрение элементов управления пользоY

вательской формы, начатое в главе 9, ‘‘Введение в пользовательские формы’’.

Переключатели

В отличие от флажков, переключатели поддерживают возможность выбора

только одного элемента из группы, как показано на рис. 21.3.

Рис. 21.3. Переключатели поддерживают возможностьвыбора только одного элемента из группы

Возможность выбора только одного элемента из группы может быть реалиY

зована с помощью программного кода, однако переключатели изначально

поддерживают такую функциональность благодаря наличию свойства Group-Name. Все переключатели с одинаковым значением свойства GroupNameпринадлежат к одной группе. Выделение одного из переключателей группы

автоматически приводит к отмене выделения остальных переключателей

группы. Чтобы иметь возможность выбора нескольких переключателей одноY

временно, присвойте им разное значение свойства GroupName или же оставьY

те его незаданным.

Page 529: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 529

Набор вкладок

Вкладки, рассматривавшиеся в главе 9, ‘‘Введение в пользовательские

формы’’, позволяют объединить воедино несколько страниц с различнымиэлементами управления. Набор вкладок (tabstrip) позволяет объединить неY

сколько страниц с одинаковыми элементами управления, общими для всех

входящих в набор вкладок. При переключении вкладок значения элементов

управления меняются, как показано на рис. 21.4.

Рис. 21.4. Набор вкладок позволяет объединитьнесколько страниц с одинаковыми элементамиуправления

См. также Более подробно вкладки рассматриваются в разделе “Использование вкладок дляобъединения форм” главы 9 на с. 225.

По умолчанию набор состоит из двух вкладок. Чтобы добавить, удалить,

переименовать или переместить вкладку, щелкните на ней правой кнопкой

мыши. Измените размер набора вкладок так, чтобы он мог вместить все необY

ходимые элементы управления.

На заметку Кнопку закрытия пользовательской формы следует разместить за пределами на&бора вкладок.

Свойство набора вкладок TabOrientation позволяет определить распоY

ложение корешков вкладок, которые могут располагаться вдоль верхней

(fmTabOrientationTop), нижней (fmTabOrientationBottom), левой

(fmTabOrientationLeft) или правой (fmTabOrientationRight) граниY

цы пользовательской формы.

Следующий код создает набор вкладок, показанный на рис. 21.4. Для

установки значений элементов управления вкладки используется процедура

SetValuesToTabStrip.

Private Sub UserForm_Initialize()' По умолчанию при инициализации формы

Page 530: ? Применение VBA и макросов в Microsoft® Excel

530 Часть III Удивительные возможности Visual Basic for Applications

' отображается содержимое первой вкладки. SetValuesToTabStrip 1End Sub

Процедура TabStrip1_Change выполняется при выборе новой вкладки,

что приводит к автоматическому изменению значений элементов управления

вкладки в соответствии с ее порядковым номером.

Private Sub TabStrip1_Change() Dim lngRow As Long lngRow = TabStrip1.Value + 1 SetValuesToTabStrip lngRowEnd Sub

Ниже приведен код процедуры SetValuesToTabStrip.

Private Sub SetValuesToTabStrip(ByVal lngRow As Long) lbl_Address.Caption = Cells(lngRow, 2).Value lbl_Phone.Caption = Cells(lngRow, 3).Value lbl_Fax.Caption = Cells(lngRow, 4).Value lbl_Email.Caption = Cells(lngRow, 5).Value lbl_Website.Caption = Cells(lngRow, 6).ValueEnd Sub

Совет Добавить дополнительный элемент управления к вкладке, входящей в набор,можно только программным путем в момент активизации этой вкладки.

Поле ввода адреса диапазона ячеекПоле ввода адреса диапазона ячеек можно разместить на любой пользоваY

тельской форме. Щелчок на кнопке, расположенной справа от поля ввода,

приводит к скрытию формы и отображению окна ввода адреса диапазона ячеY

ек, знакомого большинству пользователей по многочисленным мастерам ExY

cel. Чтобы вернуть форму на экран, щелкните на кнопке с изображением

формы, расположенной в правой части окна.

Следующая процедура форматирует содержимое диапазона ячеек, адрес

которого был задан с помощью поля ввода, изображенного на рис. 21.5, путем

утолщения шрифта.

Private Sub cb1_Click() Range(RefEdit1.Value).Font.Bold = TrueEnd Sub

Рис. 21.5. Окно ввода адреса диапазона ячеек знакомобольшинству пользователей Excel

Page 531: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 531

Немодальные формыПо умолчанию пользовательская форма является модальной, т.е. такой, коY

торая не позволяет вернуться к просмотру или изменению содержимого рабоY

чего листа Excel до тех пор, пока она не будет закрыта. Чтобы сделать форму

немодальной, установите значение ее свойства ShowModal равным False.

При отображении на экране немодальной формы пользователь может проY

должать работу с содержимым листа Excel без какихYлибо ограничений, как

показано на рис. 21.6.

Рис. 21.6. Немодальная форма позволяет продолжатьработу с листом Excel

Гиперссылки в формахПользовательская форма, показанная на рис. 21.4, содержит надписи с адY

ресом электронной почты и адресом WebYсайта. Рассмотрим код, необходиY

мый для запуска соответствующего приложения при щелчке на каждой из

этих надписей.

Разместите в верхней части модуля объявления требуемых функций API и

переменных.

Private Declare Function ShellExecute Lib "shell32.dll" _Alias "ShellExecuteA" (ByVal hWnd As Long, ByVal lpOperation _As String, ByVal lpFile As String, ByVal lpParameters As String, _ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Const SWNormal = 1

Page 532: ? Применение VBA и макросов в Microsoft® Excel

532 Часть III Удивительные возможности Visual Basic for Applications

Процедура lbl_Email_Click обрабатывает щелчок на надписи с адресом

электронной почты (рис. 21.7).

Private Sub lbl_Email_Click() Dim lngRow As Long lngRow = TabStrip1.Value + 1 ShellExecute 0&, "open", "mailto:" & Cells(lngRow, 5).Value, _vbNullString, vbNullString, SWNormalEnd Sub

Рис. 21.7. Всего лишь несколько строк кода способны превратить надписи садресом электронной почты и адресом Web&сайта в гиперссылки

Процедура lbl_Website_Click обрабатывает щелчок на надписи с адреY

сом WebYсайта.

Private Sub lbl_Website_Click() Dim lngRow As Long lngRow = TabStrip1.Value + 1 ShellExecute 0&, "open", Cells(lngRow, 6).Value, _vbNullString, vbNullString, SWNormalEnd Sub

Добавление элементов управления на формуво время выполнения программного кода

Рассмотрим простую форму, показанную на рис. 21.8.

Эта форма, содержащая всего лишь одну кнопку Закрыть, будет использоY

вана для отображения рисунков из некоторого каталога. Рисунки и соответстY

вующие им надписи добавляются на форму во время выполнения программY

ного кода.

Page 533: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 533

Рис. 21.8. Эта форма будет использованадля добавления на нее элементов управ&ления во время выполнения программ&ного кода

Подобная форма может применяться торговыми представителями для выY

вода на экран изображений товаров из каталога. Для этого достаточно выбрать

названия или коды нужных товаров на рабочем листе Excel и щелкнуть на

кнопке, отображающей форму. На рис. 21.9 приведен пример вывода на экран

нескольких фотографий.

Рис. 21.9. Рисунки и соответствующие им надписи добавляются на форму при выполнениипроцедуры инициализации UserForm_Initialize

Page 534: ? Применение VBA и макросов в Microsoft® Excel

534 Часть III Удивительные возможности Visual Basic for Applications

При выборе меньшего числа фотографий их изображения будут иметь

больший размер, как показано на рис. 21.10.

Рис. 21.10. Процедура UserForm_Initialize определяет размер рисунков, исходя из ихобщего числа

В следующих разделах рассматриваются приемы программирования, деY

лающие возможным добавление на форму элементов управления во время

выполнения программного кода.

Изменение размеров формы во время выполненияпрограммного кода

Приведенный ниже код использует свойства формы Height и Width для

изменения ее размеров во время выполнения программного кода.

' Изменить размер формы.Me.Height = Int(0.98 * ActiveWindow.Height)Me.Width = Int(0.98 * ActiveWindow.Width)

Добавление элемента управления на форму во времявыполнения программного кода

Ниже приведен пример обращения к свойству элемента управления, доY

бавленного на форму во время ее проектирования.

Me.cbSave.Left = 100

Page 535: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 535

Чтобы обратиться к свойству элемента управления, добавленного на форму

во время выполнения программного кода, необходимо использовать коллекY

цию Controls. Также рекомендуется создать переменную, хранящую имя

элемента управления. Для добавления элемента управления на форму испольY

зуется метод Add коллекции Controls. Параметр bstrProgId метода Addопределяет тип элемента управления.

Приведенный ниже код добавляет на форму надпись. Переменная Pic-Count используется для присвоения элементу управления уникального имеY

ни. Свойства надписи Top и Left определяют ее положение на форме, а

свойства Height и Width — размер надписи.

LC = "LabelA" & PicCountMe.Controls.Add bstrProgId:="forms.label.1", Name:=LC, Visible:=TrueMe.Controls(LC).Top = 25Me.Controls(LC).Left = 50Me.Controls(LC).Height = 18Me.Controls(LC).Width = 60Me.Controls(LC).Caption = Cell.Value

Определение размера и положения элемента управленияна форме во время выполнения программного кода

Определение размера (свойства Height и Width) и положения (Top и Left)

элемента управления на форме осуществляется с учетом высоты и ширины

формы, а также общего числа помещенных на форму элементов управления.

Ограничения, связанные с добавлением элементовуправления на форму во время выполненияпрограммного кода

Excel не сможет отобразить динамическую подсказку при обращении к

элементам управления, добавляемым на форму во время выполнения проY

граммного кода. К примеру, при наборе выражения Me.cbClose. Excel выY

водит на экран подсказку, содержащую доступные методы, свойства и собыY

тия соответствующего объекта. С другой стороны, при наборе выражения

Me.Controls(LC). тип элемента управления заранее неизвестен. В связи с

этим, в частности, следует помнить о том, что текст надписи задается свойстY

вом Caption, а не свойством Value.

Типы элементов управления

Как уже упоминалось, тип добавляемого на форму элемента управления

определяется параметром bstrProgId метода Controls.Add. Возможные

значения этого параметра перечислены в табл. 21.1.

Page 536: ? Применение VBA и макросов в Microsoft® Excel

536 Часть III Удивительные возможности Visual Basic for Applications

Таблица 21.1. Типы элементов управления

Элемент управления Значение параметра bstrProgId

Флажок (CheckBox) Forms.CheckBox.1

Комбинированный список (ComboBox) Forms.ComboBox.1

Кнопка (CommandButton) Forms.CommandButton.1

Панель (Frame) Forms.Frame.1

Изображение (Image) Forms.Image.1

Надпись (Label) Forms.Label.1

Список (ListBox) Forms.ListBox.1

Вкладка (MultiPage) Forms.MultiPage.1

Переключатель (OptionButton) Forms.OptionButton.1

Полоса прокрутки (ScrollBar) Forms.ScrollBar.1

Счетчик (SpinButton) Forms.SpinButton.1

Набор вкладок (TabStrip) Forms.TabStrip.1

Поле ввода (TextBox) Forms.TextBox.1

Выключатель (ToggleButton) Forms.ToggleButton.1

Добавление изображения на форму во время выполненияпрограммного кода

Добавление изображения на форму во время выполнения программного

кода связано с определенными трудностями, поскольку ни ориентация изоY

бражения YYYY альбомная или портретная, YYYY ни его размер заранее неизвестны.

Решение этой задачи рекомендуется разбить на три этапа. Загрузите изобраY

жение в натуральную величину, установив значение параметра AutoSizeравным True, как показано ниже:

TC = "Image" & PicCountMe.Controls.Add bstrProgId:="forms.image.1", Name:=TC, Visible:=TrueMe.Controls(TC).Top = LastTopMe.Controls(TC).Left = LastLeftMe.Controls(TC).AutoSize = True

On Error Resume NextMe.Controls(TC).Picture = LoadPicture(fname)On Error GoTo 0

Загрузив изображение, определите его размер и ориентацию с помощью

свойств Height и Width:

' Определить размер изображения.Wid = Me.Controls(TC).WidthHt = Me.Controls(TC).HeightWidRedux = CellWid / WidHtRedux = CellHt / Ht

Page 537: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 537

If WidRedux < HtRedux Then Redux = WidReduxElse Redux = HtReduxEnd If

NewHt = Int(Ht * Redux)NewWid = Int(Wid * Redux)

Определив исходный размер изображения, установите значение свойства

AutoSize равным False и задайте требуемые значения свойств Height и

Width.

' Изменить размер изображения.Me.Controls(TC).AutoSize = FalseMe.Controls(TC).Height = NewHtMe.Controls(TC).Width = NewWidMe.Controls(TC).PictureSizeMode = fmPictureSizeModeStretch

Результирующий код

Ниже приведен полный текст процедуры UserForm_Initialize, доY

бавляющей элементы управления на форму во время выполнения проY

граммного кода.

Private Sub UserForm_Initialize()' Эта процедура помещает на форму фотографии, имена' файлов которых выбираются с помощью рабочего листа Excel. PicPath = ThisWorkbook.Path & Application.PathSeparator

' Изменить размер формы. Me.Height = Int(0.98 * ActiveWindow.Height) Me.Width = Int(0.98 * ActiveWindow.Width)

' Определить число выбранных ячеек. CellCount = Selection.Cells.Count ReDim Preserve Pics(1 To CellCount)

' Определить размер пользовательской формы. TempHt = Me.Height TempWid = Me.Width

' Определить число столбцов и строк с изображениями. NumCol = Int(0.99 + Sqr(CellCount)) NumRow = Int(0.99 + CellCount / NumCol)

' Зарезервировать 2 точки слева и' справа от каждого изображения. CellWid = Application.WorksheetFunction.Max(Int(TempWid _/ NumCol) - 4, 1)' Зарезервировать 33 точки под каждым' изображением для размещения надписи. CellHt = Application.WorksheetFunction.Max(Int(TempHt _/ NumRow) - 33, 1)

' Переменная-счетчик. PicCount = 0

Page 538: ? Применение VBA и макросов в Microsoft® Excel

538 Часть III Удивительные возможности Visual Basic for Applications

LastTop = 2 MaxBottom = 1' Создать строку изображений. For X = 1 To NumRow LastLeft = 3' Создать столбец изображений. For Y = 1 To NumCol PicCount = PicCount + 1 If PicCount > CellCount Then' Изменить размер формы, чтобы' вместить все изображения. Me.Height = MaxBottom + 100 Me.cbClose.Top = MaxBottom + 25 Me.cbClose.Left = Me.Width - 50

Repaint

Exit Sub End If

ThisStyle = Selection.Cells(PicCount).Value ThisDesc = Selection.Cells(PicCount).Offset(0, 1).Value fname = PicPath & ThisStyle & ".jpg "

TC = "Image" & PicCount Me.Controls.Add bstrProgId:="forms.image.1", _Name:=TC, Visible:=True Me.Controls(TC).Top = LastTop Me.Controls(TC).Left = LastLeft Me.Controls(TC).AutoSize = True

On Error Resume Next Me.Controls(TC).Picture = LoadPicture(fname) On Error GoTo 0

' Определить размер изображения. Wid = Me.Controls(TC).Width Ht = Me.Controls(TC).Height WidRedux = CellWid / Wid HtRedux = CellHt / Ht If WidRedux < HtRedux Then Redux = WidRedux Else Redux = HtRedux End If

NewHt = Int(Ht * Redux) NewWid = Int(Wid * Redux)

' Изменить размер изображения. Me.Controls(TC).AutoSize = False Me.Controls(TC).Height = NewHt Me.Controls(TC).Width = NewWid Me.Controls(TC).PictureSizeMode = _fmPictureSizeModeStretch

Me.Controls(TC).ControlTipText = ThisStyle & ".jpg"

Page 539: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 539

Me.Controls(TC).Tag = fname

' Определить координаты нижнего правого угла изображения. ThisRight = Me.Controls(TC).Left + _Me.Controls(TC).Width ThisBottom = Me.Controls(TC).Top + _Me.Controls(TC).Height If ThisBottom > MaxBottom Then MaxBottom = ThisBottom

' Добавить подрисуночную надпись. LC = "LabelA" & PicCount Me.Controls.Add bstrProgId:="forms.label.1", _Name:=LC, Visible:=True Me.Controls(LC).Top = ThisBottom + 1 Me.Controls(LC).Left = LastLeft Me.Controls(LC).Height = 18 Me.Controls(LC).Width = CellWid Me.Controls(LC).Caption = ThisDesc

' Эта строка позволяет увеличить' изображение при щелчке на нем кнопкой мыши. Set Pics(PicCount).PictureGroup = Me.Controls(TC)

' Определить координаты следующего изображения. LastLeft = LastLeft + CellWid + 4' Конец строки. Next Y LastTop = MaxBottom + 21 + 16 Next X

Me.Height = MaxBottom + 100 Me.cbClose.Top = MaxBottom + 25 Me.cbClose.Left = Me.Width - 50

RepaintEnd Sub

Использование полосы прокруткидля выбора значений

В главе 9, “Введение в пользовательские формы”, описывалось использоY

вание счетчика для выбора даты. Недостаток счетчика состоит в том, что

единственный способ изменения его значения заключается в щелчке на одной

из клавиш счетчика. Альтернативный подход к выбору значения состоит в исY

пользовании полосы прокрутки. Помимо щелчка на клавишах полосы проY

крутки, ее значение можно выбрать путем перемещения ползунка.

Пользовательская форма, показанная на рис. 21.11 и 21.12, содержит надY

пись Label1 и полосу прокрутки ScrollBar1.

Page 540: ? Применение VBA и макросов в Microsoft® Excel

540 Часть III Удивительные возможности Visual Basic for Applications

Рис. 21.11. Полоса прокрутки можетприменяться в качестве альтернативысчетчику

Рис. 21.12. Преимущество полосы про&крутки заключается в возможности бы&строго изменения ее значения с помо&щью ползунка

Процедура UserForm_Initialize задает начальное, минимальное и

максимальное значение полосы прокрутки, а также текст надписи.

Private Sub UserForm_Initialize() Me.ScrollBar1.Min = 0 Me.ScrollBar1.Max = 100 Me.ScrollBar1.Value = Range("A1").Value Me.Label1.Caption = Me.ScrollBar1.ValueEnd Sub

Обработчик события ScrollBar1_Change выполняется при щелчке на

одной из кнопок полосы прокрутки.

Private Sub ScrollBar1_Change()' Событие ScrollBar1_Change срабатывает' при щелчке на одной из кнопок полосы прокрутки. Me.Label1.Caption = Me.ScrollBar1.ValueEnd Sub

Обработчик события ScrollBar1_Scroll выполняется при щелчке на

ползунке полосы прокрутки.

Private Sub ScrollBar1_Scroll()' Событие ScrollBar1_Scroll срабатывает' при щелчке на ползунке полосы прокрутки. Me.Label1.Caption = Me.ScrollBar1.ValueEnd Sub

Обработчик события CommandButton1_Click выполняется при щелчке

на кнопке OK. Следующий код копирует значение полосы прокрутки в ячейку

A1 рабочего листа Excel и закрывает пользовательскую форму.

Private Sub CommandButton1_Click() Range("A1").Value = Me.ScrollBar1.Value Unload MeEnd Sub

Page 541: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 541

Добавление подсказки к элементу управленияИспользование сочетаний клавиш

Сочетания клавиш позволяют инициировать выполнение действий, наY

пример, нажатие клавиши или установку флажка на форме. Как правило, соY

четание клавиш определяется подчеркнутой буквой в названии кнопки или

тексте надписи.

Чтобы назначить сочетание клавиш для элемента управления пользоваY

тельской формы, задайте значение свойства Accelerator. Действие, связанY

ное с этим элементом управления, будет выполняться при нажатии комбинаY

ции клавиш <Alt+значение свойства Accelerator>. Как показано на

рис. 21.13, для установки/снятия флажка VHS можно применять сочетание

клавиш <Alt+H>.

Рис. 21.13. Сочетания клавиш используются для вы&полнения различных действий, связанных с элемен&тами управления формы

Подсказка элемента управления

При подведении указателя мыши к кнопке панели инструментов Excel на

экране отображается подсказка, описывающая предназначение этой кнопки.

Аналогичную функциональность можно реализовать для любого элемента

управления формы путем установки значения свойства ControlTipText.

На рис. 21.14 показана подсказка, отображающаяся на экране при подведении

указателя мыши к переключателю Комедия.

Порядок переноса фокусаВсе пользовательские формы поддерживают перенос фокуса с одного элеY

мента управления на другой при нажатии клавиши <Tab>. Порядок переноса

фокуса определяется свойствами элемента управления TabStop и TabIndex.

Page 542: ? Применение VBA и макросов в Microsoft® Excel

542 Часть III Удивительные возможности Visual Basic for Applications

Рис. 21.14. Подсказки упрощают работу с пользова&тельской формой

Булево свойство TabStop определяет саму возможность переноса фокуса

на элемент управления при нажатии клавиши <Tab>, а свойство TabIndex —

порядковый номер элемента управления в группе (с отсчетом от нуля). Для

создания группы элементов управления можно использовать панель. Два элеY

мента управления в группе не могут иметь одинаковое значение свойства

TabIndex. После переноса фокуса на флажок или переключатель значения

последних можно устанавливать с помощью клавиши пробела (рис. 21.15).

Рис. 21.15. Значения элементов управления этой фор&мы можно устанавливать с помощью клавиши <Tab> иклавиши пробела

Изменение цвета фона активного элементауправления

Изменение цвета фона активного элемента управления способно упростить

взаимодействие пользователя с формой. Рассмотрим пример изменения цвета

фона поля ввода и комбинированного списка, как показано на рис. 21.16.

Page 543: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 543

Рис. 21.16. Изменение цвета фо&на активного элемента управле&ния способно упростить взаи&модействие пользователя сформой

Разместите следующий код в модуле класса clsCtlColor.

Public Event GetFocus()Public Event LostFocus(ByVal strCtrl As String)

Private strPreCtr As String

Public Sub CheckActiveCtrl(objForm As MSForms.UserForm) With objForm If TypeName(.ActiveControl) = "ComboBox" Or _ TypeName(.ActiveControl) = "TextBox" Then strPreCtr = .ActiveControl.Name On Error GoTo Terminate Do DoEvents If .ActiveControl.Name <> strPreCtr Then If TypeName(.ActiveControl) = "ComboBox" Or _ TypeName(.ActiveControl) = "TextBox" Then RaiseEvent LostFocus(strPreCtr) strPreCtr = .ActiveControl.Name RaiseEvent GetFocus End If End If Loop End If End WithTerminate:End Sub

Ниже приведен код, который необходимо поместить в модуль формы.

Private WithEvents objForm As clsCtlColor

Private Sub UserForm_Initialize() Set objForm = New clsCtlColorEnd Sub

Процедура UserForm_Activate изменяет цвет фона (свойство Back-Color) активного элемента управления при отображении формы на экране.

Private Sub UserForm_Activate() If TypeName(ActiveControl) = "ComboBox" Or _ TypeName(ActiveControl) = "TextBox" Then ActiveControl.BackColor = &HC0E0FF

Page 544: ? Применение VBA и макросов в Microsoft® Excel

544 Часть III Удивительные возможности Visual Basic for Applications

End If objForm.CheckActiveCtrl MeEnd Sub

Обработчик события objForm_GetFocus изменяет цвет фона элемента

управления, на который был перенесен фокус.

Private Sub objForm_GetFocus() ActiveControl.BackColor = &HC0E0FFEnd Sub

Обработчик события objForm_LostFocus изменяет цвет фона элемента

управления, с которого был перенесен фокус.

Private Sub objForm_LostFocus(ByVal strCtrl As String) Controls(strCtrl).BackColor = &HFFFFFFEnd Sub

Процедура UserForm_QueryClose удаляет объект objForm из памяти

при закрытии формы.

Private Sub UserForm_QueryClose(Cancel As Integer, _CloseMode As Integer) Set objForm = NothingEnd Sub

Практикум

Список с несколькими столбцамиРассмотрим следующую задачу. На рабочем листе Excel содержится информация омагазинах, включающая их названия и коды. Необходимо создать форму, позволяю&щую выбрать магазин по его названию и возвращающую в качестве результата кодмагазина. Несмотря на то, что подобная задача может быть решена с помощью функ&ций ВПР (VLOOKUP) и ПОИСКПОЗ (MATCH), рассмотрим альтернативный метод.Элемент управления ListBox (список) может содержать несколько столбцов,лишь часть из которых будет видна пользователю. К тому же список позволяетвыбрать столбец, значение которого будет возвращено в качестве результата.Разместите на форме список и установите значение его свойства ColumnCountравным 2. Установите значение свойства RowSource равным Магазины, гдеМагазины — это имя диапазона ячеек, включающего список кодов (первый стол&бец) и названий (второй столбец) магазинов. Чтобы скрыть первый столбец, уста&новите значение свойства ColumnWidth равным 0 pt;100 pt, как показано нарис. 21.17.Теперь при отображении формы на экране пользователь увидит вполне привыч&ный список с одним столбцом. Чтобы возвратить значение первого столбца(столбца кодов магазинов), установите значение свойства списка BoundColumnравным 1. Это можно сделать с помощью окна свойств списка или с помощьюпрограммного кода, как показано ниже:Private Sub lb_StoreName_Click() lb_StoreName.BoundColumn = 1 lbl_StoreNum.Caption = lb_StoreNameEnd Sub

Page 545: ? Применение VBA и макросов в Microsoft® Excel

Пользовательские формы — профессиональный подход Глава 21 545

Рис. 21.17. Свойство списка ColumnWidth позволяет скрыть столбцы,не предназначенные для отображения на экране

На рис. 21.18 показан результат решения поставленной задачи с помощью списка снесколькими столбцами.

Рис. 21.18. Список с несколькими

столбцами позволяет отображатьна экране один столбец, а возвращатьв качестве результата значение друго&го столбца

Использование эффекта прозрачности формыКак показано на рис. 21.19, эффект прозрачности формы позволяет видеть

содержимое расположенного под ней рабочего листа Excel.

Разместите следующий код в начале модуля формы:

Private Declare Function GetActiveWindow Lib "USER32" () As LongPrivate Declare Function SetWindowLong Lib "USER32" Alias _ "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, _ ByVal dwNewLong As Long) As LongPrivate Declare Function GetWindowLong Lib "USER32" Alias _ "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) _ As LongPrivate Declare Function SetLayeredWindowAttributes Lib "USER32" _ (ByVal hWnd As Long, ByVal crKey As Integer, _ ByVal bAlpha As Integer, ByVal dwFlags As Long) As Long

Page 546: ? Применение VBA и макросов в Microsoft® Excel

546 Часть III Удивительные возможности Visual Basic for Applications

Private Const WS_EX_LAYERED = &H80000Private Const LWA_COLORKEY = &H1Private Const LWA_ALPHA = &H2Private Const GWL_EXSTYLE = &HFFEC

Рис. 21.19. Полупрозрачная форма

Обработчик события UserForm_Activate вызывает функции Windows

API, необходимые для достижения эффекта прозрачности.

Private Sub UserForm_Activate() Dim nIndex As Long

hWnd = GetActiveWindow nIndex = GetWindowLong(hWnd, GWL_EXSTYLE) SetWindowLong hWnd, GWL_EXSTYLE, nIndex Or WS_EX_LAYERED' Вызов этой функции позволяет достичь эффекта прозрачности. SetLayeredWindowAttributes hWnd, 0, (255 * (100 - rt)) / _100, LWA_ALPHAEnd Sub

Следующий шагСледующая глава посвящена основам использования функций интерфейса

прикладного программирования (API) Windows.

Page 547: ? Применение VBA и макросов в Microsoft® Excel

Знакомство с Windows API.........547Объявления Windows API.......... 548Использование объявленийWindows API ................................. 548Примеры полезныхобъявлений Windows API.......... 549Дополнительные источникиобъявлений Windows API.......... 559Следующий шаг........................... 559

22Ãëàâà 22

Èíòåðôåéñïðèêëàäíîãîïðîãðàììèðî-âàíèÿ (API)Windows

Знакомствос Windows API

Несмотря на разнообразие встроY

енных функций Excel VBA, сущестY

вуют задачи, которые можно выполY

нить только с помощью средств инY

терфейса прикладного программироY

вания (API) Windows.

Заглянув в папку \Windows\System32 (или \Winnt\System32)

на системном диске компьютера,

можно увидеть множество файлов с

расширением .dll. Эти файлы наY

зываются динамически подключаемы*ми библиотеками, содержащими проY

цедуры и функции, доступные друY

гим программам (например, Excel).

Следует помнить, что средства WinY

dows API доступны только на компьюY

терах, работающих под управлением

операционной системы семейства

Microsoft Windows.

В этой главе рассматриваются осY

новы использования объявлений

Windows API, а также приводится неY

сколько полезных примеров.

Page 548: ? Применение VBA и макросов в Microsoft® Excel

548 Часть III Удивительные возможности Visual Basic for Applications

Объявления Windows API Рассмотрим пример объявления Windows API.

Private Declare Function GetUserName Lib "advapi32.dll" Alias _"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Существует два типа объявлений Windows API — функции, возвращающие

информацию, и процедуры, выполняющие какиеYлибо действия.

Разберем структуру приведенного выше объявления Windows API.

Private. Ключевое слово, определяющее переменную, функцию или

процедуру, использующуюся в пределах одного модуля. Чтобы объяY

вить общедоступную переменную, функцию или процедуру, примеY

няйте ключевое слово Public.

Внимание Объявления Windows API, размещенные в стандартном модуле, могут иметь об&ласть видимости Public или Private. Объявления Windows API, размещенные вмодуле класса, должны иметь область видимости Private.

Declare Function GetUserName. Объявление функции GetUser-Name. Имя функции может быть произвольным.

Lib "advapi32.dll". Функция API находится в библиотеке ad-vapi32.dll.

Alias "GetUserNameA". Псевдоним функции в библиотеке DLL.

Псевдоним чувствителен к регистру и должен быть набран в том виде, в

котором он существует в библиотеке DLL. Обычно каждая функция

API имеет два псевдонима. Псевдоним функции API, использующей

набор символов ANSI, заканчивается буквой A, а псевдоним функции

API, использующей набор символов Unicode, — буквой W.

ByVal lpBuffer As String, nSize As Long. Функция API приY

нимает два параметра YYYY lpBuffer типа String и nSize типа Long.

Использование объявлений Windows APIИспользование объявления Windows API ничем не отличается от вызова

функции или процедуры VBA. Ниже приведен пример использования объявY

ления Windows API GetUserName.

Private Function UserName() As String Dim sName As String * 256 Dim cChars As Long

cChars = 256 If GetUserName(sName, cChars) Then UserName = Left$(sName, cChars - 1) End If

Page 549: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 549

End Function

Sub ProgramRights() Dim NameofUser As String

NameofUser = UserName Select Case NameofUser Case Is = "Администратор" MsgBox "Вы имеете права администратора на этом компьютере" Case Else MsgBox "Вы имеете ограниченные права на этом компьютере" End SelectEnd Sub

Макрос ProgramRights позволяет узнать, имеет ли текущий пользоваY

тель права администратора компьютера (рис. 22.1).

Примеры полезных объявлений Windows APIВ этом разделе рассматриваются полезные объявления Windows API вместе

с краткими описаниями и примерами использования.

Определение имени компьютера

Объявление Windows API GetComputerName возвращает имя компьютера.

Private Declare Function GetComputerName Lib "kernel32" _Alias "GetComputerNameA" (ByVal lpBuffer As String, _ByRef nSize As Long) As Long

Private Function ComputerName() As String Dim stBuff As String * 255, lAPIResult As Long Dim lBuffLen As Long

lBuffLen = 255 lAPIResult = GetComputerName(stBuff, lBuffLen) If lBuffLen > 0 Then ComputerName = Left(stBuff, lBuffLen)End Function

Sub ComputerCheck() Dim CompName As String

CompName = ComputerName MsgBox Prompt:=CompName, Buttons:=vbOKOnly, _Title:="Имя компьютера"End Sub

Макрос ComputerCheck выводит на экран окно сообщения, содержащего

имя компьютера. Результат выполнения макроса ComputerCheck показан на

рис. 22.2.

Page 550: ? Применение VBA и макросов в Microsoft® Excel

550 Часть III Удивительные возможности Visual Basic for Applications

Рис. 22.1. Объявление Windows APIGetUserName позволяет узнать имяпользователя компьютера и опреде&лить, имеет ли пользователь праваадминистратора

Рис. 22.2. Объявление WindowsAPI GetComputerName позволяетузнать имя компьютера

Проверка возможности доступа к файлу

Объявления Windows API lOpen и lClose позволяют узнать, открыт или

закрыт заданный файл.

Private Declare Function lOpen Lib "kernel32" Alias "_lopen" _ (ByVal lpPathName As String, ByVal iReadWrite As Long) As LongPrivate Declare Function lClose Lib "kernel32" _ Alias "_lclose" (ByVal hFile As Long) As Long

Private Function FileIsOpen(strFullPath_FileName _As String) As Boolean Dim hdlFile As Long Dim lastErr As Long

hdlFile = -1 hdlFile = lOpen(strFullPath_FileName, OF_SHARE_EXCLUSIVE) If hdlFile = -1 Then lastErr = Err.LastDllError Else lClose hdlFile End If FileIsOpen = (hdlFile = -1) And (lastErr = 32)End Function

Sub CheckFileOpen() Dim txtFile As String txtFile = GetFileName("c:\") If txtFile = "" Then Exit Sub If FileIsOpen(txtFile) Then MsgBox "Файл занят (открыт)" Else MsgBox "Файл не занят" End IfEnd Sub

Макрос CheckFileOpen позволяет выбрать файл и узнать, открыт он или

закрыт (рис. 22.3).

Определение разрешения экрана

Объявление Windows API DisplaySize позволяет определить разрешение

экрана компьютера.

Page 551: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 551

Private Declare Function DisplaySize Lib "user32" Alias _ "GetSystemMetrics" (ByVal nIndex As Long) As Long

Private Function VideoRes() As String Dim vidWidth Dim vidHeight

vidWidth = DisplaySize(SM_CXSCREEN) vidHeight = DisplaySize(SM_CYSCREEN) Select Case (vidWidth * vidHeight) Case 307200 VideoRes = "640 x 480" Case 480000 VideoRes = "800 x 600" Case 786432 VideoRes = "1024 x 768" Case Else VideoRes = "Другое разрешение" End SelectEnd Function

Sub CheckDisplayRes() Dim VideoInfo As String Dim Msg1 As String, Msg2 As String, Msg3 As String

VideoInfo = VideoRes Msg1 = "Текущее разрешение экрана: " & VideoInfo & Chr(10) Msg2 = "Оптимальное разрешение экрана для этого приложения: _1024 x 768 " & Chr(10) Msg3 = "Пожалуйста, увеличьте разрешение экрана" Select Case VideoInfo Case Is = "640 x 480" MsgBox Msg1 & Msg2 & Msg3 Case Is = "800 x 600" MsgBox Msg1 & Msg2 & Msg3 Case Is = "1024 x 768" MsgBox Msg1 Case Else MsgBox Msg2 & Msg3 End SelectEnd Sub

Макрос CheckDisplayRes проверяет текущее разрешение экрана и при

необходимости рекомендует его увеличить, как показано на рис. 22.4.

Рис. 22.3. Объявления Windows APIlOpen и lClose могут быть ис&пользованы для того, чтобы узнать,открыт ли заданный файл

Рис. 22.4. Объявление Windows API Display-Size позволяет определить разрешение экранакомпьютера

Page 552: ? Применение VBA и макросов в Microsoft® Excel

552 Часть III Удивительные возможности Visual Basic for Applications

Блокирование кнопки закрытия окна приложения

В правом верхнем углу окна приложения находится кнопка, предназначенY

ная для его закрытия (кнопка с изображением знака ‘‘×’’). Блокировать кнопY

ку закрытия окна приложения можно с помощью объявлений Windows API

FindWindow, GetSystemMenu и DeleteMenu.

На заметку Не забудьте разблокировать кнопку закрытия окна приложения с помощью выра&жения XButtonEnabled True.

Private Declare Function FindWindow Lib "user32" Alias _"FindWindowA" (ByVal lpClassName As String, _ByVal lpWindowName As String) As LongPrivate Declare Function GetSystemMenu Lib "user32" _(ByVal hwnd As Long, ByVal bRevert As Long) As LongPrivate Declare Function DeleteMenu Lib "user32" (ByVal hMenu _As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long

Private Sub XButtonEnabled(ByVal bEnabled As Boolean) Dim hWndForm As Long Dim hMenu As Long

hWndForm = FindWindow("XLMAIN", Application.Caption) hMenu = GetSystemMenu(hWndForm, bEnabled) DeleteMenu hMenu, SC_CLOSE, 0&End Sub

Sub DisableExcelXButton() XButtonEnabled False MsgBox "Кнопка закрытия окна приложения заблокирована"End Sub

Sub EnableExcelXButton() XButtonEnabled True MsgBox "Кнопка закрытия окна приложения разблокирована"End Sub

Обратите внимание, что псевдоним функции DLL указан только в первом

объявлении Windows API. На самом деле, псевдоним можно и не указывать,

однако тогда имя объявляемой функции должно полностью совпадать с ее

именем в библиотеке DLL.

На рис. 22.5 показан результат выполнения макроса DisableExcelXButton.

Блокирование кнопки закрытия окна формы

По аналогии с предыдущим примером создадим код, блокирующий кнопку

закрытия окна формы при инициализации последней.

Private Declare Function FindWindow Lib "user32" Alias _"FindWindowA" (ByVal lpClassName As String, _ByVal lpWindowName As String) As LongPrivate Declare Function GetSystemMenu Lib "user32" _

Page 553: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 553

(ByVal hwnd As Long, ByVal bRevert As Long) As LongPrivate Declare Function DeleteMenu Lib "user32" (ByVal hMenu _As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long

Private Const SC_CLOSE As Long = &HF060

Private Sub UserForm_Initialize() Dim hWndForm As Long Dim hMenu As Long

hWndForm = FindWindow("ThunderDFrame", Me.Caption) hMenu = GetSystemMenu(hWndForm, 0) DeleteMenu hMenu, SC_CLOSE, 0&End Sub

Результат выполнения обработчика события UserForm_Initialize поY

казан на рис. 22.6. Пользователь может закрыть форму только с помощью

щелчка на кнопке Выход.

Рис. 22.5. Для блокирования кнопки за&крытия окна приложения используютсяобъявления Windows API FindWindow,GetSystemMenu и DeleteMenu

Рис. 22.6. Единственный спо&соб закрыть форму заключа&ется в щелчке на кнопкеВыход

Часы

Функция Excel VBA ТДАТА (NOW) возвращает текущие дату и время, однако

ее возможностей оказывается недостаточно для реализации простых часов.

Данную функциональность можно получить с помощью объявлений Windows

API SetTimer, KillTimer и FindWindow, как показано ниже.

Private Declare Function SetTimer Lib "user32" _ (ByVal hwnd As Long, ByVal nIDEvent As Long, _ ByVal uElapse As Long, ByVal lpTimerFunc As Long) As LongPrivate Declare Function KillTimer Lib "user32" _ (ByVal hwnd As Long, ByVal nIDEvent As Long) As LongPrivate Declare Function FindWindow Lib "user32" _ Alias "FindWindowA" (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long

Private lngTimerID

Sub StartTimer()' Остановить текущий таймер. StopTimer

Page 554: ? Применение VBA и макросов в Microsoft® Excel

554 Часть III Удивительные возможности Visual Basic for Applications

lngTimerID = SetTimer(0, 1, 10, AddressOf RunTimer)End Sub

Sub StopTimer() Dim lRet As Long, lngTID As Long

If IsEmpty(lngTimerID) Then Exit Sub

lngTID = lngTimerID lRet = KillTimer(0, lngTID) lngTimerID = EmptyEnd Sub

Private Sub RunTimer(ByVal hwnd As Long, _ ByVal uint1 As Long, ByVal nEventId As Long, _ ByVal dwParam As Long)

On Error Resume Next Sheet1.Range("A1").Value = Format(Now, "hh:mm:ss")End Sub

Макрос StartTimer размещает часы в ячейке A1, как показано на

рис. 22.7.

Рис. 22.7. Часы, созданные с помощью объявлений Windows API Set-Timer, KillTimer и FindWindow

Создание гиперссылок

Объявление Windows API ShellExecute позволяет разместить на форме

гиперссылки YYYY надписи с адресом электронной почты или адресом WebY

сайта, щелчок на которых приводит к запуску соответствующего приложения.

Private Declare Function ShellExecute Lib "shell32.dll" _ Alias "ShellExecuteA" (ByVal hwnd As Long, _ ByVal lpOperation As String, ByVal lpFile As String, _ ByVal lpParameters As String, ByVal lpDirectory As String, _ ByVal nShowCmd As Long) As Long

Const SWNormal = 1

Private Sub lbl_Email_Click() Dim lngRow As Long

ShellExecute 0&, "open", "mailto:" & lbl_Email.Caption, _ vbNullString, vbNullString, SWNormalEnd Sub

Private Sub lbl_Website_Click() Dim lngRow As Long

ShellExecute 0&, "open", lbl_Website.Caption, _ vbNullString, vbNullString, SWNormalEnd Sub

Page 555: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 555

Щелчок на надписи [email protected] приводит к открытию программы,

предназначенной для работы с электронной почтой, а щелчок на надписи

www.mrexcel.com — к запуску обозревателя Internet, как показано на рис. 22.8.

Рис. 22.8. Объявление Windows API ShellExecute позволяет разместить на фор&ме гиперссылку надпись, щелчок на которой приводит к запуску внешнего при&ложения

Воспроизведение звуковых файлов

Желаете предупредить пользователя об опасности или поздравить его с усY

пешным выполнением задачи посредством воспроизведения звукового файла?

Воспользуйтесь объявлением Windows API PlayWavSound, как показано ниже.

Private Declare Function PlayWavSound Lib "winmm.dll" _ Alias "sndPlaySoundA" (ByVal LpszSoundName As String, _ ByVal uFlags As Long) As Long

Private Sub CommandButton2_Click() SoundName = Application.GetOpenFilename("Формат WAV _(*.wav), *.wav", , "Выберите файл формата WAV", "Воспроизвести") If SoundName = False Then Exit Sub

PlayWavSound SoundName, 0End Sub

Создание диалогового окна выбора файла

Рассмотрим код, использующий объявления Windows API для создания

диалогового окна выбора файла.

Page 556: ? Применение VBA и макросов в Microsoft® Excel

556 Часть III Удивительные возможности Visual Basic for Applications

Type tagOPENFILENAME lStructSize As Long hwndOwner As Long hInstance As Long strFilter As String strCustomFilter As String nMaxCustFilter As Long nFilterIndex As Long strFile As String nMaxFile As Long strFileTitle As String nMaxFileTitle As Long strInitialDir As String strTitle As String Flags As Long nFileOffset As Integer nFileExtension As Integer strDefExt As String lCustData As Long lpfnHook As Long lpTemplateName As StringEnd Type

Declare Function aht_apiGetOpenFileName Lib "comdlg32.dll" _ Alias "GetOpenFileNameA" (OFN As tagOPENFILENAME) As BooleanDeclare Function aht_apiGetSaveFileName Lib "comdlg32.dll" _ Alias "GetSaveFileNameA" (OFN As tagOPENFILENAME) As BooleanDeclare Function CommDlgExtendedError Lib "comdlg32.dll" () As Long

Global Const ahtOFN_READONLY = &H1Global Const ahtOFN_OVERWRITEPROMPT = &H2Global Const ahtOFN_HIDEREADONLY = &H4Global Const ahtOFN_NOCHANGEDIR = &H8Global Const ahtOFN_SHOWHELP = &H10Global Const ahtOFN_NOVALIDATE = &H100Global Const ahtOFN_ALLOWMULTISELECT = &H200Global Const ahtOFN_EXTENSIONDIFFERENT = &H400Global Const ahtOFN_PATHMUSTEXIST = &H800Global Const ahtOFN_FILEMUSTEXIST = &H1000Global Const ahtOFN_CREATEPROMPT = &H2000Global Const ahtOFN_SHAREAWARE = &H4000Global Const ahtOFN_NOREADONLYRETURN = &H8000Global Const ahtOFN_NOTESTFILECREATE = &H10000Global Const ahtOFN_NONETWORKBUTTON = &H20000Global Const ahtOFN_NOLONGNAMES = &H40000Global Const ahtOFN_EXPLORER = &H80000Global Const ahtOFN_NODEREFERENCELINKS = &H100000Global Const ahtOFN_LONGNAMES = &H200000

Function ahtCommonFileOpenSave( _ Optional ByRef Flags As Variant, _ Optional ByVal InitialDir As Variant, _ Optional ByVal Filter As Variant, _ Optional ByVal FilterIndex As Variant, _ Optional ByVal DefaultExt As Variant, _ Optional ByVal FileName As Variant, _ Optional ByVal DialogTitle As Variant, _ Optional ByVal hwnd As Variant, _ Optional ByVal OpenFile As Variant) As Variant

Page 557: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 557

' Эта функция вызывает стандартное диалоговое окно' выбора файла. Все перечисленные выше параметры' являются необязательными.'' Входящие параметры:' - Flags. Одна или несколько ahtOFN-констант,' объединенных оператором OR.' - InitialDir. Начальная папка.' - Filter. Набор фильтров отбора файлов' (для создания фильтров используется' функция ahtAddFilterItem).' - FilterIndex. Номер используемого фильтра.' По умолчанию 1.' - DefaultExt. Расширение файла, используемое' по умолчанию. Применяется при сохранении файла.' - FileName. Значение по умолчанию поля ввода имени файла.' - DialogTitle. Заголовок диалогового окна.' - hWnd. Дескриптор родительского окна.' - OpenFile. Булево значение: True - открыть файл,' False - сохранить файл.' Возвращаемый результат:' - Null или имя выбранного файла. Dim OFN As tagOPENFILENAME Dim strFileName As String Dim strFileTitle As String Dim fResult As Boolean

' Задать параметры диалогового окна. If IsMissing(InitialDir) Then InitialDir = CurDir If IsMissing(Filter) Then Filter = "" If IsMissing(FilterIndex) Then FilterIndex = 1 If IsMissing(Flags) Then Flags = 0& If IsMissing(DefaultExt) Then DefaultExt = "" If IsMissing(DialogTitle) Then DialogTitle = "" If IsMissing(OpenFile) Then OpenFile = True

' Создать строковые переменные для хранения' возвращаемых значений. strFileName = Left(FileName & String(256, 0), 256) strFileTitle = String(256, 0)

' Определить значение полей структуры OFN. With OFN .lStructSize = Len(OFN) .strFilter = Filter .nFilterIndex = FilterIndex .strFile = strFileName .nMaxFile = Len(strFileName) .strFileTitle = strFileTitle .nMaxFileTitle = Len(strFileTitle) .strTitle = DialogTitle .Flags = Flags .strDefExt = DefaultExt .strInitialDir = InitialDir .hInstance = 0 .lpfnHook = 0 .strCustomFilter = String(255, 0) .nMaxCustFilter = 255 End With

Page 558: ? Применение VBA и макросов в Microsoft® Excel

558 Часть III Удивительные возможности Visual Basic for Applications

' Передать структуру OFN функции Windows API,' отображающей диалоговое окно выбора файла. If OpenFile Then fResult = aht_apiGetOpenFileName(OFN) Else fResult = aht_apiGetSaveFileName(OFN) End If

' В результате вызова функции API значение поля strFile' структуры OFN было изменено. Следующий код извлекает' полученное значение поля strFile. If fResult Then' Информация о выбранном файле хранится в поле Flags' структуры OFN. Следующий код извлекает полученное' значение этого поля для последующего анализа. If Not IsMissing(Flags) Then Flags = OFN.Flags ahtCommonFileOpenSave = TrimNull(OFN.strFile) Else ahtCommonFileOpenSave = vbNullString End IfEnd Function

Private Function ahtAddFilterItem(strDescription As String, _strFilter As String, Optional varItem As Variant) As String' Эта функция создает фильтр файлов.' Фильтр файлов = описание фильтра файлов (например,' "Базы данных ") + символ NULL + шаблон фильтра файлов' (например, "*.mdb;*.mda ") + символ NULL. If IsMissing(varItem) Then varItem = "*.*" ahtAddFilterItem = strDescription & vbNullChar & strFilter & _ vbNullChar & varItem & vbNullCharEnd Function

Private Function TrimNull(ByVal strItem As String) As String Dim intPos As Integer

intPos = InStr(strItem, vbNullChar) If intPos > 0 Then TrimNull = Left(strItem, intPos - 1) Else TrimNull = strItem End IfEnd Function

Следующая функция отображает диалоговое окно выбора файла и возвраY

щает имя последнего.

Function GetFileName(strPath As String) Dim strFilter As String Dim lngFlags As Long

strFilter = "*.xls" strFilter = ahtAddFilterItem("Файлы Excel (*.xls)", strFilter)

GetFileName = ahtCommonFileOpenSave(InitialDir:=strPath, _ Filter:=strFilter, FilterIndex:=3, Flags:=lngFlags, _ DialogTitle:="Пожалуйста, выберите файл", FileName:="")End Function

Создайте пользовательскую форму. Ниже приведен код, выполняющийся в

результате щелчка на кнопке Выбрать файл, как показано на рис. 22.9. ОбраY

Page 559: ? Применение VBA и макросов в Microsoft® Excel

Интерфейс прикладного программирования (API) Windows Глава 22 559

тите внимание, что функция GetFileName принимает в качестве параметра

путь к папке, с которой будет начат обзор файловой системы.

Private Sub CommandButton2_Click() Dim txtFile As String

txtFile = GetFileName("C:\") If txtFile <> "" Then ListBox1.AddItem (txtFile) End IfEnd Sub

Рис. 22.9. Диалоговое окно, возвращающее имя выбранного файла

Дополнительные источники объявленийWindows API

Многие программисты не прочь поделиться опытом в создании и использоваY

нии объявлений Windows API. В частности, на WebYсайте Ивана Ф. Моалы (Ivan

F. Moala) The XcelFiles (www.xcelfiles.com) содержится множество примеров

объявлений Windows API с соответствующими пояснениями (посетите WebY

страницу по адресу: http://www.xcelfiles.com/APIIndex.html).

Следующий шагСледующая глава посвящена обработке ошибок.

Page 560: ? Применение VBA и макросов в Microsoft® Excel
Page 561: ? Применение VBA и макросов в Microsoft® Excel

Отладка кода с помощьюредактора VBA.............................. 561Обработка ошибокс помощью выраженияOn Error GoTo ................................ 564Универсальныеобработчики ошибок ................. 566Общение с заказчиками............ 569“Отложенные” ошибки ............. 569Несовершенство защитыпроекта VBA ..................................572Защита проекта VBA вразличных версиях Excel............573Совместимость различныхверсий Excel ...................................573Следующий шаг............................574

23Глава 23

Îáðàáîòêà îøèáîê

Сколько бы усилий ни было заY

трачено на тестирование и отладку

программного кода, рано или поздно

он даст сбой. Единственная защита

от непредвиденных ситуаций заклюY

чается в их планировании.

Отладка кодас помощьюредактора VBA

Обнаружив необработанную ошибY

ку в программном коде, редактор VBA

отображает диалоговое окно, пример

которого показан на рис. 23.1.

Щелкните на кнопке Debug(Отладка). Редактор VBA выделяет

строку кода, выполнение которой

привело к возникновению ошибки,

желтым цветом, как показано на

рис. 23.2.

Рис. 23.1. Результат обнаружения необрабо&танной ошибки в незащищенном модуле

Page 562: ? Применение VBA и макросов в Microsoft® Excel

562 Часть III Удивительные возможности Visual Basic for Applications

Рис. 23.2. Чтобы узнать текущее значение переменной, подве&дите к ней указатель мыши — и вы получите дополнительнуюинформацию о причине сбоя

К сожалению, редактор VBA не слишком разборчив в том, что касается опY

ределения типа ошибки. В частности, огромное число сбойных ситуаций

классифицируются как ошибка времени выполнения 1004. Таким образом,

единственный способ определения причины сбоя заключается в изучении

строки, на которой было остановлено выполнение программного кода, и теY

кущих значений переменных.

Установив возможные причины возникновения ошибки, щелкните на

кнопке Reset (Сброс), чтобы прекратить выполнение макроса (рис. 23.3).

Рис. 23.3. Кнопка Reset напоминает кнопку Стоп, располо&женную на пульте дистанционного управления CD& илиDVD&плейера

Внимание Попытка выполнения макроса в режиме отладки другого макроса приводит к ото&бражению сообщения об ошибке, показанного на рис. 23.4. Если запуск макросабыл инициирован с помощью интерфейса Excel, на экране появится окно редакто&ра VBA. Тем не менее, после щелчка на кнопке OK на экране вновь появится окноExcel, что весьма неудобно.

Отладка кода пользовательской формы

Иногда редактор VBA неверно определяет строку кода, выполнение котоY

рой привело к возникновению ошибки. Рассмотрим следующую ситуацию.

Предположим, что сбой произошел при выполнении кода формы, отображаеY

мой на экране в результате выполнения некоторого макроса. После перехода в

режим отладки редактор VBA выделяет желтым цветом строку вызова формы,

что может ввести в заблуждение. Чтобы отыскать настоящий источник ошибY

ки, выполните следующие действия.

Page 563: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 563

Рис. 23.4. Это сообщение выводится редактором VBA при попыткезапуска макроса в режиме отладки другого макроса

1. В окне сообщения об ошибке щелкните на кнопке Debug (Отладка),

как показано на рис. 23.5.

Рис. 23.5. Щелкните на кнопке Debug

2. Редактор VBA выделит желтым цветом строку вызова пользовательской

формы frmChoose.Show, как показано на рис. 23.6. Это неверное реY

шение, поскольку сбой произошел при выполнении кода пользовательY

ской формы.

Рис. 23.6. Редактор VBA неверно определяет строку, выполнениекоторой привело к возникновению ошибки

Page 564: ? Применение VBA и макросов в Microsoft® Excel

564 Часть III Удивительные возможности Visual Basic for Applications

3. Нажмите клавишу <F8>, чтобы выполнить метод frmChoose.Show.

Вместо выдачи сообщения об ошибке редактор VBA приступит к выY

полнению кода процедуры инициализации формы UserForm_Initialize.

4. Нажимайте клавишу <F8> до тех пор, пока редактор VBA вновь не отоY

бразит сообщение об ошибке. Поиск проблемного участка кода может

быть затруднен наличием длинного цикла, как показано на рис. 23.7.

Рис. 23.7. Число нажатий клавиши <F8>, необходимое для прохожденияцикла For...Next, прямо пропорционально числу его итераций

Для прохождения первой итерации цикла For...Next достаточно трех

нажатий клавиши <F8> (см. рис. 23.7). Каждая следующая итерация цикла

требует нажатия клавиши <F8> два раза. В частности, чтобы добавить в спиY

сок 25 элементов, клавишу <F8> придется нажать 51 раз.

Другими словами, отладка кода пользовательской формы представляет соY

бой весьма утомительное занятие. Запаситесь терпением и не забывайте слеY

дить за выполняемой на следующем шаге строкой.

Обработка ошибок с помощью выраженияOn Error GoTo

Логика обработки ошибок в VBA заключается в передаче выполнения кода

некоторому заранее подготовленному участку макроса.

Чтобы создать код обработки ошибки, выполните следующие действия.

1. Разместите строку Exit Sub после основного кода макроса, чтобы

предотвратить несанкционированное выполнение кода обработки

ошибки.

2. Добавьте метку после строки Exit Sub, например, MyErrorHandler:.

3. Разместите после метки код обработки ошибки. Чтобы передать выполY

нение кода строке макроса, следующей за строкой, которая привела к

возникновению ошибки, воспользуйтесь выражением Resume Next.

Page 565: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 565

4. Разместите строку On Error GoTo MyErrorHandler перед строкой,

выполнение которой может привести к возникновению ошибки. Обратите

внимание, что на этот раз двоеточие после имени метки ставить не нужно.

5. Разместите строку On Error GoTo 0 после строки кода, выполнение

которой может привести к возникновению ошибки. На самом деле,

метки с именем 0 не существует. Выражение On Error GoTo 0 поY

зволяет вернуться в обычный режим обработки ошибок.

Рассмотрим пример создания кода обработки ошибки открытия файла.

Sub HandleAnError() Dim MyFile As Variant

' Определить обработчик ошибок. On Error GoTo FileNotThere Workbooks.Open Filename:="C:\NotHere.xls"

' Вернуться в обычный режим обработки ошибок. On Error GoTo 0 MsgBox "Выполнение макроса завершено"

' Строка Exit Sub позволяет предотвратить' несанкционированное выполнение обработчика ошибки. Exit Sub

' Создать метку.FileNotThere: MyPrompt = "При открытии файла произошла ошибка. Вероятно, " MyPrompt = MyPrompt & "файл не существует. Щелкните на кнопке " MyPrompt = MyPrompt & "OK, чтобы указать расположение файла, " MyPrompt = MyPrompt & "или на кнопке Cancel, чтобы завершить " MyPrompt = MyPrompt & "выполнение макроса" Ans = MsgBox(Prompt:=MyPrompt, Buttons:=vbOKCancel) If Ans = vbCancel Then Exit Sub

' Отобразить диалоговое окно выбора файла. MyFile = Application.GetOpenFilename

' Если пользователь ничего не выбрал, завершить выполнение макроса. If MyFile = False Then Exit Sub

On Error GoTo 0 Workbooks.Open MyFile

' Передать выполнение кода строке макроса, следующей' за строкой, которая привела к возникновению ошибки. Resume NextEnd Sub

Использование нескольких обработчиков ошибок

В коде макроса можно разместить несколько различных обработчиков

ошибок. Единственным требованием при этом является наличие строки Re-sume Next или Exit Sub в конце кода каждого обработчика.

Page 566: ? Применение VBA и макросов в Microsoft® Excel

566 Часть III Удивительные возможности Visual Basic for Applications

Универсальные обработчики ошибокНекоторые программисты отдают предпочтение универсальному обработY

чику ошибок, позволяющему скрыть от пользователей сообщение об ошибке,

генерируемое редактором VBA. Как правило, универсальный обработчик

ошибок обращается к свойствам объекта Err, таким как номер ошибки и ее

описание.

Sub GenericHandler() On Error GoTo HandleAny

Sheets(9).Select

Exit SubHandleAny: Msg = "Произошла ошибка номер " & Err.Number & ". Описание _ошибки: " & Err.Description MsgBox Msg Exit Sub

End Sub

Игнорирование ошибок

Некоторые ошибки можно безболезненно проигнорировать. Вспомним

макрос создания WebYстраницы, рассматривавшийся в главе 14, ‘‘ВзаимодейY

ствие с Internet’’. Перед созданием HTMLYфайла sampledirectory.htmlмакрос WriteMembershipHTML удаляет существующую копию этого файла.

Выражение Kill (Файл) возвращает ошибку, если файл с именем Файлне существует. Однако эта ошибка столь несущественна, что ее можно проигY

норировать и продолжить выполнение макроса со следующей строки.

Sub WriteMembershipHTML() ... MyFile = "sampledirectory.html"

ThisFile = MyPath & Application.PathSeparator & MyFile ThisHostFile = MyFile

' Удалить существующую Web-страницу. On Error Resume Next Kill (ThisFile) On Error GoTo 0

' Открыть файл для записи. Open ThisFile For Output As #1 ...End Sub

Ни в коем случае не злоупотребляйте выражением On Error ResumeNext. Также не забывайте размещать строку On Error GoTo 0 сразу же поY

сле строки кода, выполнение которой может привести к возникновению

ошибки.

Page 567: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 567

Попытка проигнорировать критическую ошибку приводит к завершению

выполнения макроса. Если макрос А вызывает макрос Б и выполнение поY

следнего завершается аварийно, выполнение кода продолжается со строки

макроса А, следующей за строкой вызова макроса Б. Это чревато непредскаY

зуемыми последствиями.

Игнорирование ошибок задания параметров печати страницы

Запишите макрос, задающий параметры печати страницы. Установка всего

лишь одного значения в диалоговом окне Параметры страницы (Page Setup)

приводит к созданию множества строк кода. Проблема заключается в том, что

параметры печати страницы отличаются от принтера к принтеру. Например,

при создании макроса на компьютере с принтером, поддерживающим цветY

ную печать, средство записи макросов сгенерирует строку .BlackAndWhi-te = False. Выполнение этой строки на компьютере с принтером, поддерY

живающим только черноYбелую печать, приведет к возникновению ошибки.

Еще одной причиной сбоя может стать установка недопустимых значений паY

раметров, например, параметра, определяющего качество печати. Если макY

рос был создан на компьютере с принтером, поддерживающим разрешение

600 точек на дюйм, средство записи макросов сгенерирует строку

.PrintQuality = 600. Выполнение этой строки на компьютере с принтеY

ром, поддерживающим максимальное разрешение 300 точек на дюйм, привеY

дет к сбою. В данной ситуации рекомендуется разместить выражение On Er-ror Resume Next перед фрагментом кода, устанавливающим параметры

печати страницы, а выражение On Error GoTo 0 — после него.

On Error Resume NextWith ActiveSheet.PageSetup .PrintTitleRows = "" .PrintTitleColumns = ""End WithActiveSheet.PageSetup.PrintArea = "$A$1:$L$27"With ActiveSheet.PageSetup .LeftHeader = "" .CenterHeader = "" .RightHeader = "" .LeftFooter = "" .CenterFooter = "" .RightFooter = "" .LeftMargin = Application.InchesToPoints(0.25) .RightMargin = Application.InchesToPoints(0.25) .TopMargin = Application.InchesToPoints(0.75) .BottomMargin = Application.InchesToPoints(0.5) .HeaderMargin = Application.InchesToPoints(0.5) .FooterMargin = Application.InchesToPoints(0.5) .PrintHeadings = False .PrintGridlines = False .PrintComments = xlPrintNoComments .PrintQuality = 300 .CenterHorizontally = False .CenterVertically = False

Page 568: ? Применение VBA и макросов в Microsoft® Excel

568 Часть III Удивительные возможности Visual Basic for Applications

.Orientation = xlLandscape .Draft = False .Pauperize = xlPaperLetter .FirstPageNumber = xlAutomatic .Order = xlDownThenOver .BlackAndWhite = False .Zoom = False .FitToPagesWide = 1 .FitToPagesTall = False .PrintErrors = xlPrintErrorsDisplayedEnd WithOn Error GoTo 0

Игнорирование сообщений Excel

Некоторые сообщения Excel выводятся на экран вне зависимости от текуY

щего режима обработки ошибок. Например, при попытке удаления рабочего

листа на экране появится сообщение В листах, выбранных дляудаления, могут существовать данные. Чтобы удалить данные,нажмите кнопку "Удалить". (Data may exist in the sheet(s) selected for deleY

tion. To permanently delete the data, click Delete.). Это смущает многих пользоY

вателей, так как они полагают, что произошла какаяYлибо ошибка. Чтобы отY

ключить вывод сообщений Excel, воспользуйтесь выражением Applica-tion.DisplayAlerts = False.

Sub DeleteSheet() Application.DisplayAlerts = False Worksheets("Лист2").Delete Application.DisplayAlerts = TrueEnd Sub

Извлечение пользы из ошибок

Звучит весьма странно, однако даже ошибки могут приносить определенY

ную пользу. В частности, ошибки помогают разрабатывать более быстрый и

эффективный код.

Рассмотрим задачу проверки наличия в активной рабочей книге листа с

именем Данные. Ниже приведен код, решающий эту задачу без использоваY

ния ошибок.

Sub AvoidTheErrorLongerCode() DataFound = False For Each WS In ActiveWorkbook.Worksheets If WS.Name = "Данные" Then DataFound = True Exit For End If Next WS If Not DataFound Then Sheets.Add.Name = "Данные"End Sub

Page 569: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 569

Если активная рабочая книга содержит 128 листов, тело цикла ForEach...Next будет выполнено 128 раз при условии, что листа с именем

Данные в книге нет.

Альтернативный подход заключается в попытке обращения к листу

Данные. Проигнорируйте обработку ошибок с помощью выражения On Er-ror Resume Next и проверьте номер ошибки Err.Number. Если номер

ошибки отличен от нуля, листа Данные в рабочей книге нет.

Sub ErrorOnPurposeShorter() On Error Resume Next x = Worksheets("Данные").Name If Not Err.Number = 0 Then Sheets.Add.Name = "Данные" On Error GoTo 0End Sub

Очевидно, что макрос ErrorOnPurposeShorter выполняется быстрее

макроса AvoidTheErrorLongerCode. Иногда даже ошибки способны приY

носить пользу.

Общение с заказчикамиОдним из наиболее важных аспектов общения с заказчиками является окаY

зание поддержки в вопросах, возникающих при использовании разработанY

ных для них макросов.

Постарайтесь объяснить заказчикам разницу между сообщением об ошибY

ке и обычным сообщением Excel. К сожалению, сообщения обоих типов имеY

ют свойство сваливаться как снег на голову и сопровождаются звуковым сигY

налом. Конечно же, сообщение об ошибке не сулит ничего положительного,

однако далеко не каждое сообщение является сообщением об ошибке. Один

офисный работник постоянно жаловался своему начальнику на сбои, которые

возникают при выполнении разработанного нами макроса. На самом же деле

это были обычные информационные сообщения.

Попросите заказчика связаться с вами по телефону, если на экране возникY

нет окно сообщения об ошибке. Узнайте номер ошибки и ее описание, после

чего попросите заказчика щелкнуть на кнопке Debug (Отладка), сообщить имя

модуля, процедуры и содержимое строки, выделенной желтым цветом. ВооруY

жившись полученной информацией, постарайтесь определить причину сбоя.

“Отложенные” ошибкиЗапуская программный код в первый раз, его разработчик ожидает возникY

новения внештатных ситуаций. Для обнаружения ошибок на этапе тестироваY

ния кода последний часто выполняют в пошаговом режиме.

К сожалению, тестирование и отладка не гарантируют отсутствие ошибок

на этапе эксплуатации программы. Иногда первый сбой может произойти поY

сле нескольких месяцев ее успешного применения.

Page 570: ? Применение VBA и макросов в Microsoft® Excel

570 Часть III Удивительные возможности Visual Basic for Applications

Не спешите перекладывать ответственность за неработоспособность кода

на заказчика. Зачастую пристальное изучение ошибки приводит к выявлению

слабых мест, не учтенных на этапе разработки.

В следующих разделах рассматриваются примеры внештатных ситуаций,

способных возникнуть на этапе эксплуатации программного кода.

Ошибка времени выполнения 9: “Subscript out of range”Предположим, что переданная заказчику рабочая книга содержит лист

Меню. Через некоторое время заказчик сообщает о сбое и присылает вам коY

пию экрана, показанную на рис. 23.8.

Рис. 23.8. Одной из распространенных причин возникновения ошибкивремени выполнения 9 является попытка обращения к несуществующе&му рабочему листу

Приведенный ниже код предполагает наличие рабочего листа Меню. Если

заказчик удалил или переименовал рабочий лист Меню, возникнет ошибка.

Sub GetSettings() ThisWorkbook.Worksheets("Меню").Select x = Range("A1").ValueEnd Sub

К сожалению, описанная ситуация достаточно типична. Следующий код

позволяет заменить недружественное сообщение об ошибке редактора VBA

сообщением об отсутствии рабочего листа Меню.

Sub GetSettingsLonger() On Error Resume Next x = ThisWorkbook.Worksheets("Меню").Name If Not Err.Number = 0 Then MsgBox "Рабочий лист ""Меню"" не обнаружен" Exit Sub End If On Error GoTo 0

Page 571: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 571

ThisWorkbook.Worksheets("Меню").Select x = Range("A1").ValueEnd Sub

Ошибка времени выполнения 1004: “Method 'Range'of object '_Global' failed”

Предположим, что программный код ежедневно импортирует в Excel соY

держимое некоторого текстового файла, загружаемого с FTPYсервера. Макрос

SetReportInItalics выделяет курсивом последнюю строку полученного

результата, как показано ниже.

Sub SetReportInItalics()' Выполнение этого макроса вызовет сбой при условии,' что текстовый файл не был импортирован в Excel. TotalRow = Worksheets("Лист1").Range("F65536").End(xlUp).Row FinalRow = TotalRow - 1 Range("A1:A" & FinalRow).Font.Italic = TrueEnd Sub

Через некоторое время, прошедшее с начала эксплуатации программного

кода, заказчик сообщает об ошибке времени выполнения 1004 (рис. 23.9).

Рис. 23.9. Ошибка времени выполнения 1004может быть вызвана 1001 причиной

Подобная ошибка может возникнуть при условии, что импортированный

текстовый файл не содержал данных. В этом случае значение переменной To-talRow будет равно 1, а переменной FinalRow — 0. Попытка обращения к

несуществующей строке приведет к сбою.

Следующий код позволяет заменить сообщение об ошибке редактора VBA

сообщением о необходимости проверки правильности загрузки текстового

файла с FTPYсервера.

Sub SetReportInItalicsNoError() TotalRow = Worksheets("Лист1").Range("A65536").End(xlUp).Row FinalRow = TotalRow - 1 If FinalRow > 0 Then Range("A1:A" & FinalRow).Font.Italic = True Else MsgBox "Импортированный файл не содержит данных. _Попробуйте загрузить файл с FTP-сервера еще раз" End IfEnd Sub

Page 572: ? Применение VBA и макросов в Microsoft® Excel

572 Часть III Удивительные возможности Visual Basic for Applications

Несовершенство защиты проекта VBAПроект VBA можно защитить от просмотра. В этом случае окно сообщения

об ошибке редактора VBA будет содержать нефункциональную кнопку Debug(Отладка), лишающую пользователя возможности сообщить разработчику доY

полнительную информацию о произошедшем сбое.

Вдобавок, защита, обеспечиваемая редактором VBA, далеко не совершенY

на. Программисты из Эстонии создали приложение, которое взламывает заY

щиту любого проекта Excel. Другими словами, не усложняйте себе жизнь,

прибегая к защите проектов VBA.

Практикум

Взлом паролейВзлом паролей в Excel 97 и Excel 2000 не представлял никаких трудностей. Специ&альные программы в мгновение ока сообщали пользователю пароль проекта VBA.В Excel 2002 корпорация Microsoft предложила схему защиты, стойкую к атакампрограмм для взлома паролей. Благодаря применению шифрования единствен&ным способом взлома пароля проекта VBA на протяжении нескольких месяцев по&сле выхода Excel 2002 оставался способ простого подбора. И если для взлома4&значного пароля наподобие blue требовалось 10 минут, то взлом 24&значногопароля наподобие *A6%kJJ542(9$GgU44#2drt8 занимал около 20 часов. Безус&ловно, это затрудняло доступ к коду программистам Excel, желавшим воспользо&ваться чужой интеллектуальной собственностью.К сожалению, следующее поколение программ для взлома паролей справилось с24&значным паролем Excel 2002 за 2 секунды. Поначалу сообщение программыдля взлома пароля о том, что она определила искомый 24&значный пароль какXVII, кажется ошибкой. Проверив полученный результат, убеждаешься в обрат&ном. Дело в том, что вместо применения метода простого подбора программа ге&нерирует новый 4&значный пароль проекта VBA и сохраняет его в файле рабочейкниги Excel.Подобный подход к взлому пароля может породить весьма пикантную ситуацию.Предположим, что разработчик устанавливает пароль проекта VBA*A6%kJJ542(9$GgU44#2drt8 и передает файл заказчику. Если заказчик изменитпароль, а затем обратится за помощью к разработчику, он будет вынужден пере&слать ему файл рабочей книги Excel, защищенный новым паролем. Единственный,кто способен извлечь выгоду из такой ситуации, — это талантливый программистиз Эстонии.На момент написания этой книги число VBA&проектов Excel превышало число раз&работчиков, способных их реализовать. Большинство разработчиков отдает себеотчет в том, что созданный ими код может быть доступен любому человеку, у ко&торого имеется файл рабочей книги.Тем не менее, многие начинающие программисты все еще продолжают защищатьпаролем созданные ими проекты VBA. Рассмотрим следующую ситуацию.

Page 573: ? Применение VBA и макросов в Microsoft® Excel

Обработка ошибок Глава 23 573

Предположим, что заказчик желает внести изменения в существующий VBA&проект. Он связывается с разработчиком, который выполняет всю необходимуюработу. Спустя месяц заказчик вновь обращается к разработчику, который на этотраз не может выполнить задание своевременно. Заказчик не хочет ждать и обра&щается к другому программисту.Поскольку проект VBA защищен паролем, новому разработчику придется еговзломать, чтобы получить доступ к программному коду. Если в будущем заказчикпланирует сотрудничать с первоначальным создателем кода, может возникнутьситуация, в которой два разработчика будут иметь два разных пароля для доступак проекту VBA. В подобной ситуации рекомендуется полностью отказаться от за&щиты программного кода паролем.

Защита проекта VBA в различных версиях ExcelСхема защиты проекта VBA паролем в Excel 2002 несовместима со схемой

защиты проекта VBA паролем в Excel 97. Другими словами, защиту проекта

VBA, установленную с помощью Excel 2002, нельзя снять средствами Excel 97.

В частности, это приводит к тому, что пользователь Excel 97 не сможет ни отY

ладить сбойный код, ни передать разработчику подробную информацию о

возникнувшей ошибке.

Защита проекта VBA паролем приносит больше неприятностей, чем пользы.

Совместимость различных версий ExcelКорпорация Microsoft совершенствует VBA в каждой новой версии Excel.

В частности, переход от Excel 97 к Excel 2000 был отмечен изменением кода

создания сводных таблиц, а также некоторых аспектов работы с диаграммами.

Одним из нововведений Excel 2002 является параметр TrailingMinus-Numbers метода OpenText. Попытка выполнения кода, расположенного

в одном модуле с параметром TrailingMinusNumbers, приведет к ошибке

компиляции в Excel 2000. Рассмотрим пример.

Предположим, что модуль Module1 содержит макросы ProcA, ProcBи ProcC, а модуль Module2 — макросы ProcD и ProcE. Макрос ProcEвключает вызов метода OpenText с параметром TrailingMinusNumbers.

Благодаря отсутствию кода, специфичного для Excel 2002, макросы ProcA,

ProcB и ProcC могут быть выполнены в Excel 2000 без необходимости внесеY

ния какихYлибо изменений, а вот попытка выполнения макроса ProcD приY

ведет к ошибке компиляции модуля Module2. Окончательно запутать ситуаY

цию способен тот факт, что причина сбоя находится не в макросе ProcD,

а в макросе ProcE.

Одно из возможных решений описанной выше проблемы заключается

в тестировании кода VBA во всех версиях Excel, включая Excel 97. Следует

отметить, что Excel 97 с набором исправлений SRY2 намного устойчивее

Page 574: ? Применение VBA и макросов в Microsoft® Excel

574 Часть III Удивительные возможности Visual Basic for Applications

первоначального выпуска Excel 97. Поскольку далеко еще не все пользоваY

тели Excel 97 установили набор исправлений SRY2, тестировать придется оба

выпуска.

Пользователи Macintosh ошибочно полагают, что версия Excel для MacinY

tosh и версия Excel для Windows одинаковы. На самом деле совместимость ExY

cel для Macintosh и Excel для Windows заканчивается на формате файлов и

пользовательском интерфейсе. Код VBA Windows и Macintosh не совместим.

Несмотря на внешнюю схожесть, код VBA Windows и Macintosh отличается

множеством мелких аспектов.

Следующий шагСколько бы усилий ни было затрачено на тестирование и отладку проY

граммного кода, рано или поздно он даст сбой. В этой главе были рассмотреY

ны различные способы обработки ошибок, отладка кода и другие вопросы,

связанные с возникновением непредвиденных ситуаций.

Следующая глава посвящена созданию пользовательских меню и панелей

инструментов.

Page 575: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательскогоменю ...............................................575Создание пользовательскойпанели инструментов .................581Другие способы запускамакросов ........................................587Следующий шаг........................... 592

24Глава 24

Ñîçäàíèåïîëüçîâàòåëüñêèõìåíþ è ïàíåëåéèíñòðóìåíòîâ

В этой главе рассматривается созY

дание пользовательских меню и паY

нелей инструментов, предназначенY

ных для запуска макросов. В конце

главы будут описаны способы запусY

ка макросов с помощью сочетания

клавиш, кнопки и элемента управлеY

ния ActiveX.

Созданиепользовательскогоменю

Пользовательское меню прекрасY

но подходит для размещения команд

запуска макросов, созданных для заY

казчика. На рис. 24.1 показано польY

зовательское меню, разработанное

для вымышленной компании XYZ.

Создание и удалениепользовательского меню

Строка главного меню Excel предY

ставлена объектом VBA Applica-tion.CommandBars(1) и включает

такие меню, как Файл (File), Правка(Edit), Вид (View) и т.д. Чтобы добаY

вить к главному меню новый пункт,

воспользуйтесь методом Add. При

добавлении нового пункта меню неY

обходимо указать его имя и располоY

жение.

Page 576: ? Применение VBA и макросов в Microsoft® Excel

576 Часть III Удивительные возможности Visual Basic for Applications

Рис. 24.1. Пользовательское меню, названное по именизаказчика, подчеркивает уникальность разработанногодля него приложения

Имя пункта меню (например, XYZ Co) отображается в строке меню. БольY

шинству пунктов меню сопоставлено некоторое сочетание клавиш, такое как

<Alt+В> (<Alt+V>) для меню Вид (View). Сочетание клавиш, назначенное тоY

му или иному пункту меню, определяет подчеркнутая буква в его имени. ЧтоY

бы задать сочетание клавиш для пункта меню, поставьте символ амперсанда

(&) перед требуемой буквой, например, &XYZ Co.

Следует помнить, что сочетания клавиш <Alt+А> (<Alt+I>), <Alt+В>

(<Alt+V>), <Alt+Д> (<Alt+D>), <Alt+Е> (<Alt+T>), <Alt+М> (<Alt+O>),

<Alt+О> (<Alt+W>), <Alt+П> (<Alt+E>), <Alt+С> (<Alt+H>) и <Alt+Ф>

(<Alt+F>) зарезервированы для стандартных меню Excel. Несмотря на то, что

одно и то же сочетание клавиш может быть назначено двум различным пункY

там меню, оно не будет функциональным.

По умолчанию строка меню Excel содержит 10 пунктов: значок Excel, Файл(File), Правка (Edit), Вид (View), Вставка (Insert), Формат (Format), Сервис(Tools), Данные (Data), Окно (Window) и Справка (Help). Чтобы добавить ноY

вый пункт меню перед пунктом Справка, установите значение параметра Be-fore метода Add равным 10. Чтобы добавить новый пункт меню после пункта

Справка, установите значение параметра Before метода Add равным 11. ДоY

бавление нового пункта меню после пункта Справка в Excel для Macintosh

приведет к возникновению ошибки, поскольку в MacintoshYприложениях

пункт Справка всегда должен оставаться последним пунктом меню.

Рекомендуется предусмотреть процедуры создания и удаления меню. ПроY

цедуру создания меню следует вызвать в обработчике события Work-book_Open, Workbook_Activate или Worksheet_Activate, а процедуру

удаления меню YYYY в обработчике события Workbook_BeforeClose.

Чтобы не допустить дублирования меню, вызовите в самом начале процеY

дуры создания меню процедуру его удаления.

Page 577: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 577

Ниже приведен код макроса, создающего меню (CreateMenu), и макроса,

удаляющего меню (DeleteMenu). Объектная переменная MenuObject имеет

тип CommandBarPopup. Макрос CreateMenu вызывает макрос DeleteMenu,

после чего добавляет в строку главного меню Excel пункт XYZ Co перед пункY

том Справка.

Sub DeleteMenu()' Этот макрос должен быть выполнен' перед закрытием рабочей книги. On Error Resume Next Application.CommandBars(1).Controls("&XYZ Co").Delete On Error GoTo 0End Sub

Sub CreateMenu() Dim MenuObject As CommandBarPopup Dim MenuItem As Object Dim SubMenuItem As Object

' Удалить существующее меню. Call DeleteMenu

Set MenuObject = Application.CommandBars(1). _ Controls.Add(Type:=msoControlPopup, _ Before:=10, Temporary:=True) MenuObject.Caption = "&XYZ Co"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ImportData" MenuItem.Caption = "&Импорт данных"

End Sub

Добавление команд меню

Чтобы добавить команду меню, воспользуйтесь методом MenuOb-ject.Controls.Add, установив значение параметра Type равным msoCon-trolButton. MenuObject — это созданный ранее объект меню типа Com-mandBarPopup. Объект команды меню имеет свойство Caption, опредеY

ляющее текст команды, и OnAction, определяющее макрос, который будет

выполнен при выборе этой команды.

Следующий код создает меню XYZ Co, содержащее четыре команды, как

показано на рис. 24.2.

Sub CreateSimpleMenu() Dim MenuObject As CommandBarPopup Dim MenuItem As Object Dim SubMenuItem As Object

' Удалить существующее меню. Call DeleteMenu

Set MenuObject = Application.CommandBars(1). _

Page 578: ? Применение VBA и макросов в Microsoft® Excel

578 Часть III Удивительные возможности Visual Basic for Applications

Controls.Add(Type:=msoControlPopup, _ Before:=10, Temporary:=True) MenuObject.Caption = "&XYZ Co"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ImportData" MenuItem.Caption = "&Импорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ExportData" MenuItem.Caption = "&Экспорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ProduceReport" MenuItem.Caption = "От&чет"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "AboutMe" MenuItem.Caption = "О про&грамме"End Sub

Группирование команд меню

Команды меню можно группировать. Чтобы создать линию раздела двух

групп команд меню, установите значение свойства BeginGroup первой коY

манды меню, расположенной за линией, равным True. Следующий код поY

мещает линию раздела между третьей и четвертой командой меню, как покаY

зано на рис. 24.3.

Рис. 24.2. Меню, со&держащее четыре ко&манды

Рис. 24.3. Чтобы создать линиюраздела двух групп команд ме&ню, воспользуйтесь свойствомBeginGroup

Sub CreateGroupedMenu()' Этот макрос помещает линию раздела двух групп' команд меню перед командой "О программе". Dim MenuObject As CommandBarPopup Dim MenuItem As Object Dim SubMenuItem As Object

' Удалить существующее меню. Call DeleteMenu

Set MenuObject = Application.CommandBars(1). _ Controls.Add(Type:=msoControlPopup, _ Before:=10, Temporary:=True)

Page 579: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 579

MenuObject.Caption = "&XYZ Co"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ImportData" MenuItem.Caption = "&Импорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ExportData" MenuItem.Caption = "&Экспорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ProduceReport" MenuItem.Caption = "От&чет"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "AboutMe" MenuItem.Caption = "О про&грамме"' Следующая строка создает линию раздела. MenuItem.BeginGroup = TrueEnd Sub

Создание подменю

Подменю позволяет сократить число команд меню путем вынесения неY

скольких команд в отдельный пункт. На рис. 24.4 показано подменю Отчет,

содержащее команды для создания всевозможных отчетов.

Рис. 24.4. Как правило, подменю используется для ло&гического группирования команд меню

Чтобы создать подменю, воспользуйтесь методом MenuObject.Con-trols.Add, установив значение параметра Type равным msoControl-Popup. MenuObject — это созданный ранее объект меню типа CommandBar-Popup.

Чтобы добавить команду подменю, воспользуйтесь методом MenuItem.Con-trols.Add, установив значение параметра Type равным msoControlBut-ton. MenuItem — это созданный ранее объект подменю типа Object.

Page 580: ? Применение VBA и макросов в Microsoft® Excel

580 Часть III Удивительные возможности Visual Basic for Applications

Приведенный ниже код создает подменю, показанное на рис. 24.4.

Sub CreateFullMenu() Dim MenuObject As CommandBarPopup Dim MenuItem As Object Dim SubMenuItem As Object

' Удалить существующее меню. Call DeleteMenu

Set MenuObject = Application.CommandBars(1). _ Controls.Add(Type:=msoControlPopup, _ Before:=10, Temporary:=True) MenuObject.Caption = "&XYZ Co"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ImportData" MenuItem.Caption = "&Импорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "ExportData" MenuItem.Caption = "&Экспорт данных"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlPopup) MenuItem.Caption = "От&чет" MenuItem.BeginGroup = True

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "StyleRptNew" SubMenuItem.Caption = "Отчет о товарах"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "CategoryRptNew" SubMenuItem.Caption = "Отчет о группах товаров"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "ReportCard" SubMenuItem.Caption = "Карточка отчета"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "OverRpt" SubMenuItem.Caption = "Отчет о товарах за год" SubMenuItem.BeginGroup = True

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "CreateReportCard" SubMenuItem.Caption = "Отчет о магазинах"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "InventoryAgingReportNew" SubMenuItem.Caption = "Отчет о складских запасах"

Page 581: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 581

SubMenuItem.BeginGroup = True

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "ShowStockReport" SubMenuItem.Caption = "Магазины с критическим _уровнем запасов"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "ShowRecTransfer" SubMenuItem.Caption = "Рекомендуемые перемещения товаров"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "ShowSummaryNew" SubMenuItem.Caption = "Итоговый отчет"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlPopup) MenuItem.Caption = "&Диаграмма"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "GraphOne" SubMenuItem.Caption = "Диаграмма &продаж"

Set SubMenuItem = MenuItem.Controls.Add(Type:= _msoControlButton) SubMenuItem.OnAction = "GraphTwo" SubMenuItem.Caption = "Диаграмма &запасов"

Set MenuItem = MenuObject.Controls.Add(Type:=msoControlButton) MenuItem.OnAction = "AboutMe" MenuItem.Caption = "О про&грамме" MenuItem.BeginGroup = TrueEnd Sub

Создание пользовательской панели инструментовКоманды запуска макросов, созданных для заказчика, можно также разY

мещать на панели инструментов. На рис. 24.5 показан пример пользовательY

ской панели, содержащей несколько различных элементов управления.

Рис. 24.5. Кнопка, размещенная на панели инстру&ментов, может содержать только текст, только значокили же и значок, и текст. Чтобы задать текст всплы&вающей подсказки, воспользуйтесь свойством эле&мента управления ToolTipText

Page 582: ? Применение VBA и макросов в Microsoft® Excel

582 Часть III Удивительные возможности Visual Basic for Applications

Создание и удаление пользовательской панелиинструментов

По аналогии с пользовательским меню, предусмотрите процедуры для созY

дания и удаления панели инструментов. Процедуру создания панели инструY

ментов следует вызвать в обработчике события Workbook_Open, Work-book_Activate или Worksheet_Activate, а процедуру удаления панели

инструментов YYYY в обработчике события Workbook_BeforeClose.

Макрос CreateToolbar создает плавающую панель инструментов. ПреY

дыдущие версии Excel позволяли закреплять панель инструментов, однако деY

лать этого не рекомендуется.

Чтобы создать панель инструментов, воспользуйтесь методом Command-Bars.Add, указав имя и тип панели инструментов. Ниже приведен код макY

росов CreateToolbar и DeleteToolbar.

Sub DeleteToolbar() On Error Resume Next CommandBars("XYZ").Delete On Error GoTo 0End Sub

Sub CreateToolbar() Dim Tbar As CommandBar Dim NewDD As CommandBarControl Dim NewBtn As CommandBarButton

' Удалить существующую панель инструментов. DeleteToolbar

' Создать панель инструментов. Set Tbar = CommandBars.Add With Tbar .Name = "XYZ" .Visible = True .Position = msoBarFloating End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .OnAction = "PrintCard" .Caption = "Печать..." .TooltipText = "Выберите страницы для печати" .Style = msoButtonCaption End WithEnd Sub

Добавление кнопок на панель инструментов

Чтобы добавить кнопку на созданную ранее панель инструментов TBar,

воспользуйтесь методом TBar.Controls.Add. Макрос, который будет выY

полнен в результате щелчка на кнопке, определяет ее свойство OnAction.

Page 583: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 583

Кроме того, кнопке можно назначить текст (свойство Caption), значок

(свойство FaceID) и всплывающую подсказку (свойство ToolTipText).

Свойство Style определяет содержимое кнопки YYYY только текст

(msoButtonCaption), только значок (msoButtonIcon) или же и текст, и

значок (msoButtonIconAndCaption). Как показано на рис. 24.5, кнопка

Печать содержит только текст, кнопка Фотографии YYYY текст и значок, а кнопY

ка Отчеты YYYY только значок.

Следующий код создает панель инструментов, содержащую кнопки Пе-чать, Фотографии и Отчеты.

Sub CreateToolbar() Dim Tbar As CommandBar Dim NewDD As CommandBarControl Dim NewBtn As CommandBarButton

' Удалить существующую панель инструментов. DeleteToolbar

' Создать панель инструментов. Set Tbar = CommandBars.Add With Tbar .Name = "XYZ" .Visible = True .Position = msoBarFloating End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .OnAction = "PrintCard" .Caption = "Печать..." .TooltipText = "Выберите страницы для печати" .Style = msoButtonCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 682 .OnAction = "DispPictures" .Caption = "Фотографии" .TooltipText = "Показать фотографии выбранных товаров" .Style = msoButtonIconAndCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 461 .OnAction = "ProduceReport" .Caption = "Отчеты" .TooltipText = "Создать отчеты" .Style = msoButtonIcon End WithEnd Sub

Page 584: ? Применение VBA и макросов в Microsoft® Excel

584 Часть III Удивительные возможности Visual Basic for Applications

Выбор значка кнопки панели инструментов

Значок кнопки панели инструментов определяется значением свойства

кнопки FaceID. При выборе значения свойства FaceID рекомендуется восY

пользоваться обозревателем значков. Один из бесплатных обозревателей

значков доступен по адресу: http://skp.mvps.org/faceid.htm.

Добавление раскрывающегося списка на панельинструментов

Добавим на панель инструментов раскрывающийся список, содержащий

имена всех видимых листов рабочей книги Excel. При выборе имени рабочего

листа из списка выполняется макрос GoToSheet, делающий выбранный раY

бочий лист активным. Следующий код создает панель инструментов, содерY

жащую кнопки Печать, Фотографии, Отчеты, а также раскрывающийся спиY

сок Перейти к рабочему листу.

Sub CreateToolbar() Dim Tbar As CommandBar Dim NewDD As CommandBarControl Dim NewBtn As CommandBarButton Dim Sh As Worksheet

' Удалить существующую панель инструментов. DeleteToolbar

' Создать панель инструментов. Set Tbar = CommandBars.Add With Tbar .Name = "XYZ" .Visible = True .Position = msoBarFloating End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .OnAction = "PrintCard" .Caption = "Печать..." .TooltipText = "Выберите страницы для печати" .Style = msoButtonCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 682 .OnAction = "DispPictures" .Caption = "Фотографии" .TooltipText = "Показать фотографии выбранных товаров" .Style = msoButtonIconAndCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 461

Page 585: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 585

.OnAction = "ProduceReport" .Caption = "Отчеты" .TooltipText = "Создать отчеты" .Style = msoButtonIcon End With Set NewDD = Tbar.Controls.Add(Type:=msoControlDropdown) With NewDD .Caption = "Перейти к рабочему листу" .OnAction = "GoToSheet" .Style = msoButtonAutomatic For Each Sh In ActiveWorkbook.Worksheets If Sh.Visible = True Then .AddItem Sh.Name End If Next Sh .ListIndex = 1 .Width = 110 End WithEnd Sub

Ниже приведен код макроса GoToSheet.

Sub GoToSheet() Dim ThisItem As Integer Dim ThisName As String

With CommandBars("XYZ").Controls("Перейти к рабочему листу") ThisItem = .ListIndex ThisName = .List(.ListIndex) End With' Сделать лист активным. Worksheets(ThisName).ActivateEnd Sub

Сохранение и восстановление координатпанели инструментов

Координаты панели инструментов изменяются каждый раз при ее создаY

нии. Добавим к макросам DeleteToolbar и CreateToolbar код, позвоY

ляющий сохранить и восстановить координаты панели инструментов.

Public Sub DeleteToolbar() Dim obj As CommandBar

On Error Resume Next Set obj = CommandBars("XYZ") If Err.Number = 0 Then' Запомнить текущие координаты' панели инструментов. With ThisWorkbook.Sheets("Параметры") .[I5].Value = obj.Top .[I6].Value = obj.Left End With End If obj.DeleteEnd Sub

Page 586: ? Применение VBA и макросов в Microsoft® Excel

586 Часть III Удивительные возможности Visual Basic for Applications

Sub CreateToolbar() Dim nTop As Variant Dim nLeft As Variant Dim Tbar As CommandBar Dim NewDD As CommandBarControl Dim NewBtn As CommandBarButton Dim Sh As Worksheet

' Удалить существующую панель инструментов. DeleteToolbar

With ThisWorkbook.Sheets("Параметры") nTop = .[I5].Value nLeft = .[I6].Value End With

' Создать панель инструментов. Set Tbar = CommandBars.Add With Tbar .Name = "XYZ" .Visible = True .Position = msoBarFloating If Not IsEmpty(nTop) Then .Top = nTop If Not IsEmpty(nLeft) Then .Left = nLeft End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .OnAction = "PrintCard" .Caption = "Печать..." .TooltipText = "Выберите страницы для печати" .Style = msoButtonCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 682 .OnAction = "DispPictures" .Caption = "Фотографии" .TooltipText = "Показать фотографии выбранных товаров" .Style = msoButtonIconAndCaption End With

Set NewBtn = Tbar.Controls.Add(Type:=msoControlButton) With NewBtn .FaceId = 461 .OnAction = "ProduceReport" .Caption = "Отчеты" .TooltipText = "Создать отчеты" .Style = msoButtonIcon End With Set NewDD = Tbar.Controls.Add(Type:=msoControlDropdown) With NewDD .Caption = "Перейти к рабочему листу" .OnAction = "GoToSheet" .Style = msoButtonAutomatic

Page 587: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 587

For Each Sh In ActiveWorkbook.Worksheets If Sh.Visible = True Then .AddItem Sh.Name End If Next Sh .ListIndex = 1 .Width = 110 End WithEnd Sub

Другие способы запуска макросовПомимо меню и панели инструментов, для запуска макроса можно испольY

зовать сочетание клавиш, кнопку и элемент управления ActiveX.

Запуск макроса с помощью сочетания клавиш

Чтобы назначить сочетание клавиш для запуска макроса, выберите имя

макроса в диалоговом окне Макрос (Macro) и щелкните на кнопке Параметры(Options). (Чтобы открыть диалоговое окно Макрос, выберите команду главY

ного меню Excel Сервис Макрос Макросы (Tools Macro Macros) или наY

жмите комбинацию клавиш <Alt+F8>.) Задайте сочетание клавиш, как покаY

зано на рис. 24.6.

Рис. 24.6. Чтобы выполнить макросJump, нажмите сочетание клавиш<Ctrl+J>

Внимание Будьте внимательны при выборе сочетания клавиш для запуска макроса. Многие со&четания клавиш (например, <Ctrl+C>) зарезервированы для выполнения стандартныхопераций в Windows. Относительно безопасными сочетаниями клавиш в Excel 2003являются сочетания <Ctrl+E>, <Ctrl+J>, <Ctrl+M>, <Ctrl+Q> и <Ctrl+T>.

Запуск макроса с помощью кнопки

На рабочем листе Excel можно разместить два типа кнопок: стандартную

кнопку пользовательской формы и кнопку элемента управления ActiveX.

Page 588: ? Применение VBA и макросов в Microsoft® Excel

588 Часть III Удивительные возможности Visual Basic for Applications

Выполните следующие действия, чтобы вынести команду добавления

кнопки пользовательской формы на панель управления Excel и разместить на

рабочем листе кнопку запуска макроса.

1. Щелкните на панели инструментов Excel правой кнопкой мыши и выY

берите команду контекстного меню Настройка (Customize).

2. Выберите категорию Формы (Forms) из списка Категории (Categories)

вкладки Команды (Commands) диалогового окна Настройка (Customize).

3. Перетащите команду Кнопка (Button) из списка Команды на панель инY

струментов Excel.

4. Щелкните на кнопке Закрыть (Close), чтобы закрыть диалоговое окно

Настройка.

5. Щелкните на кнопке Кнопка, вынесенной на панель инструментов.

6. С помощью указателя мыши нарисуйте на рабочем листе контур кнопки.

7. Выберите имя макроса в открывшемся диалоговом окне Назначьтемакрос объекту (Assign Macro) и щелкните на кнопке OK.

8. Выделите текст кнопки и измените его на более значащий.

9. Чтобы изменить цвет, шрифт и другие параметры внешнего вида кнопY

ки, щелкните на ней правой кнопкой мыши и выберите команду конY

текстного меню Формат объекта (Format Control).

10. Чтобы назначить кнопке другой макрос, щелкните на ней правой кнопY

кой мыши и выберите команду контекстного меню Назначить макрос(Assign Macro).

Внимание Существует две версии диалогового окна Формат элемента управления (FormatControl). Одна из них содержит семь вкладок (Шрифт (Font), Выравнивание(Alignment), Размер (Size), Защита (Protection), Свойства (Properties), Поля(Margins) и Веб (Web)), другая — только одну (Шрифт (Font)). В результате щелчка правой кнопкой мыши над элементом управления вокруг негопоявляется рамка, заполненная диагональными отрезками (рис. 24.7) или точками(рис. 24.8). В первом случае выбор команды контекстного меню Формат объектаприводит к отображению диалогового окна Формат элемента управления с однойвкладкой, во втором — с семью. Чтобы изменить заливку рамки элемента управления с диагональных отрезков наточки, щелкните на рамке левой кнопкой мыши.

Помимо кнопки, макрос можно назначить любому графическому объекту,

расположенному на рабочем листе Excel. Например, чтобы назначить макрос

автофигуре, щелкните на ней правой кнопкой мыши и выберите команду конY

текстного меню Назначить макрос (Assign Macro), как показано на рис. 24.9.

Page 589: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 589

Рис. 24.7. Выбор команды контекстного менюФормат объекта приведет к отображению диа&логового окна Формат элемента управления,содержащего одну вкладку

Рис. 24.8. Выбор команды контекстного менюФормат объекта приведет к отображению диа&логового окна Формат элемента управления,содержащего семь вкладок

Рис. 24.9. Макрос можно назначить любомуграфическому объекту, расположенному на ра&бочем листе Excel

Page 590: ? Применение VBA и макросов в Microsoft® Excel

590 Часть III Удивительные возможности Visual Basic for Applications

Назначение макроса автофигуре можно реализовать с помощью программY

ного кода, создав автофигуру и присвоив значение ее свойству OnAction. Тем

не менее, этот метод имеет один существенный недостаток: если назначаемый

макрос находится в другой рабочей книге Excel, то при ее сохранении и заY

крытии Excel изменит значение свойства OnAction, включив в него полный

путь к содержащей макрос рабочей книге.

Запуск макроса с помощью элемента управления ActiveX

Чтобы запустить макрос с помощью элемента управления ActiveX, создайте

процедуру ИмяЭлементаУправленияActiveX_Click, содержащую вызов

макроса или его код. Для этого выполните следующие действия.

1. Выберите команду главного меню Excel Вид Панели инструментовЭлементы управления (View Toolbars Control Toolbox).

2. Щелкните на кнопке Кнопка (Command Button), расположенной на паY

нели инструментов Элементы управления. С помощью указателя мыY

ши нарисуйте на рабочем листе контур кнопки.

3. Чтобы изменить параметры элемента управления ActiveX, щелкните на

кнопке Свойства (Properties), расположенной на панели инструментов

Элементы управления. На экране появится окно свойств, позволяюY

щее задать такие параметры элемента управления, как текст, цвет и др.

(рис. 24.10).

Рис. 24.10. Окно свойств элемента управления ActiveX позволяет на&строить его параметры

Page 591: ? Применение VBA и макросов в Microsoft® Excel

Создание пользовательских меню и панелей инструментов Глава 24 591

На заметку Закрытие окна свойств элемента управления ActiveX приводит к закрытию окнасвойств редактора VBA.

4. Чтобы назначить макрос элементу управления ActiveX, щелкните на

кнопке Исходный текст (View Code), расположенной на панели инстY

рументов Элементы управления. Разместите в тексте обработчика соY

бытия ИмяЭлементаУправленияActiveX_Click вызов требуемого

макроса или его код, как показано на рис. 24.11.

Рис. 24.11. Чтобы ввести код обработчика собы&тия ИмяЭлементаУправленияActiveX_Click,щелкните на кнопке Исходный текст, располо&женной на панели инструментов Элементыуправления

Практикум

Запуск макроса с помощью гиперссылкиЧтобы запустить макрос с помощью гиперссылки, следует прибегнуть к неболь&шой хитрости. Выделите ячейку, в которой требуется разместить гиперссылку, по&сле чего выберите команду главного меню Excel Вставка Гиперссылка (InsertHyperlink) или нажмите комбинацию клавиш <Ctrl+K>. В открывшемся диалого&вом окне Добавление гиперссылки (Insert Hyperlink) щелкните на кнопке Местомв документе (Place in This Document). В поле Введите адрес ячейки (Type the cellreference) введите адрес ячейки, в которой находится гиперссылка. Таким обра&зом, гиперссылка будет указывать сама на себя (рис. 24.12).Для запуска требуемого макроса воспользуйтесь обработчиком события Work-sheet_FollowHyperlink, как показано ниже:Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink) Select Case Target.TextToDisplay Case "Widgets" RunWidgetReport Case "Gadgets" RunGadgetReport Case "Gizmos" RunGizmoReport Case "Doodads" RunDooDadReport End SelectEnd Sub

Page 592: ? Применение VBA и макросов в Microsoft® Excel

592 Часть III Удивительные возможности Visual Basic for Applications

Рис. 24.12. Чтобы назначить макрос гиперссылке, создайте гиперссылку, ука&зывающую саму на себя, и воспользуйтесь обработчиком события

Worksheet_FollowHyperlink для запуска требуемого макроса

Следующий шагСледующая глава посвящена использованию надстроек в качестве контейY

неров для размещения макросов.

Page 593: ? Применение VBA и макросов в Microsoft® Excel

Стандартные надстройкиExcel ................................................ 593Преобразование рабочейкниги Excel в надстройку ........... 594Использование надстроек .........597Альтернативное решение:использование скрытойрабочей книги.............................. 599Следующий шаг............................601

25Глава 25

Íàäñòðîéêè

Надстройки YYYY это программы,

добавляющие в Excel дополнительY

ные команды и возможности.

В этой главе рассматриваются

стандартные надстройки Excel, котоY

рые можно создать средствами VBA.

Существует также два других типа

надстроек: надстройки COM и надY

стройки DLL, однако эти надстройки

можно создать только с помощью ViY

sual Basic (например, Visual Basic 6 или

Visual Basic .NET) или Visual C++.

Стандартныенадстройки Excel

Стандартные надстройки Excel

(.xla) могут использоваться в качеY

стве контейнера макросов. Ниже пеY

речислены основные преимущества

надстроек.

Выполнение обработчика соY

бытия Workbook_Open можY

но отменить путем удерживаY

ния нажатой клавиши <Shift>

при открытии рабочей книги

Excel. Этот трюк невозможно

проделать с обработчиком соY

бытия Workbook_Open, разY

мещенным в надстройке.

После установки надстройки с

помощью диалогового окна

Надстройки (AddYIns) она будет

загружаться при каждом запуске

Excel. (Чтобы открыть диалогоY

вое окно Надстройки, выберите

команду главного меню Excel

Сервис Надстройки (Tools

AddYIns).)

Page 594: ? Применение VBA и макросов в Microsoft® Excel

594 Часть III Удивительные возможности Visual Basic for Applications

Размещенный в надстройке код выполняется вне зависимости от выY

бранного уровня безопасности макросов.

Обычно область выполнения макросов ограничивается рабочей книY

гой, в которой они были объявлены. Код, размещенный в надстройке,

доступен всем открытым рабочим книгам Excel.

Надстройки не отображаются в списке открытых файлов меню Окно(Window) и не могут быть выведены на экран с помощью команды

Окно Отобразить (Window Unhide).

Поскольку надстройка является скрытой рабочей книгой, которую нельзя

вывести на экран, не существует возможности выделить или активизировать

ячейки надстройки посредством программного кода. Вдобавок, сохранение

файла надстройки необходимо реализовать в коде самой надстройки, наприY

мер, вызвав метод ThisWorkbook.Save в обработчике события Work-book_BeforeClose.

Внимание Впервые возможность сохранения файла надстройки была реализована в Excel 97.

Преобразование рабочей книги Excelв надстройку

Диалоговое окно Надстройки (AddYIns) содержит список доступных надY

строек. Имя и описание надстройки задается с помощью диалогового окна

свойств файла рабочей книги Excel.

Чтобы задать имя и описание надстройки, выберите команду главного меY

ню Excel Файл Свойства (File Properties) и перейдите во вкладку Документ(Summary), как показано на рис. 25.1.

Введите имя надстройки в поле Название (Title), а ее описание YYYY в поле

Заметки (Comments).

Существует два способа преобразования рабочей книги Excel в надстройку.

Первый способ проще, однако он не лишен некоторых недостатков. Второй

способ требует выполнения большего числа действий, но позволяет лучше

контролировать процесс создания надстройки.

Преобразование рабочей книги Excel в надстройку спомощью диалогового окна “Сохранение документа”(Save As)

Чтобы преобразовать рабочую книгу Excel в надстройку с помощью диаY

логового окна Сохранение документа, выберите команду главного меню ExY

cel Файл Сохранить как (File Save As). Выберите формат НадстройкаMicrosoft Office Excel (Microsoft Office Excel AddYIn (*.xla)) из раскрывающегоY

Page 595: ? Применение VBA и макросов в Microsoft® Excel

Надстройки Глава 25 595

ся списка Тип файла (Save as type). Обратите внимание, что папка, в которой

будет сохранена надстройка, изменится на AddIns, как показано на рис. 25.2.

Рис. 25.1. Заполните поля Название и Заметкиперед преобразованием рабочей книги Excel внадстройку

Рис. 25.2. По умолчанию надстройки Excel сохраняются в папке AddIns

Полный путь к папке AddIns зависит от операционной системы, установY

ленной на компьютере. Например, в Windows XP это может быть папка

Page 596: ? Применение VBA и макросов в Microsoft® Excel

596 Часть III Удивительные возможности Visual Basic for Applications

C:\Documents and Settings\ИмяПользователя\Application Data\Microsoft\AddIns. После преобразования рабочей книги Excel (.xls) в

надстройку (.xla) файл XLS все еще остается открытым. Хранить этот файл

не имеет смысла, так как надстройку легко преобразовать в рабочую книгу.

Внимание При преобразовании рабочей книги Excel в надстройку с помощью диалоговогоокна Сохранение документа текущим активным листом должен быть рабочийлист. Если текущим активным листом является лист диаграммы, форматНадстройка Microsoft Office Excel окажется недоступен.

Преобразование рабочей книги Excel в надстройкус помощью редактора VBA

Откройте рабочую книгу Excel, которую необходимо преобразовать в надY

стройку. В окне редактора VBA щелкните на модуле ЭтаКнига (ThisWorkbook) и

присвойте параметру IsAddin значение True, как показано на рис. 25.3.

Рис. 25.3. Чтобы преобразовать рабочую книгу внадстройку, присвойте параметру IsAddin модуляЭтаКнига значение True

Нажмите комбинацию клавиш <Ctrl+G>, чтобы открыть окно Immediate(Быстрое выполнение). В окне Immediate введите следующую строку и наY

жмите клавишу <Enter>, чтобы сохранить файл с расширением .xla.

ThisWorkbook.SaveAs FileName:="C:\ClientFiles\Chap25.xla", _FileFormat:=xlAddIn

Page 597: ? Применение VBA и макросов в Microsoft® Excel

Надстройки Глава 25 597

Использование надстроекЧтобы установить надстройку, выполните следующие действия.

1. Запустите Excel и выберите команду главного меню СервисНадстройки (Tools AddYIns).

2. Щелкните на кнопке Обзор (Browse), расположенной в открывшемся

диалоговом окне Надстройки (AddYIns) (рис. 25.4).

Рис. 25.4. Щелкните на кнопке Обзор,чтобы выбрать файл надстройки

3. Выберите файл надстройки с помощью диалогового окна Обзор(Browse) и щелкните на кнопке OK (рис. 25.5).

Рис. 25.5. Выберите файл надстройки и щелкните на кнопке OK

Page 598: ? Применение VBA и макросов в Microsoft® Excel

598 Часть III Удивительные возможности Visual Basic for Applications

Excel скопирует указанную надстройку в папку AddIns. Имя и описание

надстройки будут совпадать со значениями, введенными в поле Название(Title) и Заметки (Comments) вкладки Документ (Summary) диалогового окна

свойств файла рабочей книги Excel (рис. 25.6).

Рис. 25.6. Надстройка готова к использованию

Безопасность стандартных надстроек Excel

Чтобы отобразить стандартную надстройку Excel, достаточно открыть окно

редактора VBA и присвоить параметру IsAddin модуля ЭтаКнига(ThisWorkbook) значение True. Для защиты проекта VBA выполните следуюY

щие действия.

1. Откройте окно редактора VBA.

2. Выберите команду Tools VBAProject Properties (Сервис Свойства

проекта VBA).

3. Перейдите во вкладку Protection (Защита).

4. Установите флажок Lock project for viewing (Запретить просмотр проекта).

5. Введите пароль и подтверждение пароля.

На заметку Современные программы для взлома паролей справляются с защитой проектаVBA в считанные секунды. Более подробно этот вопрос рассматривается в разделе“Взлом паролей” главы 23 на с. 572.

Page 599: ? Применение VBA и макросов в Microsoft® Excel

Надстройки Глава 25 599

Выгрузка надстроек

Чтобы выгрузить надстройку из памяти, выполните одно из следующих

действий.

1. Снимите флажок надстройки в диалоговом окне Надстройки (AddYIns).

В результате выполнения этого действия надстройка становится недосY

тупной в рамках текущего и всех последующих сеансов работы с Excel.

2. Откройте окно Immediate (Быстрое выполнение) редактора VBA. В окне

Immediate введите следующую строку и нажмите клавишу <Enter>:

Workbooks("ИмяФайлаНадстройки.xla").Close

3. Закройте Excel. Завершение текущего сеанса работы с Excel приводит к

автоматической выгрузке из памяти всех надстроек.

Удаление надстроек

Чтобы удалить надстройку из списка доступных надстроек диалогового окY

на Надстройки (AddYIns), выполните следующие действия.

1. Закройте все открытые сеансы работы с Excel.

2. Отыщите файл надстройки с помощью средства Проводник (Windows

Explorer). На компьютере с Windows XP файл надстройки может нахоY

диться в папке C:\Documents and Settings\ИмяПользователя\Application Data\Microsoft\AddIns.

3. Переименуйте файл надстройки или переместите его в другую папку.

4. Запустите Excel. На экране появится сообщение о том, что Excel не моY

жет найти файл надстройки. Щелкните на кнопке OK, чтобы закрыть

окно сообщения.

5. Выберите команду главного меню Excel Сервис Надстройки (Tools

AddYIns). В окне Надстройки снимите флажок надстройки, которую неY

обходимо удалить. Excel предупредит об отсутствии надстройки и предY

ложит ее удалить. Щелкните на кнопке Да (Yes), чтобы удалить надY

стройку из списка доступных надстроек.

Альтернативное решение: использованиескрытой рабочей книги

Одна из ключевых характеристик надстроек состоит в том, что надстройки

являются скрытыми рабочими книгами. Однако для создания скрытой рабоY

чей книги ее совсем не обязательно преобразовывать в надстройку.

Чтобы скрыть рабочую книгу, выберите команду главного меню Excel

Окно Скрыть (Window Hide). Сохранить скрытую рабочую книгу можно

только с помощью редактора VBA, поскольку стандартные средства Excel сдеY

Page 600: ? Применение VBA и макросов в Microsoft® Excel

600 Часть III Удивительные возможности Visual Basic for Applications

лать этого не позволяют. Выделите рабочую книгу в окне диспетчера проекY

тов, введите следующую строку в окне Immediate (Быстрое выполнение) и

нажмите клавишу <Enter>:

ThisWorkbook.Save

Практикум

Размещение программного кодаи пользовательских форм в скрытойрабочей книгеРазработчики приложений Access размещают данные и программный код в раз&ных базах данных, объединяя их с помощью средства связывания таблиц.Аналогичный подход рекомендуется применять при создании крупных проектов вExcel. Все данные можно разместить в рабочей книге Data.xls, связав ее с рабо&чей книгой Code.xls с помощью небольшого фрагмента программного кода.Преимущество разделения данных и кода заключается в возможности обновленияпоследнего без необходимости изменения пользовательских данных.Рассмотрим следующую ситуацию. Предположим, что некоторое приложение Ex&cel, реализованное в виде одного файла рабочей книги, было передано50 агентам по продаже товаров, каждый из которых, в свою очередь, распростра&нил его среди 10 крупных заказчиков. Если в приложении будет обнаруженаошибка, ее потребуется исправить во всех 500 копиях рабочей книги.Очевидно, что исходное приложение нуждается в существенной переработке.Создадим две рабочие книги — для хранения данных (Data.xls) и программногокода (Code.xls). Рабочая книга Data.xls будет содержать около 20 строк кода,открывающего рабочую книгу Code.xls и передающего ей управление при от&крытии рабочей книги Data.xls, а также закрывающего рабочую книгуCode.xls при закрытии рабочей книги Data.xls.Разделение данных и кода имеет несколько преимуществ. Во&первых, существен&но уменьшится размер файла данных. Во&вторых, для внесения изменений в при&ложение достаточно исправить код рабочей книги Code.xls и распространить еесреди всех пользователей.Будьте особенно внимательны при разработке и тестировании кода, помещае&мого в рабочую книгу с данными. Ошибка, допущенная в этом коде, может по&влечь за собой необходимость исправления сотен файлов рабочих книг.Ниже приведен пример кода, помещаемого в рабочую книгу Data.xls.Private Sub Workbook_Open()' Проверить, открыт ли файл Code.xls. On Error Resume Next x = Workbooks("Code.xls").Name ErrHolder = Err.Number On Error GoTo 0 If ErrHolder <> 0 Then' Открыть рабочую книгу, содержащую программный код. CodeFile = ThisWorkbook.Path & _

Page 601: ? Применение VBA и макросов в Microsoft® Excel

Надстройки Глава 25 601

Application.PathSeparator & "Code.xls" On Error Resume Next Workbooks.Open CodeFile ErrHolder = Err.Number On Error GoTo 0 End If

' Выполнить макрос, содержащийся в рабочей книге Code.xls. If ErrHolder = 0 Then Application.Run "'Code.xls'!CustFileOpen" End IfEnd Sub

Процедура CustFileOpen может использоваться для создания меню, внесенияизменений в файл данных и т.п.Разделение данных и программного кода является ключевым моментом при раз&работке сложного приложения Excel. Для внесения изменений в приложениедостаточно исправить код рабочей книги Code.xls и распространить ее средивсех пользователей.

Следующий шагПоследняя глава книги представляет собой практикум Тушара Мехты

(Tushar Mehta) YYYY независимого консультанта, имеющего статус Microsoft

MVP. Тушар демонстрирует процесс создания приложения Excel ‘‘с нуля’’.

Page 602: ? Применение VBA и макросов в Microsoft® Excel
Page 603: ? Применение VBA и макросов в Microsoft® Excel

О Тушаре Мехта........................... 603Постановка задачи ..................... 604Решение......................................... 605Реализация решенияс помощью Excel и VBA .............. 606Резюме............................................614

26Глава 26

Ïðàêòèêóì:ñîçäàíèåïðèëîæåíèÿExcel “ñ íóëÿ”

Эта глава представляет собой

практикум Тушара Мехты (Tushar

Mehta) YYYY независимого консультанY

та, имеющего статус Microsoft MVP.

Тушар демонстрирует процесс создаY

ния приложения Excel ‘‘с нуля’’, заY

трагивая множество различных воY

просов проектирования.

О Тушаре Мехта Тушар Мехта, магистр менеджY

мента, доктор философии, проживаY

ет в Рочестере, штат НьюYЙорк,

США. ГYн Тушар YYYY независимый

консультант, специализирующийся

на разработке бизнесYрешений, объеY

диняющих в себе технологию, оргаY

низационную структуру, маркетинг и

производство. Финансовые и эконоY

мические результаты предлагаемых

Тушаром решений заключаются в

повышении производительности, боY

лее эффективном маркетинге, росте

дохода, снижении операционных

расходов и улучшении потребительY

ской ценности.

Начиная с 2000 года, Тушар ежеY

годно удостаивается звания MVP

(Most Valuable Professional) от корпоY

рации Microsoft. Подобного успеха

удалось добиться только 65 разработY

Page 604: ? Применение VBA и макросов в Microsoft® Excel

604 Часть III Удивительные возможности Visual Basic for Applications

чикам Excel. С некоторыми из созданных Тушаром решений вы можете ознаY

комиться на его личном WebYсайте по адресу: http://www.tushar-mehta.com.

Имея степень доктора делового администрирования, полученную в униY

верситете Рочестера, Тушар также является магистром менеджмента бизнесY

школы Йельского университета и бакалавром технологии в области электроY

техники (специальность YYYY вычислительная техника) Индийского технологиY

ческого института в Бомбее, Индия.

Постановка задачи Рассмотрим применение Excel в качестве платформы, используемой для

документирования конфигурации системы электрического управления,

состоящей из 6000 контактных точек. Каждая контактная точка может быть

соединена с другой контактной точкой с помощью некоторого проводника.

Предложенное решение должно предусматривать возможность одновременY

ного использования всех контактных точек.

Идентификация контактных точек осуществляется по следующей схеме.

Каждой точке ставится в соответствие комбинация из двух чисел m/nnn, где mпринимает значения в диапазоне от 1 до 10 (по горизонтали), а nnn — от 101 до

700 (по вертикали).

Каждая из 6000 контактных точек представлена одной ячейкой рабочего

листа Excel. Если контактная точка соединена с другой контактной точкой, в

соответствующую ей ячейку заносится адрес контактной точки на другом конY

це соединения.

Контактная точка не может быть использована более чем в одном соединеY

нии. Помимо создания, соединения можно разрывать и изменять. Очевидно,

что поддержание подобной системы документации вручную представляет соY

бой чрезвычайно утомительное занятие с большой вероятностью внесения неY

верных данных.

Процесс разработки соответствующего решения можно разделить на слеY

дующие этапы.

Отображение терминологии проблемной области (терминологии заY

казчика) на терминологию Excel.

Разработка визуального представления проблемной области.

Разработка функциональных процедур, соответствующих ключевым

возможностям приложения.

Разработка процедур VBA, реализующих предусмотренные на предыY

дущем этапе функциональные процедуры.

Возможно ли автоматизировать подобную систему? И если да, то каким

образом? Очевидно, что для решения задачи достаточно реализовать автомаY

тическое занесение кода контактной точки А в ячейку контактной точки Б

Page 605: ? Применение VBA и макросов в Microsoft® Excel

Практикум: создание приложения Excel “с нуля” Глава 26 605

при вводе кода последней в ячейку контактной точки А. И конечно же, нужно

запретить установку соединения с контактной точкой Б, если она уже испольY

зуется в другом соединении.

Чтобы разорвать соединение, пользователь должен удалить содержимое

любой из ячеек, соответствующих участвующим в соединении контактным

точкам. Например, чтобы разорвать соединение между контактной точкой

1/101 и контактной точкой 10/700, пользователю необходимо удалить содерY

жимое ячейки, соответствующей контактной точке 1/101, или ячейки, соотY

ветствующей контактной точке 10/700. Система восстановит начальное знаY

чение и формат ячеек.

Процесс изменения соединения состоит из двух этапов. Первый этап заY

ключается в удалении существующего соединения, второй этап YYYY в создании

нового соединения.

Решение Матрица электрических контактов состоит из 100 элементов по горизонтаY

ли и 60 элементов по вертикали. Рабочий лист Excel удовлетворяет этим параY

метрам, так как содержит 256 столбцов и 65 536 строк.

Создадим матрицу контактных точек путем введения их кодов в формате

m/nnn в ячейки рабочего листа, начиная с ячейки A1. Код контактной точки,

не участвующей в соединении, выделен светлоYсерым шрифтом, как показано

на рис. 26.1.

При попытке создания соединения система анализирует предыдущее соY

стояние ячейки и ее новое содержимое. Если код соответствующей контактY

ной точки был выделен светлоYсерым цветом (‘‘нет соединения’’), проверяетY

ся возможность создания указанного соединения. При благоприятном резульY

тате содержимое ячеек на обоих концах соединения обновляется и выделяется

синим цветом. На рис. 26.2 показан результат соединения контактных точек

1/101 и 1/175.

Рис. 26.1. Код контактной точки, не участвую&щей в соединении, выделен светло&серымшрифтом

Рис. 26.2. Коды контактных точек, участвую&щих в соединении, выделяются синим цветом

Помимо создания нового соединения, система должна обеспечить разрыв и

изменение существующего соединения. Разрыв соединения соответствует удаY

лению содержимого ячейки с помощью клавиши <Delete> или <Backspace>.

Page 606: ? Применение VBA и макросов в Microsoft® Excel

606 Часть III Удивительные возможности Visual Basic for Applications

Чтобы изменить соединение, достаточно ввести в ячейку новый код контактной

точки. Система разорвет существующее соединение и создаст новое.

Предлагаемое решение не обеспечивает защиты от непреднамеренного

разрушения матрицы контактных точек. Например, вставка в рабочий лист

матрицы контактных точек диапазона ячеек с другого рабочего листа приведет

к разрушению матрицы. Целостность матрицы может быть нарушена также в

результате удаления ячеек рабочего листа с помощью команды меню Excel.

Реализация защиты целостности матрицы контактных точек выходит за рамки

данного практикума.

Реализация решения с помощью Excel и VBA Один из ключевых моментов этого практикума состоит в использовании

обработчиков событий. Известно, что большое число обработчиков событий

затрудняет тестирование и отладку программного кода. Таким образом, горазY

до проще потратить чуть больше времени на создание надежного кода, чем

пытаться отладить сбойный код путем тестирования.

Разделим процесс реализации решения на два параллельных потока. С одY

ной стороны, при создании кода будет использоваться принцип нисходящего

программирования. С другой стороны, по мере конкретизации кода к проекту

будут добавляться так называемые ключевые компоненты, выполняющие

роль ‘‘мостов’’ между моделью приложения и моделью Excel.

Этап 1а: нисходящее программирование

Любой обработчик события может быть размещен на одном из трех уровY

ней: уровне рабочего листа, уровне рабочей книги или уровне приложения.

Воспользуемся обработчиками событий уровня рабочей книги, поскольку, воY

первых, это позволит обеспечить поддержку нескольких матриц электричеY

ских контактов (каждая матрица размещается на отдельном рабочем листе), а,

воYвторых, реализовать обработчики событий уровня рабочей книги проще,

чем обработчики событий уровня приложения. Наиболее существенный неY

достаток подобного подхода заключается в совмещении кода и данных в одY

ной и той же рабочей книге Excel. Поскольку обработчики событий будут выY

зываться вне зависимости от того, содержит рабочий лист матрицу электричеY

ских контактов или нет, необходимо также создать специальный дескрипторрабочего листа матрицы контактов.

Разместите код обработчика события Workbook_SheetChange в модуле

ЭтаКнига (ThisWorkbook).

Private Sub Workbook_SheetChange( _ ByVal Sh As Object, ByVal Target As Range) If Not TypeOf Sh Is Worksheet Then Exit Sub If Not (Sh.Range(cWSWiringTagAddr).Value = _cWSWiringTagID) Then Exit Sub '<<<<<End Sub

Page 607: ? Применение VBA и макросов в Microsoft® Excel

Практикум: создание приложения Excel “с нуля” Глава 26 607

Действие, предпринимаемое в результате изменения содержимого ячейки

рабочего листа матрицы контактов (создание нового соединения или разY

рыв/изменение существующего), на данном этапе не конкретизируется.

Процедура, инициализирующая матрицу, заполняет ячейки рабочего листа

соответствующими кодами контактных точек в формате m/nnn, изменяя цвет

шрифта ячейки на светлоYсерый. Кроме того, процедура инициализации

предлагает удалить существующее содержимое рабочего листа и добавляет к

нему дескриптор рабочего листа матрицы контактов. Разместите следующий

код в стандартном модуле.

Sub createWiringData(aWS As Worksheet)End Sub

Sub addWiringWSTag(aWS As Worksheet)End Sub

Sub initializeSystem() If Not TypeOf ActiveSheet Is Worksheet Then MsgBox "Активным листом должен быть рабочий лист" Exit Sub '<<<<< End If If Not (ActiveSheet.UsedRange.Address = "$A$1" And _ IsEmpty(Range("a1"))) Then If MsgBox("Рабочий лист содержит данные. " _& "Щелкните на кнопке OK, чтобы удалить их", vbOKCancel) _= vbCancel Then Exit Sub '<<<<< End If createWiringData ActiveSheet addWiringWSTag ActiveSheetEnd Sub

Код процедур createWiringData и addWiringWSTag будет создан на

следующих этапах разработки приложения.

Этап 1б: создание ключевых компонентов

Создадим ключевой компонент, преобразующий коды контактных точек

m/nnn в адреса ячеек рабочего листа Excel, и наоборот. Адрес ячейки рабочего

листа Excel состоит из двух частей: номера строки и номера столбца. Функция

XLtoWiringCoords преобразует адрес ячейки в код контактной точки, а

функция WiringToExcelCoords YYYY код контактной точки в адрес ячейки.

Для представления адреса ячейки применяется пользовательский тип Excel-Coords. Разместите следующий код в стандартном модуле.

Public Type ExcelCoords Row As Long Col As Long End Type

Function XLtoWiringCoords(aRow As Long, aCol As Long) XLtoWiringCoords = CStr((aCol - 1) \ 10 + 1) & "/" _ & CStr(100 + (aRow - 1) * 10 + (aCol - 1) Mod 10 + 1)End Function

Page 608: ? Применение VBA и макросов в Microsoft® Excel

608 Часть III Удивительные возможности Visual Basic for Applications

Function WiringToExcelCoords(WiringCode As String) As ExcelCoords Dim FirstPart As Long, SecondPart As Long, SlashLoc As Long SlashLoc = InStr(1, WiringCode, "/") If SlashLoc = 0 Then Exit Function On Error Resume Next FirstPart = CLng(Left(WiringCode, SlashLoc - 1)) SecondPart = CLng(Right(WiringCode, Len(WiringCode) - SlashLoc)) On Error GoTo 0 If FirstPart < 1 Or FirstPart > 10 _Then Exit Function '<<<<< If SecondPart < 101 Or SecondPart > 700 _Then Exit Function '<<<<< WiringToExcelCoords.Row = (SecondPart - 101) \ 10 + 1 WiringToExcelCoords.Col = (FirstPart - 1) * 10 + _ (SecondPart - 101) Mod 10 + 1End Function

Объявим несколько глобальных констант. В стандартной цветовой палитре

Excel светлоYсерый цвет, использующийся для представления свободных конY

тактных точек, имеет индекс 15, а синий цвет, использующийся для представY

ления занятых контактных точек, YYYY индекс 5. Дескриптор рабочего листа

матрицы контактов будет представлен глобальной константой cWSWiring-TagID, размещенной в ячейке cWSWiringTagAddr. Поместите следующий

код в начало стандартного модуля, содержащего процедуру initializeSys-tem, а также функции преобразования XLtoWiringCoords и WiringToEx-celCoords.

Public Const _ cUnusedColorIdx As Integer = 15, _ cInUseColorIdx As Integer = 5, _ cWSWiringTagID As String = "Матрица электрических контактов", _ cWSWiringTagAddr As String = "A61"

Первый этап разработки приложения завершен. Следует отметить, что созY

данный код не только компилируется, но даже выполняется!

Этап 2а: нисходящее программирование

Создадим код процедуры addWiringWSTag, объявленной на предыдущем

этапе разработки.

Sub addWiringWSTag(aWS As Worksheet) Application.EnableEvents = False On Error GoTo ErrHandler aWS.Range(cWSWiringTagAddr).Value = cWSWiringTagID Application.EnableEvents = True Exit SubErrHandler: MsgBox "Непредвиденная ошибка в процедуре addWiringWSTag:" _& vbNewLine & "Ошибка=" & Err.Description & " (" & Err.Number & ")" Application.EnableEvents = TrueEnd Sub

Page 609: ? Применение VBA и макросов в Microsoft® Excel

Практикум: создание приложения Excel “с нуля” Глава 26 609

Процедура createWiringData создает матрицу кодов контактных точек

(значений в формате m/nnn), начиная со значения 1/101 в ячейке A1 и заканY

чивая значением 10/700 в ячейке CV60. Указанная матрица состоит из

10 блоков значений от m/101 до m/700 (m=1, 2,..., 10), каждый из которых

представлен в Excel диапазоном ячеек, содержащим 60 строк и 10 столбцов.

Следующий код создает блок значений nnn, копирует его 9 раз (таким обраY

зом, всего будет создано 10 таких блоков) и добавляет соответствующее значеY

ние m/ к каждому блоку.

Sub createWiringData(aWS As Worksheet) Dim Dest As Range, i As Long'Процедура createWiringData создает матрицу кодов _контактных точек (значений в формате m/nnn), начиная _со значения 1/101 в ячейке A1 и заканчивая значением 10/700 _в ячейке CV60. Указанная матрица состоит из 10 блоков значений _от m/101 до m/700 (m=1, 2,..., 10), каждый из которых представлен _в Excel диапазоном ячеек, содержащим 60 строк и 10 столбцов. _Следующий код создает блок значений nnn, копирует его 9 раз (таким _образом, всего будет создано 10 таких блоков) и добавляет _соответствующее значение m/ к каждому блоку. При создании _nnn-блоков используется общий формат чисел, а при добавлении _значения m/ - текстовый формат ячеек, иначе выражение m/nnn будет _интерпретировано как деление двух чисел. Application.EnableEvents = False On Error GoTo ErrHandler resetFormatting aWS createOneDataBlock aWS cloneDataBlocks aWS addMSlash aWS Application.EnableEvents = True Exit SubErrHandler: MsgBox "Непредвиденная ошибка в процедуре createWiringData:" _& vbNewLine & "Ошибка=" & Err.Description & " (" & Err.Number & ")" Application.EnableEvents = TrueEnd Sub

Последней процедурой, созданной на первом этапе и нуждающейся в конY

кретизации, является обработчик события Workbook_SheetChange, срабаY

тывающий при изменении содержимого ячейки рабочего листа Excel. Если

новое значение ячейки отличается от старого, необходимо определить тип

действия: создание нового соединения, разрыв существующего соединения

или изменения существующего соединения.

Изменение значения ячейки, соответствующей незанятой контактной точке

(светлоYсерый цвет шрифта), свидетельствует о создании нового соединения.

Разрыв соединения осуществляется путем удаления содержимого ячейки с

помощью нажатия клавиши <Delete> или <Backspace>. Таким образом, о разY

рыве соединения свидетельствует пустая ячейка.

Все остальные действия классифицируются как попытка изменения сущеY

ствующего соединения.

Если пользователь попытается нарушить целостность матрицы, его нужно

уведомить об этом и восстановить предыдущее значение ячейки.

Page 610: ? Применение VBA и макросов в Microsoft® Excel

610 Часть III Удивительные возможности Visual Basic for Applications

Чтобы сохранить предыдущее значение ячейки, воспользуемся обработчиY

ком события Workbook_SheetSelectionChange, срабатывающим при выY

делении ячейки.

Этап 2б: создание ключевых компонентов

Создадим обработчик события Workbook_SheetSelectionChange, соY

храняющий предыдущее значение ячейки при ее выделении. Возможность выY

деления пользователем нескольких ячеек следует запретить, так как это привеY

дет к существенному усложнению программного кода. Ниже приведен код проY

цедур Workbook_SheetChange, Workbook_SheetSelectionChange, ‘‘загоY

товки’’ процедур создания и разрыва соединения (addAConnection и de-leteAConnection, соответственно), а также полный код процедуры изменеY

ния соединения (changeAConnection). Последняя проверяет корректность

введенного пользователем значения, сохраняет его, после чего вызывает проY

цедуры удаления и создания нового соединения. Весь следующий код должен

быть помещен в модуль ЭтаКнига (ThisWorkbook).

Dim OldVal As String

Function addAConnection(Sh As Worksheet, Target As Range)End Function

Sub deleteAConnection(Sh As Worksheet, Target As Range, _OldVal As String)End Sub

Sub changeAConnection(Sh As Worksheet, Target As Range, _OldVal As String) Dim Conn2 As ExcelCoords Dim SavedVal As String Conn2 = WiringToExcelCoords(Target.Value) If Conn2.Row = 0 Then MsgBox Target.Value & " : недопустимое значение" Application.EnableEvents = False Target.Value = OldVal Application.EnableEvents = True Exit Sub '<<<<< End If SavedVal = Target.Value deleteAConnection Sh, Target, OldVal Application.EnableEvents = False Target.Value = SavedVal Application.EnableEvents = True addAConnection Sh, TargetEnd Sub

Private Sub Workbook_SheetChange( _ ByVal Sh As Object, ByVal Target As Range) If Not TypeOf Sh Is Worksheet Then Exit Sub If Not (Sh.Range(cWSWiringTagAddr).Value = cWSWiringTagID) _Then Exit Sub '<<<<< If Target.Cells.Count > 1 Then

Page 611: ? Применение VBA и макросов в Microsoft® Excel

Практикум: создание приложения Excel “с нуля” Глава 26 611

MsgBox "Версия 1 этого приложения не поддерживает" & vbNewLine _& "одновременное изменение нескольких соединений." & vbNewLine _& "Данное изменение нарушает целостность матрицы." & vbNewLine _& "Матрица электрических контактов разрушена! " & vbNewLine _& "Автоматическое изменение матрицы отменено." Exit Sub End If If OldVal = Target.Value Then Exit Sub '<<<<< If Target.Font.ColorIndex = cUnusedColorIdx Then addAConnection Sh, Target ElseIf IsEmpty(Target) Then deleteAConnection Sh, Target, OldVal Else changeAConnection Sh, Target, OldVal End IfEnd Sub

Private Sub Workbook_SheetSelectionChange( _ ByVal Sh As Object, ByVal Target As Range) If Not TypeOf Sh Is Worksheet Then Exit Sub If Not (Sh.Range(cWSWiringTagAddr).Value = cWSWiringTagID) _Then Exit Sub '<<<<< If Target.Cells.Count > 1 ThenMsgBox "Версия 1 этого приложения не поддерживает" & vbNewLine _& "одновременное изменение нескольких соединений." & vbNewLine _& "Пожалуйста, выделите только одну ячейку."'Предотвратить рекурсивный вызов процедуры! Target.Cells(1).Select Exit Sub End If OldVal = Target.ValueEnd Sub

Этап 3а: нисходящее программирование

Разработка приложения практически завершена. Осталось создать код

процедур, имеющих непосредственное отношение к инициализации системы,

а также код процедур создания и разрыва соединения.

Следующие четыре процедуры используются при инициализации системы.

Процедура resetFormatting удаляет существующее содержимое раY

бочего листа, задает общий формат чисел и светлоYсерый цвет шрифта.

Sub resetFormatting(aWS As Worksheet) With aWS.Cells .ClearContents .NumberFormat = "General" .Font.ColorIndex = cUnusedColorIdx End WithEnd Sub

Процедура createOneDataBlock использует эквивалент команды

главного меню Excel Правка Заполнить Прогрессия (Edit Fill

Series) для заполнения значениями от 101 до 700 блока, состоящего из

60 строк и 10 столбцов.

Page 612: ? Применение VBA и макросов в Microsoft® Excel

612 Часть III Удивительные возможности Visual Basic for Applications

Sub createOneDataBlock(aWS As Worksheet) With aWS.Range("A1") .FormulaR1C1 = "101" .DataSeries Rowcol:=xlRows, Type:=xlLinear, _ Date:=xlDay, _ Step:=1, Stop:=110, Trend:=False .Resize(1, 10).DataSeries Rowcol:=xlColumns, _ Type:=xlLinear, Date:=xlDay, _ Step:=10, Stop:=700, Trend:=False End WithEnd Sub

Процедура cloneDataBlocks создает 9 копий полученного блока

значений nnn, каждый раз определяя его новые координаты.

Sub cloneDataBlocks(aWS As Worksheet) Dim Dest As Range, i As Integer With aWS.Range("A1") Set Dest = .Offset(, 10) For i = 2 To 9 Set Dest = Union(Dest, .Offset(, i * 10)) Next i .CurrentRegion.Copy Dest End WithEnd Sub

Процедура addMSlash заносит формулу Excel в диапазон, состоящий

из 60 строк и 100 столбцов и расположенный непосредственно под суY

ществующим содержимым рабочего листа. Формула Excel отображает

значения nnn на соответствующие им коды контактных точек m/nnn.

После этого процедура addMSlash копирует полученную матрицу на

место диапазона значений nnn и удаляет исходный диапазон формул.

Sub addMSlash(aWS As Worksheet) With aWS.Range("A1").Offset(60, 0).Resize(60, 100)' В англоязычной версии Excel:' .FormulaR1C1 = _' "=TRUNC((COLUMN()-1)/10,0)+1 &""/""&R[-60]C" .FormulaR1C1Local = _ "=ОТБР((СТОЛБЕЦ()-1)/10,0)+1 &""/""&R[-60]C" aWS.Cells.NumberFormat = "@" .Copy aWS.Range("a1").PasteSpecial xlPasteValues .EntireRow.Delete End WithEnd Sub

Процедура addAConnection создает соединение между указанными конY

тактными точками. При возникновении ошибки вызывается процедура re-setValue, которая восстанавливает начальное содержимое ячейки рабочего

листа Excel.

Function addAConnection(Sh As Worksheet, Target As Range) Dim Conn2 As ExcelCoords Conn2 = WiringToExcelCoords(Target.Value) If Conn2.Row = 0 Then MsgBox Target.Value & " : недопустимое значение"

Page 613: ? Применение VBA и макросов в Microsoft® Excel

Практикум: создание приложения Excel “с нуля” Глава 26 613

addAConnection = True resetValue Target Exit Function '<<<<< End If With Sh.Cells(Conn2.Row, Conn2.Col) If .Font.ColorIndex <> cUnusedColorIdx Then MsgBox Target.Value & " занята!" & vbNewLine _ & "Она соединена с контактной точкой " & _Cells(Conn2.Row, Conn2.Col).Value resetValue Target addAConnection = True Exit Function '<<<<< End If Application.EnableEvents = False On Error GoTo ErrHandler .Value = XLtoWiringCoords(Target.Row, Target.Column) .Font.ColorIndex = cInUseColorIdx End With Target.Font.ColorIndex = cInUseColorIdx Application.EnableEvents = True Exit FunctionErrHandler: MsgBox "Непредвиденная ошибка в функции addAConnection: _Ячейка=" & Target.Address & vbNewLine _ & "Ошибка=" & Err.Description & " (" & Err.Number & ")" Application.EnableEvents = True End Function

Процедура deleteAConnection разрывает соединение между указанныY

ми контактными точками путем восстановления начальных значений соответY

ствующих ячеек рабочего листа Excel.

Sub deleteAConnection(Sh As Worksheet, Target As Range, _OldVal As String) Dim Conn2 As ExcelCoords Conn2 = WiringToExcelCoords(OldVal) Application.EnableEvents = False On Error GoTo ErrHandler With Conn2 resetValue Sh.Cells(.Row, .Col) End With resetValue Target Application.EnableEvents = True Exit SubErrHandler: MsgBox "Непредвиденная ошибка в процедуре _deleteAConnection: Ячейка=" & Target.Address & vbNewLine _& "Ошибка=" & Err.Description & " (" & Err.Number & ")" Application.EnableEvents = True End Sub

Этап 3б: создание ключевых компонентов

Ниже приведен код процедуры resetValue, восстанавливающей начальY

ное значение и форматирование ячейки рабочего листа Excel.

Page 614: ? Применение VBA и макросов в Microsoft® Excel

614 Часть III Удивительные возможности Visual Basic for Applications

Sub resetValue(Target As Range) Application.EnableEvents = False On Error GoTo ErrHandler With Target .Value = XLtoWiringCoords(.Row, .Column) .Font.ColorIndex = cUnusedColorIdx End With Application.EnableEvents = True Exit SubErrHandler: MsgBox "Непредвиденная ошибка в процедуре resetValue: _Ячейка=" & Target.Address & vbNewLine & "Ошибка=" & _Err.Description & " (" & Err.Number & ")" Application.EnableEvents = TrueEnd Sub

РезюмеВ этом практикуме был продемонстрирован процесс разработки реального

приложения Excel ‘‘с нуля’’ с использованием различных методик программиY

рования: структурного анализа, принципа распараллеливания и принципа

нисходящего программирования.

Page 615: ? Применение VBA и макросов в Microsoft® Excel

Предметный указатель

..NET Tools for Office, 31

AADO (ActiveX Data Objects), 490

объект

Connection, 492

Recordset, 492

API (Application Programming

Interface). См. Windows API

CCSV, 429

DDAO (Data Access Objects), 490

LLotus 1Y2Y3, 29

MMDB (Multidimensional Database), 489

Microsoft Access, 489

Microsoft Jet, 492

Microsoft Word, 439

SStarOffice, 30

VVBA. См. Visual Basic for Applications

VisiCalc, 29

Visual Basic for Applications, 59

синтаксис, 60

справочная система, 63

WWebYзапрос

обновление, 409

создание, 407; 410

Windows API, 547

объявление, 548

использование, 548

примеры, 549

структура, 548

XXML, 427

правила, 428

сопоставление данных, 430

схема данных, 429

ААвтозаполнение, 236

Автофильтр, 297

ББриклин, Дэн, 29

ВВкладка, 225

Выражение

On Error GoTo, 564

Property Get, 513

Property Let, 513

ДДиаграмма, 229

биржевая, 254

Page 616: ? Применение VBA и макросов в Microsoft® Excel

616 Предметный указатель

встроенная, 204; 230

контейнер, 230

гистограмма, 251

график, 251

иерархическая кольцевая, 265

изменение размещения, 235

кольцевая, 253

коническая, 255

кривой предложения, 264

круговая, 252; 258

круговая пузырьковая, 262

легенда, 247

лепестковая, 253

линейчатая, 251

линии сетки, 245

линия тренда, 248

название, 247

область диаграммы, 231; 237

область построения

диаграммы, 240

ось диаграммы, 243

вспомогательная, 245

пирамидальная, 255

поверхностная, 253

подписи данных, 246

полосы погрешности, 248

пузырьковая, 253

расположенная на отдельном

листе, 232

ряд данных, 242

с областями, 253

с точками данных в виде

спидометров, 264

таблица данных, 247

тип, 251

точечная, 252; 262

трехмерная, 256

цилиндрическая, 254

Диапазон ячеек, 95

именованный, 96

Динамически подключаемая

библиотека, 547

Диспетчер

объектов, 85

проектов, 46

Документ Word

закрытие, 447

открытие, 447

печать, 447

создание, 446

сохранение, 447

ИИзображение, 223

Имя

глобальное, 177

зарезервированное, 183

локальное, 177

массива, 183

создание, 179

строки, 181

удаление, 180

формулы, 181

числа, 182

ККейпор, Мич, 29

Кнопка, 220

Код

оптимизация, 90

отладка, 561

Коллекция, 60; 63; 515

Areas, 108

Axes, 243

Charts, 233

SeriesCollection, 242

создание

в модуле класса, 516

в стандартном модуле, 515

Константа

предопределенная, 68

Конструкция

Do Until...Loop, 151

Do While...Loop, 150

Do...Loop, 147

For Each...Next, 152

For...Next, 141

If...ElseIf...End If, 157

If...Then...Else, 155

If...Then...Else...End If, 156

If...Then...End If, 156

Select Case...End Select, 157

Type...End Type, 521

Page 617: ? Применение VBA и макросов в Microsoft® Excel

Предметный указатель 617

While...Wend, 152

With...End With, 90

ЛЛичная книга макросов, 42

ММакрос

безопасность, 40

выполнение, 43

с помощью гиперссылки, 591

с помощью кнопки, 587

с помощью сочетания

клавиш, 587

с помощью элемента

управления ActiveX, 590

запись, 42; 48; 53

сохранение, 42

Массив, 463

динамический, 469

заполнение, 464

манипулирование элементами, 466

многомерный, 464

объявление, 463

одномерный, 464

Матрица, 464

Меню

пользовательское

группирование команд, 578

добавление команд, 577

создание, 575

создание подменю, 579

удаление, 575

Метод, 60; 63

Intersect, 103

Microsoft Word

EndKey, 448

HomeKey, 448

TypeText, 448

OpenText, 66

SpecialCells, 106

Union, 103

параметр, 61; 63

Модуль, 46

класса, 47; 505

создание, 506

ННабор вкладок, 529

Надпись, 220

Надстройка, 593

безопасность, 598

выгрузка, 599

создание, 594

стандартная, 593

удаление, 599

установка, 597

ООбъект, 60; 63

ADO

Connection, 492

Recordset, 492

ChartArea, 237

ChartObject, 230

Microsoft Word

Document, 446

Range, 449

Selection, 448

PlotArea, 241

Range, 95

пользовательский

применение, 511

создание, 510

Ограничивающий прямоугольник, 241

Окно

Immediate (Быстрое

выполнение), 79

Watches (Просмотр), 82

ввода данных, 215

свойств, 47

сообщения, 216

Ошибка

времени выполнения

‘‘Method 'Range' of object

'_Global' failed’’, 571

‘‘Subscript out of range’’, 570

игнорирование, 566

извлечение пользы, 568

обработка, 561

выражение On Error GoTo, 564

универсальный обработчик, 566

Page 618: ? Применение VBA и макросов в Microsoft® Excel

618 Предметный указатель

ППанель инструментов, 222

UserForm, 525

Visual Basic, 39

пользовательская

выбор значка кнопки, 584

добавление кнопок, 582

добавление раскрывающегося

списка, 584

создание, 582

сохранение и восстановление

координат, 585

удаление, 582

Параметр, 61; 63

TrailingMinusNumbers, 68; 478

необязательный, 68

события, 190

Переключатель, 222; 528

Переменная, 89

объектная, 152; 236

цикла, 144

Песочница, 40

Поле ввода, 220

адреса диапазона ячеек, 530

Полоса прокрутки, 539

Пользовательская форма

вкладка, 225

вызов, 218

добавление элемента

управления, 219

закрытие, 218; 225

изображение, 223

кнопка, 220

модальная, 531

набор вкладок, 529

надпись, 220

немодальная, 531

панель, 222

переключатель, 222; 528

поле ввода, 220

адреса диапазона ячеек, 530

полоса прокрутки, 539

создание, 216

список, 221

комбинированный, 221

счетчик, 224

эффект прозрачности, 545

Примечания ячеек, 376

РРасширенный фильтр, 267; 364

автофильтр, 297

диапазон условий, 276

Редактор Visual Basic, 45

автозаполнение, 236

диспетчер объектов, 85

диспетчер проектов, 46

окно Immediate (Быстрое

выполнение), 79

окно Watches (Просмотр), 82

окно свойств, 47

отладчик, 74

параметры, 45

ССводная таблица, 299

автоотображение лучшей

десятки, 340

вычисляемое поле, 328

вычисляемый элемент, 331

группирование дат, 333

определение размера, 307

перемещение и изменение, 306

создание, 300; 303

удаление, 307

фильтрация данных, 344

Свойство, 62; 63

Cells, 99

Columns, 102

CurrentRegion, 105

Offset, 100

Resize, 101

Rows, 102

Связывание

позднее, 442

раннее, 439

Событие, 189

AppEvent_NewWorkbook, 210

AppEvent_SheetActivate, 210

AppEvent_SheetBeforeY

DoubleClick, 210

AppEvent_SheetBeforeY

RightClick, 210

AppEvent_SheetCalculate, 211

AppEvent_SheetChange, 211

Page 619: ? Применение VBA и макросов в Microsoft® Excel

Предметный указатель 619

AppEvent_SheetDeactivate, 211

AppEvent_SheetFollowHyperlink,

211

AppEvent_SheetSelectionChange,

211

AppEvent_WindowActivate, 211

AppEvent_WindowDeactivate, 211

AppEvent_WindowResize, 212

AppEvent_WorkbookActivate, 212

AppEvent_WorkbookAddinInstall,

212

AppEvent_WorkbookAddinUninstall,

212

AppEvent_WorkbookBeforeClose,

213

AppEvent_WorkbookBeforePrint,

213

AppEvent_WorkbookBeforeSave, 213

AppEvent_WorkbookDeactivate, 213

AppEvent_WorkbookNewSheet, 213

AppEvent_WorkbookOpen, 214

Chart_Activate, 205

Chart_BeforeDoubleClick, 205

Chart_BeforeRightClick, 206

Chart_Calculate, 206

Chart_Deactivate, 206

Chart_DragOver, 206

Chart_DragPlot, 206

Chart_MouseDown, 206

Chart_MouseMove, 207

Chart_MouseUp, 207

Chart_Resize, 207

Chart_Select, 207

Chart_SeriesChange, 208

Workbook_Activate, 192

Workbook_AddinInstall, 196

Workbook_AddinUninstall, 196

Workbook_BeforeClose, 194

Workbook_BeforePrint, 193

Workbook_BeforeSave, 193

Workbook_Deactivate, 192

Workbook_NewSheet, 195

Workbook_Open, 192

Workbook_SheetActivate, 197

Workbook_SheetBeforeY

DoubleClick, 197

Workbook_SheetBeforeRightClick,

197

Workbook_SheetCalculate, 197

Workbook_SheetChange, 198

Workbook_SheetDeactivate, 198

Workbook_SheetFollowHyperlink,

198

Workbook_SheetSelectionChange,

198

Workbook_WindowActivate, 196

Workbook_WindowDeactivate, 196

Workbook_WindowResize, 195

Worksheet_Activate, 199

Worksheet_BeforeDoubleClick, 199

Worksheet_BeforeRightClick, 200

Worksheet_Calculate, 200

Worksheet_Change, 202

Worksheet_Deactivate, 199

Worksheet_FollowHyperlink, 203

Worksheet_SelectionChange, 203

встроенной диаграммы, 204; 509

листа диаграммы, 204

параметры, 190

приложения, 208; 507

рабочего листа, 199

рабочей книги, 191

Список, 221

комбинированный, 221

Ссылка

абсолютная, 52; 167

относительная, 53; 166

смешанная, 167

Стиль записи ссылок

A1, 161; 165

R1C1, 162; 165; 166

Счетчик, 224

ТТаблица Access

запись

добавление, 493

извлечение, 494

обновление, 496

удаление, 499

поле

проверка существования, 501

создание, 503

проверка существования, 500

создание, 502

Page 620: ? Применение VBA и макросов в Microsoft® Excel

620 Предметный указатель

Точка прерывания, 77

создание, 77; 83

удаление, 78

УУсловное форматирование ячеек, 171;

364; 381

ФФайл

.dll, 547

.mdb, 489

.xls, 431

.xml, 431

.xsd, 431

текстовый

импорт, 473

экспорт, 486

Форма. См. Пользовательская форма

Формула

A1, 164; 168

R1C1, 164; 168; 169

массива, 174

Фрэнкстон, Боб, 29

Функция

CreateObject, 444

GetObject, 444

IsEmpty, 104

определенная пользователем, 111

создание, 112

ЦЦикл, 141

Do Until...Loop, 151

Do While...Loop, 150

Do...Loop, 147

For Each...Next, 152

For...Next, 141

While...Wend, 152

вложение циклов, 146

досрочное завершение, 145

изменение шага, 144

Page 621: ? Применение VBA и макросов в Microsoft® Excel

Научно�популярное издание

Билл Джелен, Трейси Сирстад

Применение VBA и макросов в Microsoft Excel

Литературный редактор П.Н. МачугаВерстка О.В. Линник

Художественный редактор С.А. ЧернокозинскийКорректор О.В. Мишутина

Издательский дом ‘‘Вильямс”

101509, г. Москва, ул. Лесная, д. 43, стр. 1

Подписано в печать 30.09.2005. Формат 70x100/16.

Гарнитура Times. Печать офсетная

Усл. печ. л. 50,3. Уч.$изд. л. 30,4.

Тираж 3000 экз. Заказ № .

Отпечатано с диапозитивов в ФГУП ‘‘Печатный двор”

Министерства РФ по делам печати,

телерадиовещания и средств массовых коммуникаций

197110, С.$Петербург, Чкаловский пр., 15