- •Об авторе
- •Введение
- •Глава 1. Excel 2010: история программы
- •Краткая история электронных таблиц
- •Все начиналось с VisiCalc
- •Quattro Pro
- •Microsoft Excel
- •Почему программа Excel так удобна разработчикам
- •Место Excel в стратегии Microsoft
- •Объектное мышление
- •Рабочие книги
- •Рабочие листы
- •Листы диаграмм
- •Листы макросов XLM
- •Пользовательский интерфейс Excel
- •Ввод данных
- •Формулы, функции и имена
- •Выделение объектов
- •Форматирование
- •Глава 3. Особенности формул
- •О формулах
- •Вычисление формул
- •Ссылки на ячейки и диапазоны
- •Зачем нужны неотносительные ссылки
- •Ссылки на другие листы или рабочие книги
- •Применение имен к существующим ссылкам
- •Пересечение имен
- •Присвоение имен столбцам и строкам
- •Определение области действия
- •Присвоение имен константам
- •Присвоение имен объектам
- •Ошибки в формулах Excel
- •Формулы массивов
- •Пример формулы массива
- •Создание календаря с помощью формулы массива
- •Достоинства и недостатки формул массивов
- •Примеры формул суммирования
- •Другие инструменты подсчета
- •Работа со значениями даты и времени
- •Использование дат до 1900 года
- •Создание мегаформул
- •Глава 4. Файлы Excel
- •Запуск Excel
- •Типы файлов
- •Форматы файлов Excel
- •Форматы текстовых файлов
- •Форматы файлов баз данных
- •Другие форматы файлов
- •Создание шаблонов
- •Создание шаблонов рабочих книг
- •Файл XLB
- •Файлы надстроек
- •Настройки Excel
- •Глава 5. Приложения электронных таблиц
- •О приложениях электронных таблиц
- •Разработчик и конечный пользователь
- •Кто такие разработчики и чем они занимаются
- •Классификация пользователей электронных таблиц
- •Для кого предназначены приложения электронных таблиц
- •Решение проблем с помощью Excel
- •Основные типы электронных таблиц
- •Однопользовательские приложения
- •Приложения-утилиты
- •Надстройки с функциями рабочих листов
- •Одноблоковые бюджеты
- •Электронные таблицы для хранения данных и доступа к ним
- •Клиентские приложения баз данных
- •Глава 6. Принципы разработки приложений электронных таблиц
- •Этапы разработки приложения
- •Определение потребностей пользователя
- •Проектирование приложения с учетом потребностей пользователя
- •Определение удобного пользовательского интерфейса
- •Работа с конечным пользователем
- •Тестирование приложения
- •Создание привлекательных и интуитивно понятных приложений
- •Документирование усилий, затраченных на разработку
- •Распространение приложения среди пользователей
- •Обновление приложения
- •Другие вопросы разработки приложений
- •Версия Excel, установленная у пользователя
- •Трудности, касающиеся поддержки языка
- •Видеорежимы
- •Глава 7. Введение в VBA
- •Основы языка BASIC
- •Обзор VBA
- •Объектные модели
- •Сравнение VBA и XLM
- •Основы VBA
- •Работа с Project Explorer
- •Добавление нового модуля VBA
- •Удаление модуля VBA
- •Экспорт и импорт объектов
- •Работа с окнами кода
- •Сворачивание и восстановление окон
- •Сохранение кода VBA
- •Ввод кода VBA
- •Настройка среды VBE
- •Что записывается
- •Параметры записи
- •Улучшение записанных макросов
- •Об объектах и коллекциях
- •Иерархия объектов
- •О коллекциях
- •Ссылки на объекты
- •Свойства и методы
- •Свойства объекта
- •Методы объекта
- •Свойства объекта Comment
- •Методы объекта Comment
- •Коллекция Comments
- •Работа с объектами Range
- •Свойство Range
- •Свойство Offset
- •Что следует знать об объектах
- •Важные концепции для запоминания
- •Узнайте больше об объектах и свойствах
- •Обзор элементов и конструкций VBA
- •Комментарии
- •Переменные, типы данных и константы
- •Определение типов данных
- •Объявление переменных
- •Работа с константами
- •Операторы присваивания
- •Массивы
- •Объявление массивов
- •Объявление многомерных массивов
- •Объявление динамических массивов
- •Объектные переменные
- •Пользовательские типы данных
- •Встроенные функции
- •Управление объектами и коллекциями
- •Конструкция With - End With
- •Конструкция For Each - Next
- •Контроль за выполнением кода
- •Конструкция Select Case
- •Циклическая обработка инструкций
- •Глава 9. Работа с процедурами VBA
- •О процедурах
- •Объявление процедуры Sub
- •Область действия процедуры
- •Выполнение процедуры
- •Выполнение процедуры с помощью ленты
- •Выполнение процедуры из пользовательского контекстного меню
- •Выполнение процедуры из другой процедуры
- •Выполнение процедуры по щелчку на объекте
- •Выполнение процедуры по событию
- •Выполнение процедуры в окне отладки
- •Передача аргументов процедурам
- •Обработка ошибок
- •Перехват ошибок
- •Реальный пример
- •Цель
- •Требования к проекту
- •Исходные данные
- •Подход
- •Что необходимо знать
- •Написание кода
- •Создание процедуры сортировки
- •Устранение проблем
- •Доступность
- •Глава 10. Создание функций
- •Процедуры и функции
- •Назначение пользовательских функций
- •Простой пример функции
- •Анализ пользовательской функции
- •Синтаксис функции
- •Область действия функции
- •Аргументы функций
- •Примеры функций
- •Функции без аргументов
- •Функция с одним аргументом
- •Функция с двумя аргументами
- •Функция с аргументом в виде массива
- •Функция с необязательными аргументами
- •Функция VBA, возвращающая массив
- •Функция с неопределенным количеством аргументов
- •Расширенные функции для работы с датами
- •Отладка функций
- •Определение категории функции
- •Использование надстроек для хранения пользовательских функций
- •Использование функций Windows API
- •Примеры функций Windows API
- •Определение папки Windows
- •Определение состояния клавиши <Shift>
- •Дополнительная информация о функциях Windows API
- •Учимся на примерах
- •Работа с диапазонами
- •Копирование диапазона
- •Перемещение диапазона
- •Подсчет выделенных ячеек
- •Определение типа выделенного диапазона
- •Удаление всех пустых строк
- •Дублирование строк
- •Чтение и запись диапазонов
- •Перенесение одномерных массивов
- •Перенесение диапазона в массив типа Variant
- •Выбор ячеек по значению
- •Копирование несмежных диапазонов
- •Управление рабочими книгами и листами
- •Сохранение всех рабочих книг
- •Синхронизация рабочих книг
- •Методы программирования на VBA
- •Переключение значения булева свойства
- •Определение количества страниц для печати
- •Отображение списка шрифтов
- •Обработка последовательности файлов
- •Полезные функции для программ VBA
- •Функция FileExists
- •Функция FileNameOnly
- •Функция PathExists
- •Функция RangeNameExists
- •Функция SheetExists
- •Получение значения из закрытой рабочей книги
- •Полезные функции в формулах Excel
- •Получение информации о форматировании ячейки
- •Беседа с рабочим листом
- •Отображение даты сохранения файла или вывода файла на печать
- •Основы иерархии объектов
- •Подсчет количества ячеек между двумя значениями
- •Соответствует ли строка шаблону
- •Возвращение из строки n-го элемента
- •Возвращение максимального значения всех рабочих листов
- •Возвращение массива случайных целых чисел без повторов
- •Расположение значений диапазона в произвольном порядке
- •Определение текущего видеорежима
- •Чтение и запись параметров системного реестра
- •Глава 12. Создание собственных диалоговых окон
- •Перед созданием диалоговых окон...
- •Использование окон ввода данных
- •Функция VBA MsgBox
- •Отображение формы ввода данных с помощью VBA
- •CommandButton
- •Frame
- •Image
- •Label
- •ListBox
- •MultiPage
- •OptionButton
- •RefEdit
- •ScrollBar
- •SpinButton
- •TabStrip
- •TextBox
- •ToggleButton
- •Настройка элементов управления пользовательского диалогового окна
- •Общие свойства
- •Отображение пользовательского диалогового окна
- •Отображение немодальной формы
- •Отображение пользовательского диалогового окна на основе значения переменной
- •Загрузка пользовательского диалогового окна
- •О процедурах обработки событий
- •Закрытие пользовательского диалогового окна
- •Пример создания пользовательского диалогового окна
- •Создание пользовательской формы
- •Создание кода для отображения диалогового окна
- •Проверка правильности введенных данных
- •События объекта UserForm
- •События объекта UserForm
- •События элемента управления SpinButton
- •Ссылка на элементы управления пользовательского диалогового окна
- •Настройка панели инструментов Toolbox
- •Добавление новых страниц
- •Настройка или комбинирование элементов управления
- •Вопросы для самоконтроля
- •Создание заставки
- •Отключение кнопки закрытия пользовательского диалогового окна
- •Изменение размера диалогового окна
- •Добавление опций в элемент управления ListBox
- •Определение выделенного элемента списка
- •Определение нескольких выделенных элементов списка
- •Работа с многоколоночными элементами управления ListBox
- •Использование элемента управления ListBox для выделения строк на листе
- •Использование элемента управления ListBox для активизации листа
- •Использование внешних элементов управления
- •Глава 15. Дополнительные приемы работы с пользовательскими формами
- •Отображение индикатора текущего состояния
- •Создание мастеров
- •Программирование зависимостей
- •Выполнение задачи
- •Имитация работы функции MsgBox
- •Несколько кнопок с одной процедурой обработки событий
- •Глава 16. Разработка утилит Excel с помощью VBA
- •Об утилитах Excel
- •Создание утилит с помощью VBA
- •Признаки хорошей утилиты
- •Утилита Text Tools
- •Рабочая книга утилиты
- •Как работает утилита
- •Оценка проекта
- •Принципы работы утилиты
- •Дополнительно об утилитах Excel
- •Глава 17. Работа со сводными таблицами
- •Вводный пример
- •Просмотр созданного кода
- •Код сводной таблицы
- •Создание обратной сводной таблицы
- •Кратко о диаграммах
- •Создание внедренной диаграммы
- •Размещение диаграммы на листе диаграммы
- •Активизация диаграммы с помощью кода VBA
- •Деактивизация диаграммы
- •Определение активности диаграммы
- •Изменение размеров и выравнивание диаграмм
- •Экспорт диаграммы
- •События диаграмм
- •Поддержка событий для встроенных диаграмм
- •Тонкости создания диаграмм
- •Печать встроенных диаграмм на всю страницу
- •Отображение/сокрытие рядов данных
- •Создание фиксированной диаграммы
- •Анимирование диаграмм
- •Прокрутка диаграммы
- •Глава 19. Концепция событий Excel
- •Типы событий Excel
- •Понимание последовательности событий
- •Отключение событий
- •Ввод кода процедуры обработки события
- •События уровня объекта Workbook
- •Событие Open
- •Событие Activate
- •Событие SheetActivate
- •Событие NewSheet
- •Событие Deactivate
- •Событие BeforePrint
- •Событие Change
- •Включение событий уровня объекта Application
- •Определение факта открытия рабочей книги
- •События объекта UserForm
- •Запуск другого приложения из Excel
- •Использование функции Shell
- •Использование API-Функции ShellExecute
- •Инструкция AppActivate
- •Работа с внешними объектами
- •Раннее и позднее связывание
- •Простой пример позднего связывания
- •Использование метода SendKeys
- •Глава 21. Создание и использование надстроек
- •Определение надстройки
- •Основные причины создания надстроек
- •Создание надстройки
- •Пример надстройки
- •Установка надстройки
- •Тестирование надстройки
- •Распространение надстройки
- •Изменение надстройки
- •Членство в коллекциях
- •Получение доступа к VBA-процедурам надстройки
- •События объекта AddIn
- •Оптимизация производительности надстроек
- •Проблемы, связанные с использованием надстроек
- •Правильная установка
- •Ссылки на другие файлы
- •Указание правильной версии Excel
- •Глава 22. Работа с лентой
- •Начальные сведения о ленте
- •Активизация вкладки
- •Настройка ленты
- •Простой пример кода RibbonX
- •Некоторые замечания о настройке ленты
- •Код панели инструментов
- •Глава 23. Работа с контекстными меню
- •Обзор объекта CommandBar
- •Типы объектов CommandBar
- •Отображение контекстных меню
- •Настройка контекстных меню с помощью VBA
- •Сброс контекстных меню
- •Отключение контекстного меню
- •Отключение элементов контекстного меню
- •Добавление подменю в контекстное меню
- •Автоматическое добавление и удаление меню
- •Создание нового контекстного меню
- •Справка в приложениях Excel
- •Справочная система, созданная с помощью компонентов Excel
- •Использование примечаний к ячейке для предоставления справки
- •Использование средства HTML Help
- •Связывание файлов справочного руководства с приложением
- •Глава 25. Разработка пользовательских приложений
- •Что такое приложение, ориентированное на пользователя
- •Как это работает
- •Концепции разработки приложений
- •Концепция совместимости
- •Проблемы совместимости
- •Избегайте использования новых возможностей
- •Использование 64-разрядной версии Excel
- •Создание интернациональных приложений
- •Многоязычные приложения
- •Идентификация настроек системы
- •Параметры настройки даты и времени
- •Часто выполняемые операции с файлами
- •Управление файлами с помощью функций VBA
- •Использование объекта FileSystemObject
- •Открытие текстового файла
- •Чтение текстового файла
- •Запись в текстовый файл
- •Получение номера файла
- •Определение или установка позиции в файле
- •Примеры управления текстовыми файлами
- •Импортирование данных из текстового файла
- •Экспортирование диапазона в текстовый файл
- •Импортирование текстового файла в диапазон
- •Протоколирование операций в Excel
- •Фильтрация текстового файла
- •Экспортирование диапазона в формат HTML
- •Введение в IDE
- •Объектная модель IDE
- •Использование VBA для создания кода VBA
- •Простой пример
- •Глава 29. Модули классов
- •Определение модуля класса
- •Пример создания модуля класса
- •Дополнительные сведения о модулях классов
- •События модуля класса
- •Модуль класса CSVFileClass
- •Глава 30. Работа с цветом
- •Определение цвета
- •Цветовая модель RGB
- •Темы документа
- •Изменение цветов диаграммы
- •Списки часто задаваемых вопросов
- •Общие вопросы об Excel
- •Редактор Visual Basic
- •Процедуры
- •Функции
- •Объекты, свойства, методы и события
- •Пользовательские диалоговые окна
- •Надстройки
- •Пользовательский интерфейс
- •Справочная система Excel
- •Техническая поддержка со стороны компании Microsoft
- •Группы новостей
- •Веб-сайты
- •Сайт Йона Пелтиера
- •Системные требования
- •Использование компакт-диска
- •Файлы и программы, находящиеся на компакт-диске
- •Решение проблем
- •Предметный указатель
242 |
Часть III. Visual Basic for Applications |
Функция VBA I I £
В VBA существует альтернатива конструкции if-T h e n : функция I l f . Эта функция имеет три аргумента и работает подобно функции рабочего листа Excel если. Рассмот рим ее синтаксис:
I l f (вы раж ение, ч а с т ь _ Т ги е , 4 a c T b _ F a ls e )
•Выражение (обязательный аргумент) — выражение, которое нужно оценить
•Ч асть_т гие (обязательный аргумент) — значение или выражение, возвращаемое функцией, когда выражение имеет тип True
•4 a c T b _ F a ls e (обязательный аргумент) — значение или выражение, возвращаемое функцией, когда выражение имеет тип F alse
Следующая инструкция демонстрирует применение функции ний отображается Нуль, если ячейка А1 содержит нуль или пуста, А1 содержит другое значение.
MsgBox Ilf( R a n g e ( " A l" ) = 0, "Н уль", "Н е -нуль")
i i f . В окне сообще He-нуль, если ячейка
Важно понимать, что третий аргумент (4 a c T b _ F a ls e ) всегда оценивается, даже ес ли второй аргумент (част ь_т гие) выполняется. Следовательно, следующий оператор выдает ошибку, если значение п равно нулю.
MsgBox I l f ( n = 0 , 0, 1 / n)
Конструкция Select Case
Конструкция S e le c t Case применяется при выборе между тремя и более вариан тами. Она справедлива также для двух вариантов и является хорошей альтернативой
структуре I f - |
Then - E ls e . Конструкция S e le c t Case имеет следующий синтаксис. |
S e le c t Case |
т ест ируем ое_вы раж ение |
[Case с п и с о к у с л о в и й -n [оп ерат оры - n ] ]
[Case E lse
[операт оры _по_ум олчанию ] ]
End S e le c t
Приведем пример конструкции S e le c t Case, который показывает еще один способ запрограммировать процедуру G reetM e, рассмотренную в предыдущем разделе.
Sub |
G reetM e() |
S trin g |
|
|||
|
Dim |
Msg |
As |
|
||
|
S e le c t |
Case |
Time |
|
||
|
|
Case |
Is |
= |
< 0.5 |
утро" |
|
|
Msg |
"Доброе |
|||
|
|
Case 0 .5 To 0.75 |
день" |
|||
|
|
Msg |
= |
"Добрый |
||
|
|
Case |
E lse |
вечер" |
||
|
End |
Msg |
= |
"Добрый |
||
|
S e le c t |
|
|
|
||
End |
MsgBox |
Msg |
|
|
|
|
Sub |
|
|
|
|
||
Ниже приведена версия процедуры D is c o u n t, переписанная с использованием кон струкции S e le c t Case. Эта процедура предполагает, что Q u a n tity всегда выражает ся целым числом. Чтобы упростить процедуру, в ней не выполняется проверка введен ных данных.
Глава 8. Основы программирования на VBA |
243 |
||||||
Sub D is c o u n t3 () |
|
|
|
|
|||
Dim |
Q u a n tity |
As |
V a ria n t |
|
|||
Dim |
D is c o u n t |
As |
Double |
|
|||
Q u a n tity = |
In p u tB o x ( " В в е д и т е з н а ч е н и е : |
") |
|||||
S e le c t |
Case |
Q u a n tity |
|
||||
|
Case |
"" |
|
|
|
|
|
|
E x it |
Sub |
|
|
|
||
|
Case |
0 To |
24 |
|
|
|
|
|
D is c o u n t |
= |
0 .1 |
|
|||
|
Case 25 To 4 9 |
|
|
||||
|
D is c o u n t |
= |
0.15 |
|
|||
|
Case |
50 |
To |
74 |
0.2 |
|
|
|
D is c o u n t |
= |
|
||||
|
Case |
Is |
>= 75 |
|
|
||
|
D is c o u n t |
= |
0.25 |
|
|||
End |
S e le c t |
|
|
" |
& D isco u n t |
|
|
MsgBox " С к и д к а : |
|
||||||
End Sub |
|
|
|
|
|
|
|
В операторе Case можно использовать запятую, разделяющую несколько значений для одного варианта. В следующей процедуре используется функция VBA WeekDay, с помощью которой определяется, является ли текущий день субботой либо воскресень ем (функция Weekday возвращает значение 1 либо 7). Затем отображается соответст вующее сообщение.
Sub G re e tU se rl () |
||
S e lect |
Case |
Weekday(Now) |
Case |
1, 7 |
|
MsgBox |
"Э т о в ы ход ны е" |
|
Case |
E lse |
|
MsgBox |
"Э т о не в ы ход ны е" |
|
End S e le c t |
|
|
End Sub |
|
|
Следующий пример демонстрирует еще один способ кодирования предыдущей про цедуры.
Sub G reetUser2 () |
|
S elect Case |
Weekday(Now) |
Case 2, 3, 4, 5, 6 |
|
MsgBox |
" Э т о не в ы ход ны е" |
Case E lse |
|
MsgBox |
"Э т о в ы ход ны е" |
End S e le c t |
|
End Sub |
|
Под каждым оператором Case может указываться любое количество инструкций, и они выполняются при условии Case, имеющем значение True. Если вы используете в каждом случае Case только одну инструкцию (как в предыдущем примере), то можете поместить ее в той же строке, что и ключевое слово Case (но не забудьте о символе раз деления операторов в VBА — двоеточии). Этот прием сделает текст программы более компактным.
Sub D isco u n t3 () |
As |
V a ria n t |
|
Dim Q u a n tity |
|||
Dim D isco u n t |
As |
Double |
|
Q u a n tity = In p u tB o x ( " В в в е д и т е к о л и ч е с т в о : ") |
|||
S elect |
Case |
Q u a n tity |
|
Case |
" " : |
E x it |
Sub |
244 |
|
|
|
|
|
Часть III. Visual Basic for Applications |
Case |
0 |
To |
24: |
D is c o u n t |
= |
0 .1 |
Case |
25 |
To |
49 |
D is c o u n t |
= |
15 |
Case |
50 |
To |
74 |
D is c o u n t |
= |
2 |
Case |
Is |
>= |
75 |
D is c o u n t |
= |
25 |
End S e le c t |
|
|
|
|
|
|
MsgBox |
" С к и д к а : |
& D is c o u n t |
|
|||
End Sub |
|
|
|
|
|
|
Совет
Интерпретатор VBA осуществляет выход из конструкции S e le c t Case, как только найдено условие True. Следовательно, для максимальной эффек тивности, в первую очередь, следует выполнить проверку наиболее вероят ного случая.
Структуры S e le c t Case можно вкладывать друг в друга. Например, следующая процедура использует процедуру VBA TypeName для определения того, что выделено в настоящий момент (диапазон ячеек, ничего или что-либо еще). Если выделен диапазон, процедура вызывает на выполнение вложенный оператор S e le c t Case, а также прове ряет количество ячеек в диапазоне. Если выделена одна ячейка, отображается сообщение Выделена одна ячейка. В противном случае отображается сообщение, в котором указывается количество выделенных строк.
Sub |
S e le c tio n T y p e () |
|
|
|
|
|
|
S e le c t Case |
TypeN am e(S election) |
|
|||
|
Case "Д и а п а з о н " |
|
|
|
||
|
S e le c t |
Case S e le c tio n . Count |
|
|||
|
Case 1 |
|
|
|
|
|
|
MsgBox |
"В ы д е л е н а од н а |
я ч е й к а " |
|
||
|
Case E lse |
|
|
|
|
|
|
MsgBox |
S e le c tio n .R o w s . Count & |
" с т р о к " |
|||
|
End S e le c t |
|
|
|
|
|
|
Case " Н и ч е г о " |
|
|
|
|
|
|
MsgBox |
"Н и ч е г о |
не в ы д е л ен о " |
|
||
|
Case E lse |
|
|
|
|
|
|
MsgBox |
"В ы д ел ен |
о б ъ е к т , |
отл и ч н ы й |
о т д и а п а з о н а " |
|
|
End S e le c t |
|
|
|
|
|
End |
Sub |
|
|
|
|
|
Можно создавать конструкции S e le c t Case любой степени вложенности, но убедитесь, что каждому оператору S e le c t Case соответствует свой оператор End S e le c t.
Данная процедура демонстрирует, насколько важно использовать отступы в коде, чтобы выделить его структуру. Например, рассмотрим ту же процедуру, но без отступов.
Sub S e le c tio n T y p e () |
|
||
S e le c t |
Case TypeN am e(S election) |
|
|
Case " Д и а п а з о н " |
|
|
|
S e le c t |
Case S e le c tio n . Count |
|
|
Case 1 |
|
|
|
MsgBox |
"В ы д е л е н а од н а я ч е й к а " |
|
|
Case E lse |
|
|
|
MsgBox |
S e le c tio n . Rows. Count & " |
с т р о к " |
|
End S e le c t |
|
|
|
Case " Н и ч е г о " |
|
|
|
MsgBox |
" Н и ч е г о |
не в ы д е л е н о " |
|
Case E lse |
|
|
|
MsgBox |
"В ы д ел ен |
о б ъ е к т , о тл и ч н ы й |
о т д и а п а з о н а " |
Глава 8. Основы программирования на VBA |
245 |
End S e le c t
End Sub
В таком представлении мало что понятно даже опытному программисту!
Циклическая обработка инструкций
Цикл — это процесс повторения набора инструкций. Возможно, вы заранее знаете, сколько раз должен повториться цикл, или это значение определяется переменными в программе.
Следующий код, в котором в диапазон вводятся последовательные числа, является примером того, что называют плохим циклом. Процедура использует две переменные для хранения начального значения ( S ta r t V a l) и общего количества ячеек, которые не обходимо заполнить (N u m T o F ill). В этом цикле для управления порядком выполнения операций используется оператор GoTo. Если переменная C nt, отвечающая за то, сколь ко ячеек заполнено, меньше числа, заданного пользователем, то выполняется переход назад, к метке D o A n o th e r.
Sub BadLoop () |
|
As |
In te g e r |
|
|
||||
Dim |
S ta rtV a l |
|
|
||||||
Dim N um T oF ill |
As |
In te g e r |
|
|
|||||
Dim |
Cnt |
As |
In te g e r |
|
|
|
|||
S ta rtV a l |
= |
1 |
|
|
|
|
|
||
Num ToFill |
= 100 |
|
|
|
|
||||
A c tiv e C e ll.V a lu e |
= |
S ta rtV a l |
|
|
|||||
Cnt |
= |
1 |
|
|
|
|
|
|
|
poAnother: |
|
|
|
|
|
|
|
||
'A ctive C e ll. Of f s e t (C n t, |
0) .V alue |
= S ta rtV a l |
+ Cnt |
||||||
Cnt |
= |
Cnt |
+ 1 |
|
|
|
|
||
I f |
Cnt |
< N um T oF ill |
Then GoTo |
DoAnother |
E lse E x it Sub |
||||
End Sub
Описанная процедура выполняется правильно. Почему же она является примером пло хого цикла? Настоящие программисты не используют оператор GoTo, если можно обой тись без него. Применение операторов GoTo в цикле противоречит концепции структурно го программирования (см. врезку “Несколько слов о структурном программировании”). Этот оператор значительно усложняет восприятие кода, поскольку в данном случае прак тически невозможно структурировать цикл с помощью отступов. Кроме того, такой тип не структурированного цикла делает процедуру подверженной частым ошибкам. Также исполь зование большого количества меток приводит к получению программы с плохой структу рой (или без структуры вообще) и бессистемным порядком следования операций.
Поскольку в VBA встроено несколько структурированных команд циклов, в процессе принятия решений практически никогда не требуется прибегать к операторам GoTo.
Несколько слов о структурном программировании
Пообщайтесь с профессиональными программистами, и рано или поздно вы услы шите термин “структурное программирование”. Кроме того, вы обнаружите, что струк турные программы лучше иных типов программ.
Чтоже представляет собой структурное программирование и как его применить к VBA?
Основное условие заключается в том, что процедура (или сегмент программы) должна иметь только одну точку входа и одну точку выхода. Другими словами, тело кода является независимым элементом, а контроль за выполнением программы не должен
246 |
Часть III. Visual Basic for Applications |
выходить за рамки этого элемента. Поэтому в структурной программе не допускается применение оператора GO T O . В подобной программе выполнение кода происходит в определенном порядке, который легко отслеживается (в отличие от кода, в котором программа “перескакивает” с места на место).
Структурную программу проще воспринимать и анализировать, чем неструктурную. И что более важно, ее легче изменять.
VBA— структурированный язык. Он предлагает стандартные структурные конструкции, такие как If-T h e n -E ls e и S e le ct Case, а также циклы For-N ext, Do U n t il и Do W hile.
Более того, VBA полностью поддерживает модульный подход к созданию программ.
Если вы начинаете программировать, привыкайте сразу же создавать структуриро ванные программы.
Циклы F o r -N e x t
Простейший пример хорошего цикла — F or-N ext (он уже применялся в нескольких предыдущих примерах). Этот оператор имеет следующий синтаксис.
For |
счет чик = начало То ко н е ц [S tep шаг] |
[инст рукции] |
|
[E x it For] |
|
[инст рукции] |
|
N ext |
[счет чик] |
Ниже приведен пример цикла F or-N ext, в котором не используется значение шаг
переменной S tep |
и необязательный оператор E x it For. Эта процедура выполняет |
|||
оператор Sum = |
Sum + Sqr (Count) 100 раз и отображает результат— сумму квад |
|||
ратных корней первых 100 целых чисел. |
||||
Sub |
SumSquareRoots() |
|||
|
Dim |
Sum As |
Double |
|
|
Dim |
Count |
As In te g e r |
|
|
Sum = 0 |
|
|
|
|
For Count = 1 To 100 |
|||
|
Sum = Sum + S qr(C ount) |
|||
|
N ext |
Count |
|
|
|
MsgBox Sum |
|
||
End |
Sub |
|
|
|
Вданном примере Count (переменная-счетчик цикла) имеет начальное значение 1
иувеличивается на 1 при каждом повторении цикла. Переменная Sum суммирует квад ратные корни каждого значения Count.
Предупреждение
Используя циклы F o r-N e xt, важно понимать, что в качестве счетчика цикла используется обычная переменная, и ничего больше. В результате значение счетчика цикла можно изменять в блоке программы, который выполняется между операторами For и Next. Однако это очень неудачный прием, посколь ку он может привести к непредсказуемым результатам. Необходимо принять специальные меры предосторожности, чтобы удостовериться в том, что про грамма не изменяет счетчик цикла.
Можно также указать значение ш аг для переменной S tep, чтобы пропустить отдель ные итерации цикла. Ниже рассмотрена исходная процедура, переписанная так, что сум мируются квадратные корни всех нечетных чисел в диапазоне от 1 до 100.
Глава 8. Основы программирования на VBA |
247 |
||
Sub SumOddSquareRoots() |
|
||
Dim |
Sum As |
Double |
|
Dim |
Count |
As In te g e r |
|
Sum = 0 |
|
|
|
For Count = 1 To 100 Step 2 |
|
||
Sum = Sum + S q r(C ount) |
|
||
Next |
Count |
|
|
MsgBox Sum
End Sub
В этой процедуре исходное значение Count равно 1, затем счетчик принимает значе ния 3, 5, 7 и т.д. Последнее значение Count, используемое в цикле, равно 99. Когда цикл заканчивается, значение Count равно 101.
Значение переменной S tep в цикле F or-N ext может быть также отрицательным. Приведенная ниже процедура удаляет строки 2, 4, 6, 8 и 10 в активном листе.
Sub DeleteRowsO
Dim RowNum As Long
For RowNum = 10 To 2 Step -2
Rows(RowNum).Delete
Next RowNum
End Sub
На первый взгляд, вызывает удивление использование отрицательного значения пере менной S tep в процедуре DeleteRows. Если же использовать положительные значения переменной Step, как показано в следующей процедуре, будут удалены не те строки. Это связано с тем, что строки, находящиеся под удаленными строками, получают новые номе ра. Например, если удалена 2-я строка, 3-я строка получает номер 2. Эту проблему можно устранить путем использования отрицательных значений переменной Step.
Sub D eleteR ows2()
Dim RowNum As Long
For RowNum = 2 To 10 Step 2
Rows(RowNum).Delete
Next RowNum
End Sub
Следующая процедура выполняет ту же задачу, что и пример цикла BadLoop, кото рый приводился в начале раздела “Циклическая обработка инструкций”. В данном слу чае был устранен оператор GoTo, благодаря чему “плохой цикл” был превращен в “хороший цикл”, в котором используется структура F or-N ext.
Sub GoodLoop() |
|
As |
In te g e r |
|
||
Dim S ta rtV a l |
|
|||||
Dim N um ToFill |
As |
In te g e r |
|
|||
Dim Cnt |
As |
|
In te g e r |
|
||
S ta rtV a l |
= |
= |
1 |
|
|
|
NumToFill |
100 |
|
|
|||
For Cnt |
= |
0 |
To N um T oF ill |
- 1 |
||
A c tiv e C e ll. O ffs e t( C n t, |
0 ) .V alue = S ta rtV a l + Cnt |
|||||
Next Cnt |
|
|
|
|
|
|
End Sub |
|
|
|
|
|
|
Циклы F or-N ext могут также содержать один или более операторов E x it For. Когда программа встречает этот оператор, то сразу же выходит из цикла, как показано в следующем примере. Эта процедура определяет, какая ячейка столбца А на активном рабочем листе имеет наибольшее значение.
248 |
|
|
|
|
Часть III. Visual Basic for Applications |
Sub |
E xitF orD em o() |
||||
|
Dim |
MaxVal |
As Double |
||
|
Dim |
Row As |
Long |
||
|
MaxVal |
= |
A p p lic a tio n .W o rk s h e e tF u n c tio n .M a x (R a n g e ( "A :A ")) |
||
|
For |
Row |
= |
1 To 1048576 |
|
|
I f |
C ells(R o w , 1 ) .V alue = MaxVal Then |
|||
|
|
|
E x it |
For |
|
|
End |
I f |
|
||
|
N ext |
Row |
|
|
|
|
MsgBox |
"Максимальное значение в строке " & Row |
|||
|
C ells(R o w , |
1 ) .A c tiv a te |
|||
End |
Sub |
|
|
|
|
Максимальное значение в столбце вычисляется с помощью функции Excel МАХ. Затем это значение присваивается переменной MaxVal. Цикл F or-N ext проверяет каждую ячейку в столбце. Если определенная ячейка равна MaxVal, оператор E x it For закан чивает процедуру. Однако перед выходом из цикла процедура сообщает пользователю о расположении искомой ячейки и активизирует ее.
Примечание
Пример ExitForDem o представлен с целью продемонстрировать выход из цикла F o r-N e xt. Однако это не самый эффективный способ найти макси мальное значение в диапазоне. Поставленную задачу может выполнить единственный оператор.
Range( " А :А " ) . F in d (A p p lic a tio n .W o rk s h e e tF u n c tio n .M a x _ (Range( "A :A ") ) ) .A c tiv a te
В предыдущих примерах использовались достаточно простые циклы. Но вы можете помещать в цикл любое количество операторов и даже вкладывать циклы For-N ext в другие циклы For-N ext. Ниже приведен пример, в котором применены вложенные циклы F or-N ext для инициализации массива 10x10x10 значением -1. По завершении выполне ния процедуры все 1000 элементов массива МуАггау будут содержать значение -1.
Sub |
N estedLoops() |
|
|
|
|
|
|
|
|
||||||
|
Dim |
М уА ггау(1 |
to |
10, |
1 |
to |
10, |
1 |
to |
10) |
|||||
|
Dim |
i |
As |
|
In te g e r, j |
As |
In te g e r, |
k |
As In te g e r |
||||||
|
For |
i |
= |
1 |
To |
10 |
|
|
|
|
|
|
|
|
|
|
For |
j |
|
= |
1 |
To |
10 |
|
|
|
|
|
|
|
|
|
|
|
For |
k |
= |
1 |
To |
10 |
|
|
|
|
|
|
|
|
|
|
|
|
M y A rra y (i, |
j , |
k) |
= -1 |
|
|
|
||||
|
|
|
Next |
k |
|
|
|
|
|
|
|
|
|
||
|
N ext |
j |
|
|
|
|
|
|
|
|
|
|
|
||
|
N ext |
i |
|
|
|
|
|
|
|
|
|
|
|
|
|
End |
Sub |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Циклы Do |
W h ile |
|
|
|
|
|
|
|
|
|
|||||
Оператор |
Do |
W h ile — |
еще |
один |
тип |
циклической структуры, представленной |
|||||||||
в VBA. В отличие от цикла F or-N ext, цикл Do W hile выполняется до тех пор, пока удовлетворяется заданное условие. Цикл Do W hile может иметь один из двух пред ставленных ниже синтаксисов.
Do [W hile |
у с л о в и е ] |
[инст рукции] |
|
[E x it |
Do] |
Глава 8. Основы программирования на VBA |
249 |
[инст рукции]
Loop
или
Do
[инст рукции]
[E x it Do]
[инст рукции]
Loop [W hile условие]
Как видите, VBA позволяет проверять условие W hile в начале или в конце цикла. Разница между этими двумя синтаксисами связана с моментом, когда оценивается усло вие. В первом синтаксисе содержимое цикла может вообще не выполняться. Во втором содержимое цикла всегда выполняется (как минимум один раз).
Вследующих примерах в активный рабочий лист вставляется набор дат. Эти даты со ответствуют дням текущего месяца, а их ввод в столбец осуществляется, начиная с ак тивной ячейки.
Вэтих примерах используются некоторые функции VBA, обрабатывающие даты:
•D ate возвращает текущую дату;
•Month возвращает номер месяца для даты, являющейся аргументом;
• D a te S e ria l конструирует дату на основе значений дня, месяца и года, указан ных в качестве аргументов.
В первом примере демонстрируется цикл Do W hile, в котором реализована провер ка условия в начале цикла: процедура E n te rD a te sl вводит даты текущего месяца в столбец рабочего листа, начиная с активной ячейки.
Sub E n te rD a te s l () |
|
||
' цикл |
Do |
W h ile , |
условие проверяется в начале |
Dim TheDate |
As Date |
||
TheDate |
= D a te S e ria l(Y e a r(D a te ), M o n th (D a te ), 1) |
||
Do While |
M onth(TheDate) = M onth(D ate) |
||
A c tiv e C e ll = TheDate
TheDate = TheDate + 1
A c t iv e C e ll. O ff s e t(1, 0 ) .A c tiv a te
Loop
End Sub
В этой процедуре используется переменная TheDate, которая хранит даты, записан ные в рабочем листе. Для инициализации переменной используется первый день текуще го месяца. В процессе выполнения цикла значение переменной TheD ate было введено в активную ячейку, затем это значение было увеличено на единицу, после чего активизи руется следующая ячейка. Цикл выполняется до тех пор, пока значение месяца, присво енное переменной TheD ate, совпадет со значением месяца текущей даты.
Результат выполнения следующей процедуры будет таким же, что и результат выпол нения процедуры E n te rD a te sl, но в данном случае используется вторая форма син таксиса цикла Do W hile, предусматривающая проверку условия в конце цикла.
Sub E n te rD a tes2 () |
|
' цикл Do W h ile , |
условие проверяется в конце |
Dim TheDate As |
Date |
TheDate = D a te S e ria l(Y e a r(D a te ), M o n th (D a te ), 1)
Do
A c tiv e C e ll = TheDate
250 |
Часть III. Visual Basic for Applications |
|
TheDate = TheDate + 1 |
|
A c t iv e C e ll. O ff s e t(1, 0 ) .A c tiv a te |
|
Loop W h ile M onth(TheDate) = M onth(D ate) |
End |
Sub |
Ниже представлен пример цикла Do W h ile . Эта процедура открывает текстовый файл, |
|
считывает каждую строку и преобразует текст в символы верхнего регистра. Затем текст сохраняется на активном рабочем листе, начиная с ячейки А1 в направлении вниз до конца столбца. Данная процедура использует функцию VBA EOF, которая возвращает значение T ru e по достижении конца файла. Последний оператор закрывает текстовый файл.
Sub |
DoW hileDem ol() |
|
|
|||
|
Dim |
L in e C t As |
Long |
|
|
|
|
Dim |
L in e O fT e xt |
As |
S trin g |
|
|
|
Open " c : \ d a t a \ t e x t f i l e . t x t " For |
In p u t As #1 |
||||
|
L in e C t = |
0 |
|
|
|
|
|
Do |
W h ile |
Not EO F(l) |
|
||
|
|
L in e |
In p u t |
#1, |
L in e O fT e xt |
|
|
|
Range( " A l" ) .O ffs e t( L in e C t, 0) |
= U C ase (L ine O fT ext) |
|||
|
|
L in e C t = L in e C t + 1 |
|
|||
|
Loop |
|
|
|
|
|
|
C lose #1 |
|
|
|
|
|
End |
Sub |
|
|
|
|
|
Перекрестная ссылка
ОДополнительные сведения о чтении и записи текстовых файлов с помощью VBA можно найти в главе 27.
Циклы Do W h ile также могут включать один или более операторов E x it Do. По достижении оператора E x it Do цикл завершается, а управление передается оператору, следующему за оператором Loop.
Циклы Do U n t il
Структура цикла Do U n t i l имеет много общего с конструкцией Do W h ile . Разни ца заключается лишь в том, как проверяется условие цикла. В варианте Do W h ile цикл выполняется до тех пор, пока выполняется условие. В цикле Do U n t i l цикл выполня ется, пока условие не станет выполняться.
Структура Do U n t i 1 может быть представлена двумя вариантами синтаксиса.
Do [U n til у сл о в и е ]
[инст рукции]
[E x it Do]
[инст рукции]
Loop
или
Do
[инст рукции]
[E x it Do]
[инст рукции]
Loop [ U n til у с л о в и е ]
Ниже показаны два примера кода, смотренные ранее примеры циклов Do ключается в месте проверки условия (в
которые выполняют те же действия, что и рас W h ile . Отличие между этими процедурами за
начале либо в конце цикла).
Глава 8. Основы программирования на VBA |
|
251 |
|||||
Sub E n te rD a te s 3 () |
|
|
|
|
|
||
1 |
Цикл Do |
U n t il, |
проверка |
условия |
в начале |
|
|
|
Dim TheDate As |
Date |
|
|
|
|
|
|
TheDate |
= D a te S e ria l(Y e a r(D a te ), |
M o n th (D a te ), |
1) |
|||
|
Do U n t il |
M onth(TheDate) |
<> |
M onth(D ate) |
|
||
|
A c tiv e C e ll |
= TheDate |
|
|
|
|
|
|
TheDate = TheDate + 1 |
|
|
|
|
||
|
A c t iv e C e ll. O f f s e t (1, |
0 ) .A c tiv a te |
|
||||
|
Loop |
|
|
|
|
|
|
End Sub |
|
|
|
|
|
|
|
Sub E n te rD a te s 4 () |
|
|
|
|
|
||
1 |
Цикл Do |
U n t il, |
проверка |
условия |
в конце |
|
|
|
Dim TheDate As |
Date |
|
|
|
|
|
|
TheDate |
= D a te S e ria l(Y e a r(D a te ), |
M o n th (D a te ), |
1) |
|||
|
Do |
|
|
|
|
|
|
|
A c tiv e C e ll |
= TheDate |
|
|
|
|
|
|
TheDate = TheDate + 1 |
|
|
|
|||
|
A c t iv e C e ll. O ff s e t(1, |
0 ) .A c tiv a te |
|
||||
|
Loop U n t il M onth(TheDate) |
<> M onth(D ate) |
|
||||
End Sub |
|
|
|
|
|
|
|
Следующий пример сначала использовал цикл Do W hile, но позднее был переписан с учетом применения цикла Unt i 1. В результате изменилась единственная строка, в ко торой находится оператор Do. Получился более “прозрачный” код, не требующий отри
цательных значений переменной S tep, как было в примере с циклом Do W hile. |
||||
Sub DoU ntilD em ol () |
|
|
||
Dim L in e C t As |
Long |
|
|
|
Dim L in e O fT e xt |
As |
S trin g |
|
|
Open " c : \ d a t a \ t e x t f i l e . t x t " For |
In p u t As #1 |
|||
LineCt = |
0 |
|
|
|
Do U n t il |
EOF(1) |
|
|
|
L in e |
In p u t |
#1, |
L in e O fT e xt |
|
Range( " A l" ) . O ffs e t( L in e C t, 0) |
= U C ase (L ine O fT ext) |
|||
L in e C t = L in e C t + 1 |
|
|||
Loop |
|
|
|
|
Close #1 |
|
|
|
|
End Sub |
|
|
|
|
Примечание
В VBA используется еще один вид цикла, w h ile Wend. Эта циклическая структура была включена в целях обеспечения совместимости и вряд ли вы
встретите ее на практике. Ниже приведен код процедуры |
ввода данных, |
|
в котором используется цикл W h ile Wend. |
|
|
Sub |
E n te rD a te s 5 () |
|
|
Dim TheDate As Date |
|
|
TheDate = D a te S e ria l(Y e a r(D a te ), M o n th (D a te ), |
1) |
|
W h ile M onth(TheDate) = M onth(D ate) |
|
|
A c tiv e C e ll = TheDate |
|
|
TheDate = TheDate + 1 |
|
|
A c t iv e C e ll. O f f s e t (1, 0 ) .A c tiv a te |
|
|
Wend |
|
End |
Sub |
|
