Автор — Шмаков Иван Владимирович .
Почтовый ящик автора в интернете — IvanShmakov@yandex.ru Сайт автора — IvanShmakov2.narod.ru Все права защищены . В электронном виде настоящая книга используется для обучения преподавателей Санкт-Петербургского Политехнического Университета . Рассмотрю все предложения об издании её в бумажном виде , согласен на гонорар в размере одного рубля с каждого экземпляра ( например , при тираже 200 000 мой гонорар составит двести тысяч рублей ) .
ШМАКОВ И.В. VBA С НОЛЯ
Выполнив все упражнения ( “ уроки ” и “ задачи ” ) этой книги , Вы напишите “ настоящую ” , полезную программу , которую можно использовать для преподавания истории , и научитесь рационально и быстро писать программы на VBA . Макросы Microsoft Word 97 и Microsoft Word 2000 пишутся на VBA . Если Вы уже писали макросы , то Вы программировали на VBA . Оглавление : Урок 1 . Папка “ шаблоны ” , Ярлык , Шаблон без мусора Итог Урок 2 . Параметры страницы , Стиль “ обычный ” Итог Урок 3 . Создание панели , Сохранение шаблона Итог Урок 4 . Начинаем программировать Итог Урок 5 . Встроенная функция Chr(n) Итог Урок 6 . ParamArray , Рекурсия Итог Урок 7 . Вставка номеров страниц Итог Урок 8 . Select Case , Глобальные переменные и массивы Итог Урок 9 . Timer , Optional Итог Урок 10 . InputBox , MsgBox Итог Урок 11 . Каждому вопросу - свою паузу , Полноэкранный режим Итог Урок 12 . ThisDocument Итог Урок 13 . Ctrl Pause Break Итог Задача 1 . Число пропущенных вопросов Урок 14 . ByVal , ByRef Итог Урок 15 . Циклы , Дробная и целая части Итог Задача 2 . Простой способ задания диалога Урок 16 . Нумерованные диалоги Итог Урок 17 . Выбор диалога Итог Урок 17 А . Традиционная обработка ошибок Итог Урок 18 . Усовершенствованный выбор диалога Итог Урок 19 . Изменение паузы Итог Урок 20 . Подтипы вопросов Итог Урок 21 . Разбиение на подтипы ( начало ) Итог Задача 3 . Модификация процедуры ББ4 Урок 22 . Разбиение на подтипы ( продолжение ) Итог Задача 4 . Наименьшее общее кратное Задача 5 . Модификация Б2 Урок 23 . Разбиение на подтипы ( продолжение ) Итог Урок 24 . Разбиение на подтипы ( продолжение ) Задача 6 . Число разных подтипов Урок 25 . Разбиение на подтипы ( продолжение ) Задача 7 . Число разных подтипов Урок 26 . Разбиение на подтипы ( конец ) Итог Урок 27 . Процедура , задающая 2 целых числа по десятичной дроби Итог Урок 28 . Первый тип контрольной Урок 29 . Нумерация вопросов Урок 30 . Автоматическое создание макроса Итог Урок 31 . Квадратик вместо номера ответа Итог Урок 32 . Удаление модуля Итог Задача 8 . Сколько массивов может быть передано процедуре с помощью ключа ParamArray ? Урок 33 . Автотекст ( начало ) Итог Урок 34 . Автотекст ( продолжение ) Итог Урок 35 . Автотекст ( конец ) Итог Урок 36 . Первый способ навигации по проверочным Итог Урок 37 . Совершенствование первого способа навигации по проверочным Итог Задача 9 . ДаНет с ParamArray Урок 38 . Процедуры-функции Итог Задача 10 . фДаНет с ParamArray Урок-задача 39 . Единая нумерация вопросов нескольких проверочных Итог Урок 40 . НумероватьВопросы , Квадратики Итог Урок 41 . gПечатьОтветов Итог Урок 42 . Быстрое приведение кнопок в соответствие значениям глобальных переменных Итог Задача 11 . Соответствие кнопок глобальным переменным при открытии шаблона Урок 43 . Модификация фNot Итог Урок 44 . Добавление вопросов Итог Урок 45 . Второй способ навигации по проверочным Итог Урок 46 . TypeName Итог Урок 47 . Омоложение шаблона Итог Урок 48 . Защита шаблона ( начало ) Итог Урок 49 . Защита шаблона ( конец ) Итог ЭПИЛОГ
Урок 1 папка “ шаблоны ” ярлык шаблон без мусора
К оглавлению 1) Откройте Microsoft Word ( почти всегда это можно сделать , нажав “ Пуск ” , наведя мышь на “ Программы ” и нажав “ Microsoft Word ” ) . 2) В головном меню ( наверху ) нажмите “ Сервис ” , вниз выпадет меню ; в этом меню нажмите “ Параметры ” , появится диалоговое окно “ Параметры ” ; в правом верхнем углу этого окна найдите кнопку “ Расположение ” и нажмите её. 3) В открывшемся окне в третьей строчке посмотрите , где расположены “ шаблоны пользователя ” ( обычно эти шаблоны расположены в папке “ C: \ Program Files \ Microsoft Office \ Шаблоны ” ) ; запишите , где расположены эти шаблоны именно в Вашем компьютере , и нажмите “ Отмена ” . Файл с программой на VBA профессиональные программисты не очень удачно называют “шаблоном” . Это название ассоциируется с простотой , примитивностью и трафаретностью ( жёсткостью , негибкостью ) . На самом деле , “ шаблон ” может быть очень серьёзной , гибкой и эффективной программой . Только что записанная Вами информация очень важна , так как многие шаблоны не будут правильно работать , если расположены не в папке “ шаблонов пользователя ” . 4) На клавиатуре нажмите сначала кнопку Alt и затем , не отпуская её , кнопку F4 ; Microsoft Word закроется , и Вы вернётесь на Рабочий стол . 5) Откройте папку , где расположена папка “ шаблонов пользователя ” , ( обычно это “ C: \ Program Files \ Microsoft Office ” ) . 6) В этой папке найдите папку “ шаблонов пользователя ” ( обычно это “ Шаблоны ” ) ; наведите на неё мышь и , нажав правую кнопку мыши , перетащите её на Рабочий стол . Отпустите кнопку мыши , и появится контекстное меню : Переместить Копировать Создать ярлык(и) Отменить Нажмите Создать ярлык(и) . Вид перетащенной папки должен слегка измениться ( должна появиться стрелочка ) , а под новым значком должна появиться надпись “ Ярлык для … ” ( вместо многоточия - имя папки ) . Правой кнопкой мыши называют кнопку , расположенную напротив Вашей правой стороны ; если Вы правша , Вам удобнее нажимать её не указательным , а безымянным пальцем . Если Вы с другом стоите лицом друг к другу , то напротив Вашей правой руки находится его левая рука , но если Вы стоите лицом к шкафу , то напротив вашей правой руки находится его правая же сторона . Текст , который Вы сейчас читаете , написан слева направо , и если его перед Вами будет держать Ваш друг , то правой рукой он будет держать левую сторону текста , а левой - правую . Таким образом , в русском языке термины “ левый ” и “ правый ” по отношению к одушевлённым и неодушевлённым предметам употребляются различно . Однако Windows может быть настроена так , что правая и левая кнопки поменяются ролями . В этом случае , когда Вы отпустите правую кнопку мыши , не появится контекстное меню , а папка “ шаблонов пользователя ” будет скопирована или перемещена . Если папка будет скопирована ( “ раздвоится ” ) - папку с Рабочего стола удалите в корзину , если перемещена ( т.е. если исчезнет из папки , откуда Вы её перетаскивали ) - верните её обратно . 7) На только что созданный Вами ярлык наведите мышь и нажмите её правую кнопку ( в дальнейшем я не буду напоминать , что правая и левая кнопки мыши могут поменяться ролями ) - появится довольно большое контекстное меню . В этом контекстном меню найдите слово Переименовать и нажмите его - выделенное имя ярлыка станет находиться в рамке с левым и правым полями . На клавиатуре нажмите кнопку Ctrl и , не отпуская её , кнопку Home , отпустите кнопки - выделение с имени ярлыка снимется и курсор окажется в начале этого имени . Нажмите кнопку Shift и , не отпуская её , кнопкой со стрелкой вправо ( также расположенной на клавиатуре ) выделите “Ярлык для ” , отпустите кнопки , нажмите и отпустите кнопку Delete ( также расположенную на клавиатуре ) - имя ярлыка сократится , и он станет меньше занимать места на Рабочем столе . 8) Нажимая крестики , закройте все папки . Наведите мышь на только что переименованный Вами ярлык В этом случае , когда Вы отпустите правую кнопку мыши , не появится контекстное меню , а папка “ шаблонов пользователя ” будет скопирована или перемещена . Если папка будет скопирована ( “ раздвоится ” ) - папку с Рабочего стола удалите в корзину , если перемещена ( т.е. если исчезнет из папки , откуда Вы её перетаскивали ) - верните её обратно . 7) На только что созданный Вами ярлык наведите мышь и нажмите её правую кнопку ( в дальнейшем я не буду напоминать , что правая и левая кнопки мыши могут поменяться ролями ) - появится довольно большое контекстное меню . В этом контекстном меню найдите слово Переименовать и нажмите его - выделенное имя ярлыка станет находиться в рамке с левым и правым полями . На клавиатуре нажмите кнопку Ctrl и , не отпуская её , кнопку Home , отпустите кнопки - выделение с имени ярлыка снимется и курсор окажется в начале этого имени . Нажмите кнопку Shift и , не отпуская её , кнопкой со стрелкой вправо ( также расположенной на клавиатуре ) выделите “Ярлык для ” , отпустите кнопки , нажмите и отпустите кнопку Delete ( также расположенную на клавиатуре ) - имя ярлыка сократится , и он станет меньше занимать места на Рабочем столе . 8) Нажимая крестики , закройте все папки . Наведите мышь на только что переименованный Вами ярлык и дважды нажмите левую кнопку мыши - откроется папка “ шаблонов пользователя ” . 9) В этой папке найдите файл “ Normal.dot ” , наведите на него мышь и нажмите её правую кнопку - появится довольно большое контекстное меню . В этом контекстном меню найдите слово Переименовать и нажмите его - выделенное имя файла станет находиться в рамке с левым и правым полями . На клавиатуре нажмите кнопку Ctrl и , не отпуская её , кнопку End , отпустите кнопки - выделение с имени файла снимется и курсор окажется в конце этого имени . 4 раза нажмите кнопку со стрелкой влево - курсор окажется перед точкой . Клавиатурой наберите сегодняшнюю дату , например - 22_01_2002 ( нельзя использовать точку !!! ) , и нажмите Enter - файл сменит имя . В результате выполнения пунктов 7 и 9 Вы научились переименовывать файлы . В дальнейшем такую процедуру я не буду описывать так подробно , а буду писать : “ Переименуйте файл … в … ” . Normal.dot - это шаблон Word , доступный всем документам Word и всем файлам в формате RTF, и может влиять на работу любого другого шаблона Word ( не всегда положительно ) . Поэтому важно иметь именно стандартный , не изменённый Normal.dot - не вносите в него никаких изменений , кроме , если хотите , удаления элементов автотекста ( на уроке 35 мы обсудим , зачем это может быть нужно ) . Однако , на Вашем компьютере , возможно , кто-то изменил его ( например , записал макрос ) . Чтобы эта работа не пропала , мы не удалили Normal.dot в корзину , а переименовали . 10) На только что переименованный Вами шаблон наведите мышь и дважды нажмите её левую кнопку - будет создан файл в шаблоне , который Вы только что переименовали . Не внося в этот файл никаких изменений , нажмите Alt F4 - Word закроется , а в папке шаблонов появится новый Normal.dot . Любой файл ( как и любую папку ) можно открывать двойным нажатием левой кнопки мыши . В дальнейшем я не буду описывать эту процедуру , а буду писать : “ Откройте файл … ” . 11) Наведите мышь на новый Normal.dot и нажмите её правую кнопку - появится контекстное меню . Найдите в нём слово Свойства и нажмите его - откроется диалоговое окно “ Свойства: Normal.dot ” . В этом диалоговом окне нажмите кнопку Общие и посмотрите размер Normal.dot в килобайтах и байтах ( эти данные желательно переписать на бумагу ; обратите внимание , что один килобайт больше тысячи байтов ) . Нажмите кнопку Отмена - диалоговое окно закроется . 12) Переименуйте Normal.dot в История.dot . Откройте История.dot . 13) В головном меню нажмите слово Формат . В выпавшем меню нажмите слово Стиль ; в появившемся диалоговом окне нажмите кнопку Организатор - появится диалоговое окно Организатор . В этом диалоговом окне нажмите кнопку Автотекст - в левом нижнем оконце будет стоять История.dot , а в оконце над ним - полный список элементов автотекста шаблона История.dot . Удалите их всех с помощью кнопки Удалить диалогового окна . Нажмите кнопку Закрыть в правом нижнем углу диалогового окна . Компьютер спросит , сохранить ли изменения в “ документе ” История.dot . Ответьте Да . 14) Закройте Word , нажав Alt F4 . 15) Посмотрите размер История.dot - он окажется меньше чем был у Normal.dot . 16) Отформатируйте дискету и скопируйте на неё История.dot . Для диска А Вы также можете создать ярлык и получить быстрый доступ к дискетам . Выполнив урок 1 , Вы научились : 1) Находить системную папку шаблонов пользователя . 2) Быстро закрывать Word . Alt F4 - почти универсальный “ закрыватель ” . В частности , этим сочетанием клавиш можно закрывать и Windows . 3) Создавать ярлык . 4) Переименовывать файл . 5) Быстро открывать папку с помощью ярлыка . С помощью ярлыка можно быстро открывать не только папку , но и любой файл и любой диск . 6) Открывать файл двойным нажатием левой кнопки мыши . Шаблон важно открывать именно двойным нажатием левой кнопки мыши , а не её правой кнопкой , так как при двойном нажатии создаётся новый документ Word или текст в формате RTF ( в зависимости от настройки Word ) , а при открытии шаблона правой кнопкой мыши - нет , и любой текст , Вами набранный , любой рисунок , Вами нарисованный или вставленный , будет относиться непосредственно к этому шаблону , может сохраниться в этом шаблоне и очень быстро увеличить его объём . В шаблоне следует хранить только “ программную ” информацию . 7) Создавать стандартный Normal.dot . 8) Узнавать точный размер файла . 9) Создавать “ чистый ” , без ненужной информации , малый по размеру ( числу байтов ) шаблон Word . Следующий итог К оглавлению
Урок 2 Параметры страницы Стиль “ обычный ”
Действия в начале второго урока зависят от того , действительно ли Ваш компьютер персональный . Т.е. от того , только ли Вы пользуетесь им или кто-то ещё . В первом случае вполне можно просто открыть шаблон История.dot . Если же компьютером пользуется кто-то ещё , то другой пользователь ( особенно ребёнок ) преднамеренно или случайно может изменить Ваш шаблон . В этом случае Ваш шаблон из системной папки разумно временно сохранить на Рабочем столе , а в системную папку скопируйте шаблон с дискеты . Если окажется ( это маловероятно ) , что шаблон на дискету записался плохо или что она испортилась при хранении , то Вы воспользуетесь файлом , который сохранили на Рабочем столе , в противном случае - в конце работы удалите его ( файл , сохранённый на Рабочем столе ) в корзину . Вообще , жёсткий диск - очень ненадёжный хранитель информации , все созданные Вами файлы обязательно копируйте на дискеты . К оглавлению 1) С помощью ярлыка , откройте папку шаблонов пользователя . 2) Используя правую кнопку мыши , переместите История.dot на Рабочий стол . 3) Вставьте в дисковод дискету , на которой Вы сохранили История.dot . 4) Откройте диск А . 5) Левой кнопкой мыши перетащите История.dot с диска А в папку шаблонов пользователя , отпустите кнопку - файл История.dot будет скопирован ( “ раздвоится ” ) , а не перемещён . 6) Выньте дискету из дисковода , закройте папку диска А . 7) Двойным нажатием левой кнопки мыши откройте История.dot ( естественно , файл , к этому времени помещённый в папку шаблонов пользователя , а не на Рабочем столе ) . 8) Левой кнопкой мыши нажмите Вид , Разметка страницы ( т.е. сначала слово Вид в головном ( верхнем ) меню , затем - слова Разметка страницы в выпавшем вниз меню ) . Левой кнопкой мыши нажмите Вид , Масштаб - появится диалоговое окно “ Масштаб ” . В этом диалоговом окне отметьте по ширине страницы и нажмите ОК . На клавиатуре наберите какое-нибудь слово - например , “ Арбуз ” . Наверно , оно показалось Вам слишком мелким . 9) Левой кнопкой мыши нажмите Файл , Параметры страницы - откроется диалоговое окно “ Параметры страницы ” . 10) В этом диалоговом окне левой кнопкой мыши нажмите Поля и установите : Верхнее 1,6 см Нижнее 1 см Левое 0,5 см Правое 0,5 см Переплёт 0 см От края до колонтитула верхнего 0,7 см нижнего 0,7 см 11) Левой кнопкой мыши нажмите Размер бумаги и установите : Размер бумаги Ширина 16,7 см Высота 28,5 см Ориентация книжная Применить Ко всему документу 12) Нажмите По умолчанию - компьютер спросит : “ Изменить параметры страницы , используемые по умолчанию ? ” . Левой кнопкой мыши нажмите Да . Буквы на экране станут крупнее . 13) Нажмите Alt F4 - компьютер спросит : “ Сохранить изменения в документе “ Документ1 ” ? ” . Левой кнопкой мыши нажмите Нет - компьютер спросит : “ Сохранить изменения в документе “ История.dot ” ? ” . Левой кнопкой мыши нажмите Да - новые параметры страницы сохранятся в шаблоне История.dot ( но не будут влиять на работу других шаблонов ) . Сейчас мы установили ширину страницы существенно меньшую чем у стандартного машинописного листа . При наборе текста на компьютере часто устанавливают большое левое поле , так как распечатанный на нескольких страницах текст потом нужно будет как-то скрепить . Однако гораздо рациональнее установить не большое левое поле , а меньшую ширину страницы , а чтобы сделать поле на бумаге , просто сдвинуть её влево в принтере . В таком случае буквы и рисунки на экране будут крупнее и Ваши глаза будут меньше уставать . Ориентация книжная приведёт к тому , что текст будет набираться и печататься поперёк листа . При альбомной же ориентации текст набирается и печатается вдоль листа . Другие установленные нами параметры также имеют некоторое значение , так как обеспечивают более правильную печать на принтере ( если драйвер принтера , установленный на компьютере , не вполне соответствует марке принтера ) . 14) Левой кнопкой мыши нажмите Формат , Стиль - откроется диалоговое окно “ Стиль ” . Левой кнопкой мыши отметьте “ Обычный ” ( в левом верхнем оконце ) и левой же кнопкой мыши нажмите Изменить - откроется диалоговое окно “ Изменение стиля ” . В этом окне левой кнопкой мыши нажмите Формат , Шрифт - откроется диалоговое окно “ Шрифт ” . В этом диалоговом окне левой кнопкой мыши нажмите Шрифт и установите Размер 16 , нажмите Интервал и установите Интервал Разреженный . 15) Левой кнопкой мыши нажмите ОК - Вы вернётесь в диалоговое окно “ Изменение стиля ” . В этом окне левой кнопкой мыши нажмите Формат , Абзац - откроется диалоговое окно “ Абзац ” . В этом диалоговом окне левой кнопкой мыши нажмите Отступы и интервалы и установите : Выравнивание По левому краю Уровень Основной текст Отступ слева 0 см справа 0 см первая строка Отступ Интервал перед 6 пт после 0 пт междустрочный Одинарный . В этом же диалоговом окне левой кнопкой мыши нажмите Положение на странице и левой кнопкой мыши отметьте “ не разрывать абзац ” . 16) Левой кнопкой мыши нажмите ОК - Вы вернётесь в диалоговое окно “ Изменение стиля ” . Левой кнопкой мыши отметьте “ Добавить в шаблон ” и нажмите ОК - Вы вернётесь в диалоговое окно “ Стиль ” . В этом окне левой кнопкой мыши нажмите Применить . 17) Закройте Word , сохранив изменения в История.dot . 18) Отформатируйте ещё одну дискету и скопируйте на неё История.dot . Вам нужно иметь по крайней мере 3 дискеты , на которые Вы будете циклически копировать последовательные версии ( т.е. состояния ) История.dot : после первого урока - на первую , после второго - на вторую , после третьего - на третью , после четвёртого - опять на первую и т.д. . При таком порядке в случае порчи последней версии Вы будете иметь возможность вернуться немного назад . Такое правило будет особенно важно , когда Вы будете писать программы не по моей или другой шпаргалке , а самостоятельно : в сложную , обширную программу Вы можете внести ошибки , таким образом нарушающие правильную работу программы , что Вы сразу этого не заметите ; в таком случае Вам будет практически необходимо вернуться к более ранним версиям программы . При этом разумно выделить дискеты как для короткого цикла ( по меньшей мере три дискеты ) , так и для длительного хранения ( если есть обширное место для хранения дискет , можно еженедельно копировать последнюю версию программы на новую дискету , которую хранить вечно ) . Выполнив урок 2 , Вы научились : 1) Быстро ( левой кнопкой мыши ) копировать файл с диска на диск . 2) Устанавливать параметры страницы и сохранять их в шаблоне . 3) Менять параметры стиля и сохранять их в шаблоне . Стиль “ Обычный ” - это стиль , в который Вы попадаете , создавая новый файл в Вашем шаблоне , в том числе и открывая Ваш шаблон двойным нажатием левой кнопки мыши , если только попадание в другой стиль Вы специально не запрограммируете . Кроме этого Вы узнали некоторые правила , которые обеспечивают более надёжную работу компьютера . Следующий итог К оглавлению
Урок 3 Создание панели Сохранение шаблона
До настоящего времени мы сохраняли шаблон только при закрытии Word . Сейчас мы научимся сохранять шаблон в процессе работы . Это очень важно , так как иногда компьютер сообщает : “ Программа WinWord выполнила недопустимую команду и будет закрыта . Все несохранённые данные будут потеряны ” и много времени и сил при этом может быть потрачено напрасно ( чтобы этого не произошло , нужно постоянно сохранять результаты работы : если Вы изменяете текстовый файл ( документ Word или текст в формате RTF ) , надо сохранять его , если Вы изменяете программный файл ( например , шаблон Word ) , надо сохранять его , а не текстовый файл ) . В Microsoft Word для сохранения текстового файла служит одна команда , для сохранения шаблона - другая . К оглавлению 1) Наведите мышь на головное меню и нажмите её правую кнопку - появится список панелей инструментов . Галочка напротив названия панели означает , что в настоящее время панель видна на экране . Отсутствие галочки значит , что в настоящее время панель скрыта . Как ставить , так и убирать галочку можно , наведя на название панели мышь и нажав кнопку мыши ( правую или левую - всё равно ) . Уберите с экрана все панели кроме “ Форматирование ” . Если на экране нет этой панели , поставьте напротив её названия галочку - она появится на экране . Если на экране есть только панель “ Форматирование ” , никакой другой , и Вы не знаете , как убрать с экрана список панелей , - наведите мышь на любое место страницы вне списка панелей и нажмите левую кнопку мыши . Список панелей при этом исчезнет . 2) На левом краю панели “ Форматирование ” - три окошечка . Первое ( левое ) показывает , какой стиль будет иметь набираемый текст . Второе - какой шрифт будет иметь набираемый текст . Третье - какой размер будет иметь набираемый текст . Чем крупнее размер ( т.е. чем большее число стоит в третьем окошечке ) , тем крупнее буквы текста . Если предыдущий урок Вы выполнили правильно , то в третьем окошечке стоит число 16 . На клавиатуре наберите какое-нибудь слово ( например , “ Москва ” ) и убедитесь , что на предыдущем уроке мы вполне разумно определили стиль “ Обычный ” , так как текст хорошо читается . 3) Щёлкните правой кнопкой мыши ( т.е. наведите мышь и нажмите правую кнопку мыши ) на головном меню или панели “ Форматирование ” - появится уже знакомый Вам список панелей . Обратите внимание , что в конце списка - слово “ Настройка ” , отделённое чертой . Оно не является названием панели . Щёлкните на нём левой или правой кнопкой мыши - появится диалоговое окно “ Настройка ” . 4) В этом диалоговом окне левой кнопкой мыши нажмите Команды , в маленьком нижнем окошечке установите “ История.dot ” . 5) Левой кнопкой мыши нажмите Панели инструментов , Создать . Вместо слова “ Настраиваемая1 ” клавиатурой наберите “ История ” . Нажмите ОК , Закрыть . В каком-то месте экрана появилась маленькая новая панель . 6) Левой кнопкой мыши ( не нажимайте на крестик ) перетащите её в левый верхний угол экрана под панель “ Форматирование ” . Отпустите кнопку мыши . 7) Вызовите диалоговое окно “ Настройка ” , нажмите Команды , установите “ История.dot ” . 8) В окошечке “ Категории ” найдите слова “ Все команды ” и щёлкните на них левой кнопкой мыши . 9) В окошечке “ Команды ” найдите слово “ SaveTemplate ” и левой кнопкой мыши перетащите его на панель “ История ” . Отпустите кнопку мыши . Нажмите Закрыть . 10) На панели “ История ” появилась кнопка “ Сохранить шаблон ” . Смотря на строку состояния внизу экрана , левой кнопкой мыши нажмите эту кнопку - в строке состояния на очень краткое время появятся слова “ Сохранение История.dot ” , которые значат , что Вы сохранили шаблон , не закрывая Word . 11) Вызовите диалоговое окно “ Настройка ” , установите “ История.dot ” . Правой кнопкой мыши нажмите кнопку " Сохранить шаблон " - появится список с окошечком “ Имя ” . На этом окошечке щелкните левой кнопкой мыши - в окошечке появится курсор . Стерите курсором всё , что написано в окошечке , и клавиатурой вставьте в него большую букву “ Ш ” . Нажмите кнопку Enter на клавиатуре , затем мышью - кнопку Закрыть . Надпись новой кнопки состоит теперь только из одной буквы , и кнопка занимает гораздо меньше места . 12) Левой кнопкой мыши нажмите кнопку Ш . 13) Кнопками Alt F4 закройте Word , не сохраняя Документ1 . Выполнив урок 3 , Вы научились : 1) Скрывать и выводить на экран панель инструментов . 2) Вызывать диалоговое окно “ Настройка ” . 3) В этом диалоговом окне выбирать шаблон , в котором Вы хотите сохранить новые меню или панель инструментов или изменения в старых . 4) Создавать новую панель инструментов и перетаскивать её на нужное место . 5) Перетаскивать на панель инструментов команду и таким образом создавать новую кнопку . 6) Менять надпись на кнопке . 7) Сохранять шаблон , не закрывая Word . Следующий итог К оглавлению
Урок 4 Начинаем программировать
К оглавлению 1) Нажмите Alt F11 - откроется окно Редактора , в котором собственно и пишутся программы . 2) Если это окно занимает не весь экран , левой кнопкой мыши нажмите в нём кнопку рядом с косым крестиком в правом верхнем углу - это окно развернётся на весь экран . 3) В этом окне левой кнопкой мыши нажмите все косые крестики ( т.е. знаки умножить ) кроме крестика в правом верхнем углу ( конечно , если таковые имеются ) . 4) Нажмите Ctrl R - по левому боку окна Редактора откроется окно проекта . 5) В окне проекта левой кнопкой мыши нажмите все минусы , если таковые имеются , - окно проекта примет вид : + - - Normal + - - Project ( Документ1 ) + - - TemplateProject ( История ) . 6) Правой кнопкой мыши нажмите TemplateProject - откроется вертикальный списочек. 7) В этом списочке слова Свойства TemplateProject нажмите правой или левой кнопкой мыши - откроется диалоговое окно “ TemplateProject - свойства проекта ” . 8) В этом диалоговом окне левой кнопкой мыши нажмите Общие и в окошечке “ Имя проекта ” “ TemplateProject ” замените на латинскую букву A ( возможно , для этого придётся щёлкнуть на этом окошечке правой или левой кнопкой мыши ) . Левой кнопкой мыши нажмите ОК - “ TemplateProject ” переименуется в “ A ” . 9) Нажмите Alt F11 - окно Редактора закроется . 10) Левой кнопкой мыши нажмите Ш ( на панели “ История ” ) - изменения , которые Вы внесли в шаблон , будут сохранены . 11) Нажмите Alt F11 - окно Редактора откроется вновь . 12) На “ А(История) ” щёлкните правой кнопкой мыши - появится вертикальный списочек . Наведите мышь на “ Вставить ” и левой кнопкой мыши нажмите Модуль - появится модуль “ Модуль1 ” . 13) Левой кнопкой мыши выделите “ Модуль1 ” ( для этого наведите на это слово мышь и нажмите её левую кнопку ) . 14) Нажмите F4 - откроется окно свойств . 15) Если окно свойств закрывает больше четверти окна проекта , то на верхнюю границу окна свойств наведите мышь , нажмите левую кнопку мыши и , не отпуская её , перетащите границу вниз . 16) В окне свойств левой кнопкой мыши нажмите По алфавиту . 17) В этом же окне напротив “ (Name) ” левой кнопкой мыши щёлкните на слове “ Модуль1 ” и замените его на русскую букву А ( имя модуля не может совпадать с именем проекта ) , нажмите Enter - модуль будет переименован . 18) Нажмите Ctrl S - изменения , внесённые Вами в шаблон , будут сохранены . 19) Когда появился модуль , в окне Редактора появилось и окно кода ( правее окна проекта ) . В окне кода левой кнопкой мыши в правом верхнем углу нажмите кнопку рядом с крестиком - окно кода развернётся на всю незанятую часть окна Редактора . 20) Закройте окна свойств и проекта , левой кнопкой мыши нажимая на крестики . 21) Если в окне кода нет курсора , щёлкните в нём левой кнопкой мыши - курсор появится в левом верхнем углу . 22) В окне кода наберите текст : Sub Б ( Z ) Selection.TypeText Z End Sub Sub Проверка ( ) Б "Москва -- большой город ." End Sub 23) Сохраните История.dot , нажав Ctrl S . 24) Закройте окно Редактора , нажав Alt F11 . 25) Настройка Команды ( История.dot ) Макросы ( вызовите диалоговое окно “ Настройка ” , левой кнопкой мыши нажмите Команды , в нижнем окошечке установите “ История.dot ” , в окошечке “ Категории ” найдите и нажмите левой кнопкой мыши слово Макросы ) - в окошечке “ Команды ” появится текст “ А.А.Проверка ” . 26) Этот текст левой кнопкой мыши перетащите на панель “ История ” , отпустите кнопку мыши - на панели появится новая кнопка “ А.А.Проверка ” . Нажав её правой кнопкой мыши , измените её имя на “ Проверка ” и поставьте галочку напротив “ Начать группу ” . 27) В окне “ Настройка ” нажмите Закрыть . 28) Левой кнопкой мыши на панели “ История ” нажмите Ш . Изменяя шаблон , нужно его постоянно сохранять . Работая в окне Редактора , шаблон можно сохранять сочетанием клавиш Ctrl S . Когда окно редактора закрыто , сохраняйте шаблон кнопкой Ш . В дальнейшем я буду выпускать пункты о сохранении шаблона . 29) Несколько раз левой кнопкой мыши нажмите кнопку Проверка - сколько раз Вы нажмёте , столько появится фраз "Москва -- большой город ." . 30) Клавишами Alt F4 закройте Word , не сохраняя Документ1 . Вы создаёте шаблон , а не текстовый файл . Поэтому не сохраняйте текстовый файл , который автоматически создаётся при открытии шаблона двойным нажатием левой кнопкой мыши . Кроме того , я надеюсь , что Вы уже запомнили сочетание Alt F4 . Поэтому в дальнейшем я буду заканчивать урок фразой : “ Закройте Word ” . Выполнив урок 4 , Вы научились : 1) Открывать и закрывать окно Редактора , окно проекта и окно свойств . 2) Разворачивать окно Редактора и окно кода на весь экран . 3) Произвольно менять высоту окна свойств . 4) Переименовывать проект . 5) Создавать и переименовывать стандартный модуль . Мы выбрали однобуквенные имена для проекта и модуля в основном для того , чтобы в окошечке “ Команды ” диалогового окна “ Настройка ” были полностью видны длинные имена макросов . Кроме того , вероятно , мы немного сэкономим память , когда для макросов будем создавать кнопки на панелях или в меню , ( компьютеру необходимо запомнить , что такой-то кнопке соответствует такой-то макрос в таком-то модуле такого-то проекта ; чем короче имена модуля и проекта , тем меньше ему надо запоминать ) . 6) Вводить программный код в окно кода . 7) Создавать на панели кнопку , вызывающую макрос . Создать кнопку точно таким же образом можно не только на созданной панели ( называемой “ панелью пользователя ” ) , но и на любой встроенной панели ( например , на панели “ Форматирование ” ) . Однако встроенные панели лучше не изменять . Во-первых , чтобы пользователь Вашего шаблона не столкнулся с совершенно незнакомым ему интерфейсом . Во-вторых , в дальнейшем мы будем “ омолаживать ” наш шаблон , т.е. сокращать его размер , удаляя “ пустые ” байты путём копирования программного кода и панелей в “ чистый ” шаблон , а изменённую встроенную панель невозможно скопировать так просто как панель пользователя . 8) Отделять кнопку от другой кнопки ( “ Начать группу ” ) . Выполнив урок 4 , Вы написали две процедуры Sub ( процедуру Sub часто называют просто процедурой ) . Процедура Sub - это кусок программного кода между Sub и End Sub , включая Sub и End Sub , плюс , возможно , одно или два слова перед Sub в той же строке . Процедура Sub может иметь один или несколько аргументов ( как наша процедура “ Б ” ) или не иметь ни одного ( как наша процедура “ Проверка ” ) . Не имеющая ни одного аргумента процедура Sub называется макросом . Как процедура с аргументами , так и макрос могут быть вызваны другой или той же самой процедурой ( например , наша процедура “ Проверка ” вызывает процедуру “ Б ” ) . Однако кнопку создать можно только для макроса . Кроме процедур Sub в VBA имеются процедуры-функции и процедуры-свойства . Процедура Sub - основная “ клеточка ” программного кода : можно написать серьёзную , полезную , эффективную программу , используя только процедуры Sub . Кроме того , опыт показывает , что процедура Sub работает надёжнее процедуры-функции . Наша цель - создать шаблон , который бы автоматически писал проверочные по истории и обучал школьников истории в диалоговом режиме . Выполнив урок 4 , Вы научили компьютер автоматически писать текст , что необходимо для нашей цели . Обе созданные на последнем уроке процедуры мы будем использовать до конца работы : процедуру “ Б ” мы будем вызывать другими процедурами вместо написания длинного текста “ Selection.TypeText ” , а кнопкой и макросом “ Проверка ” тестировать новые процедуры , вызывая их вместо процедуры “ Б ” ( для этого нужно будет менять код внутри макроса ; как бы ни меняли мы код внутри макроса , созданная для него кнопка будет его вызывать, если имена проекта , модуля и макроса останутся теми же ) . Следующий итог К оглавлению
Урок 5 Встроенная функция Chr(n)
Выполнив настоящий урок , Вы научитесь открывать и закрывать окно кода и научите компьютер автоматически вставлять в текст тире ( вместо двух коротких дефисов ) и автоматически создавать новый абзац и новую строку . К оглавлению Чтобы понять разницу между новым абзацем и новой строкой , двойным нажатием левой кнопки мыши откройте История.dot и : 1) Клавиатурой наберите какое-нибудь слово , например “ Арбуз ” . 2) Нажмите Enter - таким образом Вы создадите новый абзац . Наберите какое-нибудь слово . 3) Нажмите кнопку Shift и , не отпуская её , Enter - таким образом Вы создадите новую строку ( иногда добавляют : “ без создания нового абзаца ” ) . Наберите какое-нибудь слово . 1) Нажмите Alt F11 - откроется окно Редактора ( надеясь , что Вы уже запомнили это сочетание клавиш , в дальнейшем буду просто писать : “ Откройте окно Редактора ” ) . Разверните это окно на весь экран , если оно ещё не развёрнуто . 2) Закройте окна свойств и проекта , если какое-нибудь из них открыто . 3) Если имеется окно кода и оно не развёрнуто на почти весь экран , то разверните его . 4) Если имеется развёрнутое окно кода , то в правом верхнем углу экрана - два крестика . Левой кнопкой мыши нажмите нижний - окно кода закроется ( если бы Вы нажали верхний крестик , то закрылось бы окно Редактора ) . 5) Нажмите Ctrl R - откроется окно проекта . 6) Левой кнопкой мыши нажимайте в нём на минусы , пока не останутся только плюсы . Этих плюсов останется три . Верхний плюс будет находиться напротив “ А(История) ” . 7) Левой кнопкой мыши нажмите верхний плюс - под “ А(История) ” появились по меньшей мере две новые строчки : Microsoft Word Объекты Модули . 8) Если напротив “ Модули ” стоит плюс , нажмите его левой кнопкой мыши - под “ Модули ” появится новая строчка “ А ” . 9) Левой кнопкой мыши дважды нажмите букву А под “ Модули ” - откроется окно кода с модулем “ А ” . Проект может иметь несколько модулей . Тогда каждый из этих модулей будет иметь свое окно кода . Кроме того , Normal.dot и текстовый файл тоже могут иметь модули . Каждый из этих модулей будет иметь своё окно кода . Надеюсь , что , выполнив пункты 5 … 9 , Вы поняли систему и сможете открыть окно кода любого из этих модулей ( или , иными словами , открыть любой из этих модулей ) . 10) Разверните окно кода , если оно ещё не развёрнуто . Закройте окно проекта . 11) Если Вам не привелось выполнить пункт 4 , выполните его сейчас и повторите пункты 5 … 10 ( для закрепления материала можете несколько раз выполнить пункты 4 … 10 ) . 12) Измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " & Chr ( 150 ) & " большой город ." End Sub 13) Несколько раз нажмите кнопку Проверка и посмотрите , что получится . Если два последних пункта Вы выполнили правильно , то Вы увидели , что вместо двух дефисов компьютер стал вставлять тире . 14) Левой кнопкой мыши нажмите Правка , Выделить всё и затем - кнопку Delete клавиатуры ( в дальнейшем я буду писать : “ Очистите текстовый файл ” ) . 15) Ещё раз измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " & Chr ( 150 ) & " большой город ." & Chr ( 13 ) End Sub Несколько раз нажмите кнопку Проверка и посмотрите , что получится . 16) Ещё раз измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " & Chr ( 150 ) & " большой город ." & Chr ( 11 ) End Sub 17) Ещё раз измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " & _ Chr ( 150 ) & " большой город ." _ & Chr ( 11 ) End Sub Несколько раз нажмите кнопку Проверка и посмотрите , что получится . Если Вы всё сделали правильно , то работа макроса не изменится . 18) Измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " & _ Chr ( 150 ) & " большой _ город ." _ & Chr ( 11 ) End Sub Текст макроса выделится красным цветом , и компьютер сообщит : “ Ошибка компиляции : Ожидалось : конец инструкции ” . Левой кнопкой мыши нажмите ОК и закройте окно Редактора . Нажмите Проверка - компьютер сообщит : “ Ошибка компиляции : Ошибка синтаксиса ” . 19) Левой кнопкой мыши нажмите ОК и верните код макроса “ Проверка ” к предыдущему состоянию . Если компьютер при этом спросит : “ Данная операция приведёт к сбросу проекта . Продолжить ? ” , то нажмите ОК . Если нет , то левой кнопкой мыши нажмите Запуск , Сброс . Закройте окно Редактора . 20) Несколько нажав Проверка , убедитесь , что макрос работает . Выполнив урок 5 , Вы научились : 1) Открывать и закрывать окно кода ( точнее - открывать и закрывать модуль ) . 2) Программировать вставку тире , символа нового абзаца и символа новой строки в автоматически создаваемый текст . 3) Длинную строку программного кода разбивать на несколько коротких . Это очень важное умение , так как позволяет представлять программы в читаемом виде ( некоторые программы могут иметь очень длинные строки ) . 4) Исправлять синтаксические ошибки программного кода . Следующий итог К оглавлению
Урок 6 ParamArray Рекурсия
В течение настоящего урока мы усовершенствуем процедуру “ Б ” , чтобы меньше приходилось использовать знак & и функцию Chr , что позволит нам в дальнейшем писать процедуры короче . К оглавлению 1) Измените процедуры “ Б ” и “ Проверка ” , чтобы они выглядели так : Sub Б ( ParamArray zТекстЧисло ( ) ) For k = 0 To UBound ( zТекстЧисло ) If k Mod 2 = 0 Then Selection.TypeText zТекстЧисло ( k ) Else Selection.TypeText Chr ( zТекстЧисло ( k ) ) End If Next k End Sub Sub Проверка ( ) Б "Москва " , 150 , " большой город ." , 11 End Sub Несколько раз нажав кнопку Проверка , убедитесь , что макрос работает . Две короткие наши процедуры демонстрируют сейчас сразу несколько возможностей VBA . Ключевое слово ParamArray значит , что процедура “ Б ” может иметь практически неограниченное число аргументов ( точнее - число аргументов , ограниченное только “ железом ” компьютера ) . Эти аргументы образуют массив zТекстЧисло , каждый элемент ( иначе говоря , член ) которого имеет индекс , или номер . Этот индекс пробегает значения с 0 по UBound ( zТекстЧисло ) ( Ubound - встроенная функция VBA , показывающая последний номер в массиве ) . Если , например , мы вызовем Б строчкой Б 1 , 2 , 3 , 4 , 5 , 6 , 7 , то zТекстЧисло ( 0 ) = 1 zТекстЧисло ( 1 ) = 2 zТекстЧисло ( 2 ) = 3 zТекстЧисло ( 3 ) = 4 zТекстЧисло ( 4 ) = 5 zТекстЧисло ( 5 ) = 6 zТекстЧисло ( 6 ) = 7 UBound ( zТекстЧисло ) = 6 . Запись For k = 0 To UBound ( zТекстЧисло ) . . . Next k называется циклом и значит , что переменная k пробегает все целые значения с 0 по UBound ( zТекстЧисло ) . При каждом таком значении k кусок программного кода между For k = 0 To UBound ( zТекстЧисло ) и Next k выполняется один раз ( таким образом , всего этот кусок выполняется UBound ( zТекстЧисло ) + 1 раз ) . При выходе из цикла переменная k будет равна UBound ( zТекстЧисло ) + 1 . Только что сказанное о числе раз выполнения и о значении счётчика цикла при выходе из цикла абсолютно верно для нашего цикла , - но может быть неверно для другого цикла , так как в VBA предусмотрены досрочный выход , изменение значения счётчика цикла внутри цикла , шаг отличный от единицы и другие возможности . k Mod 2 равняется остатку при делении k на 2 : 0 Mod 2 = 0 1 Mod 2 = 1 2 Mod 2 = 0 3 Mod 2 = 1 4 Mod 2 = 0 и т.д. . Условный оператор If Утверждение Then Код1 Else Код2 End If действует следующим образом : если Утверждение истинно , то выполняется Код1 ; если Утверждение ложно , то выполняется Код2 . Таким образом , если вызвать Б строкой Б Z0 , Z1 , Z2 , Z3 , Z4 , Z5 , Z6 , … , то сначала напечатается Z0 , потом Chr ( Z1 ) , потом Z2 , потом Chr ( Z3 ) и т.д. . 2) Измените процедуру Б , чтобы она выглядела так : Sub Б ( ParamArray zТекстЧисло ( ) ) For k = 0 To UBound ( zТекстЧисло ) If k Mod 2 = 0 Then Selection.TypeText zТекстЧисло ( k ) Else Б Chr ( zТекстЧисло ( k ) ) End If Next k End Sub Несколько раз нажав Проверка , убедитесь , что работа макроса не изменилась . Процедура Б теперь вызывает саму себя . Вызов процедурой себя самой непосредственно или через другие процедуры называется рекурсией . Наша процедура благодаря рекурсии сократилась не много . Однако некоторые процедуры с помощью рекурсии могут быть сокращены в несколько раз . Кроме того , иногда для выполнения определённой задачи трудно придумать алгоритм без рекурсии , в таком случае рекурсия становится практически необходимой . Рекурсия - очень мощное средство программирования . 3) Измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Б "Москва " , 150 , " большой город . Нью-Йорк " , 150 Б " тоже большой город . Арбуз " , 150 , " большая ягода . " End Sub Несколько раз нажмите Проверка и посмотрите , что получится . Можете переделать “ Проверка ” , заменив запятые на & , 150 - на Chr(150) , и посмотреть , насколько увеличится этот макрос . Выполнив урок 6 , Вы узнали программный код ( реализованный в процедуре Б ) , позволяющий в текстовый файл эффективно вводить программно любой текст . Кроме того , Вы узнали , что такое массив , ParamArray , mod , цикл , условный оператор и рекурсия . Следующий итог К оглавлению
Урок 7 Вставка номеров страниц
К оглавлению 1) Левой кнопкой мыши нажмите Вид , Разметка страницы . 2) Много раз нажмите Проверка , чтобы первая страница полностью заполнилась и в начале второй страницы было несколько строк . 3) Нажмите Вставка , Номера страниц - откроется диалоговое окно “ Номера страниц ” . 4) В этом диалоговом окне левой кнопкой мыши нажмите Формат - откроется диалоговое окно “ Формат номера страницы ” . 5) Установите : Формат номера 1,2,3,… Нумерация начать с : 1 Левой кнопкой мыши уберите галочку напротив “ Включить номер главы ” , если таковая имеется . 6) Нажмите ОК - окно “ Формат номера страницы ” закроется . 7) Установите : Положение Вверху страницы Выравнивание От центра Левой кнопкой мыши поставьте галочку напротив “ Номер на первой странице ” , если таковой ещё нет . 8) Нажмите ОК - окно “ Номера страниц ” закроется , а вверху как первой , так и второй страницы появится номер страницы . 9) Вставьте номера страниц Вверху страницы Слева и Вверху страницы Справа ; Внизу страницы От центра , Внизу страницы Слева и Внизу страницы Справа . Убедитесь , что вставленные номера страниц никак не повлияли на набранный текст . 10) Закройте Word и вновь откройте История.dot . 11) Нажмите Файл , Параметры страницы . Установите Поля Верхнее: 1,3 см Нижнее: 1,3 см . Нажмите ОК ( не нажимайте По умолчанию !!! ) . 12) Повторите пункты 2 … 9 и посмотрите , как вставка страниц изменяет текст . Выполнив урок 7 , Вы научились вставлять номера страниц и убедились , что в шаблоне История.dot верхнее и нижнее поля мы установили не случайно , а так , чтобы вставка номеров страниц не изменяла текст . Следующий итог К оглавлению
Урок 8 Select Case Глобальные переменные и массивы
К оглавлению 1) В модуль А введите новую процедуру : Sub Г ( zТипВопроса ) Б Chr ( 13 ) Selection.Font.Italic = False Select Case zТипВопроса Case 0 Б "В каком веке Москва вновь стала столицей России ?" Case 1 Б "Считается , что Иван Сусанин завёл в лес :" Case 2 Б "Основателями марксизма были :" End Select End Sub 2) Измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) Г 0 End Sub 3) Несколько раз нажмите Проверка и посмотрите , что получится . 4) В макросе “ Проверка ” замените 0 на 1 и повторите пункт 3 . 5) В макросе “ Проверка ” замените 1 на 2 и повторите пункт 3 . Оператор выбора Select case позволяет пронумеровать вопросы и затем вызывать их по номерам . Процедура Г - основная процедура нашего будущего шаблона . В дальнейшем мы напишем процедуры , вызывающие определённый набор вопросов в определённом порядке или как бы хаотично , “ навсегда ” ( чтобы распечатать вопросы на бумаге ) или на несколько секунд ( чтобы компьютер проверил знания ученика в диалоговом режиме ) . Однако пока мы сделали вопросы без ответов . Оставшуюся часть урока мы посвятим созданию ответов на каждый вопрос , причём вопросы будут печататься прямым шрифтом , а ответы к ним - курсивом . 6) В начало модуля А введите : Public G ( ) Public gПравильный Sub М ( zНомерПравильногоОтвета , ParamArray zОтветы ( ) ) gПравильный = zНомерПравильногоОтвета ReDim G ( 1 To UBound ( zОтветы ) + 1 ) For k = 0 To UBound ( zОтветы ) G ( k + 1 ) = zОтветы ( k ) Next k End Sub В начале модуля мы объявили глобальные ( доступные всем процедурам ) массив и переменную . Это можно сделать только в начале модуля , до процедур , ни одна процедура не может стоять раньше блока объявления глобальных переменных : это не признак “ хорошего ” программирования , а синтаксическое , обязательное требование VBA . В отличие от глобальных , переменная , появляющаяся в процедуре но не являющаяся её аргументом , никак не влияет на работу другой процедуры , даже если в той используется переменная с тем же именем . Нельзя двум процедурам одного модуля давать одинаковое имя . Нельзя , чтобы глобальная или локальная ( появляющаяся в процедуре ) переменная имела имя , совпадающее с именем процедуры в том же или другом модуле . Если глобальную переменную случайно использовать в качестве локальной , то её значение может измениться , что может непредсказуемо повлиять на работу других процедур . Поэтому важно отличать друг от друга имена локальных переменных , имена глобальных переменных и имена процедур . Для этого мы будем использовать простой принцип : имя процедуры всегда будем начинать с русской буквы ; имя глобальной переменной всегда будем начинать с латинской буквы g ; имя локальной переменной всегда будем начинать с любой другой латинской буквы , обычно с Z . Обратите внимание , что имя процедуры М должна образовывать не латинская , а русская буква М . 7) Измените процедуры Г и Проверка , чтобы они выглядели так : Sub Г ( zТипВопроса ) Б Chr ( 13 ) Selection.Font.Italic = False Select Case zТипВопроса Case 0 Б "В каком веке Москва вновь стала столицей России ?" М 3 , "в восемнадцатом" , "в девятнадцатом" , "в двадцатом" Case 1 Б "Считается , что Иван Сусанин завёл в лес :" М 3 , "французов" , "немцев" , "поляков" Case 2 Б "Основателями марксизма были :" М 1 , "Карл Маркс и Фридрих Энгельс" , "Фридрих Маркс и Карл Энгельс" End Select Б Chr ( 11 ) Selection.Font.Italic = True For k = 1 To UBound ( G ) Б k & " ) " Б G ( k ) , 11 Next k End Sub Sub Проверка ( ) Г 0 End Sub 8) Несколько раз нажмите Проверка и посмотрите , что получится . 9) В макросе Проверка замените 0 на 1 и повторите пункт 8 . 10) В макросе Проверка замените 1 на 2 и повторите пункт 8 . Выполнив урок 8 , Вы научились : 1) Использовать оператор выбора . 2) Объявлять глобальные переменные и массивы . 3) Программно устанавливать прямой и курсивный шрифт . Вы также узнали простой принцип , позволяющий отличать друг от друга имена глобальных переменных , имена локальных переменных , имена процедур , и зачем это нужно . Следующий итог К оглавлению
Урок 9 Timer Optional
Timer - встроенная переменная VBA , показывающая , сколько секунд прошло с полуночи . К оглавлению 1) В модуль А введите 2 новых процедуры : Sub Пауза ( Z ) zВремя = Timer sМетка : If Timer < zВремя + Z And Timer >= zВремя Then GoTo sМетка End Sub Sub УдалитьВсё ( ) Selection.WholeStory Selection.Delete 1 , 1 End Sub 2) Измените процедуру Г , чтобы она выглядела так : Sub Г ( zТипВопроса ) Б Chr ( 13 ) Selection.Font.Italic = False Select Case zТипВопроса Case 0 Б "В каком веке Москва вновь стала столицей России ?" М 3 , "в восемнадцатом" , "в девятнадцатом" , "в двадцатом" Case 1 Б "Считается , что Иван Сусанин завёл в лес :" М 3 , "французов" , "немцев" , "поляков" Case 2 Б "Основателями марксизма были :" М 1 , "Карл Маркс и Фридрих Энгельс" , "Фридрих Маркс и Карл Энгельс" End Select Б Chr ( 11 ) Selection.Font.Italic = True For k = 1 To UBound ( G ) Б k & " ) " Б G ( k ) , 11 Next k Пауза 2 УдалитьВсё End Sub 3) В процедуре Проверка замените 2 на 0 . 4) Нажмите Проверка и посмотрите , что получится . 5) В процедуре Проверка замените 0 на 1 и повторите пункт 4 . 6) В процедуре Проверка замените 1 на 2 и повторите пункт 4 . Вы сделали первый шаг к диалоговому режиму : научились выводить текст на экран на краткое время , а не “ навсегда ” . Однако мы хотим сохранить также и недиалоговый режим , пригодный для вывода вопросов на бумагу . 7) Первую строку процедуры Г Sub Г ( zТипВопроса ) замените на Sub Г ( zТипВопроса , Optional zНаВремя = False) В этой же процедуре Пауза 2 УдалитьВсё замените на If zНаВремя Then Пауза 2 УдалитьВсё End If 8) Нажмите Проверка и убедитесь , что текст выводится “ навсегда ” . 9) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 2 , True End Sub 10) Нажмите Проверка и убедитесь , что текст выводится на экран на краткое время . С помощью Optional мы ввели необязательный аргумент . Если перед именем аргумента нет Optional , то аргумент обязателен , т.е. при вызове процедуры обязательно нужно указывать его значение . В списке аргументов процедуры ( в первой строке кода процедуры , в скобках после имени процедуры ) необязательный аргумент не может стоять до обязательного . Каждому необязательному аргументу можно установить значение по умолчанию . Мы установили значение False ( ложь ) , противоположное значение - True ( истина ) . Однако по умолчанию можно устанавливать и другие значения ; например , 7 или “Сидней” . С помощью необязательных аргументов , мы можем расширять возможности , гибкость процедуры , не меняя её работы в тех процедурах , которые её уже вызывают . Слова ParamArray и Optional не совместимы , т.е. если в первой строке кода процедуры перед именем массива аргументов стоит ParamArray , то перед этим именем ( ни до , ни после ParamArray ) не может стоять Optional . Таким образом , массив , введённый словом ParamArray , всегда является обязательным аргументом ( в дальнейшем аргументом я буду называть как одиночную переменную , так и массив ) . С другой стороны , ParamArray может стоять только перед последним аргументом процедуры , а обязательный аргумент не может стоять после необязательного . Поэтому , если в списке аргументов процедуры используется ParamArray , то использовать в нём Optional нельзя . Выполнив урок 9 , Вы узнали : 1) 2 очень важных кода - код паузы и код очищения файла . 2) Оператор безусловного перехода GoTo . GoTo отсылает действие процедуры к метке , которая должна быть в той же процедуре . Меткой может быть не только “sМетка” , но и любой набор букв и цифр ; например , “начало” , “Конец” , “0” , “1” , “Метка1” , “Метка2” . Чтобы имя метки случайно не совпало с именем процедуры или переменной , мы будем начинать его всегда с цифры или S ( большой или малой ) . 3) Что условный оператор можно записывать в одну строку . 4) Слово Optional и зачем оно нужно . Следующий итог К оглавлению
Урок 10 InputBox MsgBox
В течение настоящего урока мы предоставим пользователю возможность выбирать правильный ответ и получать от компьютера информацию , правильно ли он , пользователь , ответил . К оглавлению 1) В начале модуля А Public G ( ) Public gПравильный замените на Public G ( ) Public gПравильный Public Const Аб = vbCrLf & " " Public Const Сб2 = vbCrLf & Аб & "Чтобы убрать настоящую справку с экрана ," _ & vbCrLf & "нажмите кнопку ОК настоящей справки или" _ & vbCrLf & "кнопку ""Пробел"" , Esc или Enter клавиатуры ." Сейчас с помощью слов Pablic Const мы ввели две глобальные ( доступные каждой процедуре ) константы - Аб и Сб2 . В отличие от переменной , значение константы не может быть изменено . Чтобы отличать константы от переменных и меток , имя константы всегда будем составлять только из русских букв и цифр ( VBA требует , чтобы имя константы начиналось с буквы , а не с цифры ) . Чтобы имя процедуры случайно не совпало с именем константы , мы ограничимся малым числом типов имён констант . Мы ввели константы с “ говорящими ” именами : Аб - сокращение от “ Абзац ” , Сб2 - от “ Сообщение 2 ” ( в именах констант , переменных , меток и процедур следует избегать цифры 0 , 1 , 3 , 6 , так как 0 похожа на латинскую и русскую О , 1 - на латинскую l , 3 - на З , 6 - на б ) . 2) В процедуре Г If zНаВремя Then Пауза 2 УдалитьВсё End If замените на If zНаВремя Then Пауза 2 УдалитьВсё zЗг = " Номер верного ответа" zСб = "Введите цифру с 1 по 9 и нажмите ОК ." Select Case InputBox(zСб, zЗг, 0) Case Empty Case gПравильный MsgBox "Ответ верен . Поздравляем Вас !" & Сб2 Case Else MsgBox "Ответ неверен ." & Сб2 End Select End If 3) Нажмите Проверка и посмотрите , что получится . InputBox - встроенная функция VBA , которая : во-первых , выводит на экран диалоговое окно с двумя кнопками - ОК и Отмена - и окошечком для ввода текста ; во-вторых , принимает значение , зависящее от того , какую кнопку - ОК или Отмена - нажал пользователь , и от того , что было в окошечке , когда пользователь нажал ОК . Если пользователь нажал Отмена , то InputBox принимает значение Empty , независимо от того что стояло в окошечке . Если пользователь нажал ОК , то InputBox принимает значение равное тому , что стояло в окошечке . В окошечко можно вводить не только одну цифру , но и любой текст - например , “201” , “01” , “Арбуз” , “москва” , “Архангельск” , “78?*\5%;” и т.д. ; InputBox примет любое из этих значений . InputBox имеет один обязательный и шесть необязательных аргументов . Первый , обязательный аргумент - prompt , сообщение , выводимое под заголовком ( в нашем случае - "Введите цифру с 1 по 9 и нажмите ОК ." ) . Второй , необязательный аргумент - title , заголовок . Третий , необязательный аргумент - default , текст , появляющийся в окошечке при вызове InputBox до того , как пользователь введёт свой текст . Если пользователь нажмёт ОК не вводя своего текста , то InputBox примет значение равное default . Default разумно использовать в качестве образца , или подсказки , для пользователя . Если при вызове InputBox default не указан , то окошечко будет пустым . Если при вызове InputBox не указан title , то заголовком будут слова “Microsoft Word” . Осталось ещё 4 необязательных аргумента , которыми , при первом знакомстве с VBA , лучше не забивать голову . Выполнив урок 10 , Вы узнали : 1) Как вводить глобальные константы . 2) InputBox . 3) MsgBox . 4) Что в операторе выбора можно использовать “ пустой ” Case ( у нас после Case Empty сразу идёт Case gПравильный , т.е. если InputBox равна Empty , то оператор выбора ничего не делает ) . 5) Что в операторе выбора можно использовать строку Case Else и зачем она нужна . На последнем уроке мы организовали настоящий диалог между пользователем и компьютером , начинает просматриваться окончательный вариант нашего шаблона , наша конечная цель близка !!! Сколько дней Вы занимаетесь VBA ? 10 , 7 , 5 ? А уже можете писать вполне приличные программы . Следующий итог К оглавлению
Урок 11 Каждому вопросу - свою паузу Полноэкранный режим
Вопросы , временно выводимые на экран , могут быть различны по размеру . Поэтому может требоваться разное время для их прочтения . Мы же пока каждый вопрос выводим на одно и то же время ( 2 секунды ) . К оглавлению 1) В модуле А строку Public gПравильный замените на Public gПравильный, gПауза 2) В модуль А введите новую процедуру Sub П ( zПауза ) gПауза = zПауза End Sub 3) В процедуре Г Select Case zТипВопроса Case 0 Б "В каком веке Москва вновь стала столицей России ?" М 3 , "в восемнадцатом" , "в девятнадцатом" , "в двадцатом" Case 1 Б "Считается , что Иван Сусанин завёл в лес :" М 3 , "французов" , "немцев" , "поляков" Case 2 Б "Основателями марксизма были :" М 1 , "Карл Маркс и Фридрих Энгельс" , "Фридрих Маркс и Карл Энгельс" End Select замените на Select Case zТипВопроса Case 0 Б "В каком веке Москва вновь стала столицей России ?" М 3 , "в восемнадцатом" , "в девятнадцатом" , "в двадцатом" П 2 Case 1 Б "Считается , что Иван Сусанин завёл в лес :" М 3 , "французов" , "немцев" , "поляков" П 2 Case 2 Б "Основателями марксизма были :" М 1 , "Карл Маркс и Фридрих Энгельс" , "Фридрих Маркс и Карл Энгельс" П 2 Case 3 Б "Индия была колонией :" М 4 , "Франции" , "Германии" , "России" , "Англии" , "Испании" , _ "Италии" , "Швеции" П 7 End Select 4) В процедуре Г строку Пауза 2 замените на Пауза gПауза 5) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 3 , True End Sub 6) Нажмите Проверка и посмотрите , что получится , ( засеките время , на которое на экране появляется вопрос ) . 7) В макросе Проверка 3 замените на 2 и повторите пункт 6 . Сейчас мы оператор Select Case zТипВопроса процедуры Г привели практически к окончательному виду . В дальнейшем мы будем добавлять только “ новые случаи ” , т.е. четвёрки строк : Case ZZ Б “Текст” М m , “Текст_1” , “Текст_2” , … , “Текст_n” П N Мы вплотную подошли к проблеме того , что большой вопрос может не уместиться на экране . Более полно использовать место на экране позволяет полноэкранный режим . 8) Левой кнопкой мыши нажмите Вид , Во весь экран - Вы перейдёте в полноэкранный режим . 9) Наведите мышь на самый верх экрана - появится головное меню . Этим меню Вы можете пользоваться как обычно . Например , опять нажмите Вид , Во весь экран - Вы вернётесь в обычный режим . 10) Вернитесь в полноэкранный режим и левой кнопкой мыши нажмите Вернуть обычный режим - Вы вторым способом вернётесь в обычный режим . Кнопка Вернуть обычный режим находится на панели “ Во весь экран ” . 11) Вернитесь в полноэкранный режим . С помощью правой кнопки выведите на экран и уберите с него какую-нибудь панель инструментов ( например , История ) . Попытайтесь убрать все панели - Вы убедитесь , что панель “ Во весь экран ” просто убрать нельзя . 12) Выведите на экран панель “ История ” и нажмите Проверка - макрос сработает как обычно . 13) Вызовите диалоговое окно “ Настройка ” , нажмите Команды , установите История.dot . 14) На клавиатуре нажмите кнопку Ctrl и , не отпуская её , левой кнопкой мыши перетащите Вернуть обычный режим с панели “ Во весь экран ” на панель “ История ” - кнопка будет скопирована ( “ раздвоится ” ) , а не перемещена . 15) Закройте окно “ Настройка ” и несколько раз нажмите Вернуть обычный режим на панели “ История ” . Остановитесь на полноэкранном режиме . 16) Измените макрос “ Проверка ” , чтобы он выглядел так : Sub Проверка ( ) On Error Resume Next For Each k In CommandBars k.Visible = False Next k CommandBars ( "История" ).Visible = True End Sub 17) Нажмите Проверка - панель “ Во весь экран ” исчезнет и на экране останется только панель “ История ” . CommandBars - множество всех панелей нашего шаблона . Visible - свойство каждой панели ( т.е. свойство каждого элемента CommandBars ) : когда Visible равно True , панель видна на экране , а когда Visible равно False , панель скрыта , т.е. не видна . Работа цикла For Each k In N тело цикла Next k заключается в том , что для каждого элемента k множества N выполняется тело цикла . Таким образом , цикл For Each k In CommandBars k.Visible = False Next k скрывает все панели нашего шаблона . Строка CommandBars("История").Visible = True делает вновь видимой панель “ История ” . On Error Resume Next приводит к тому , что если какой-нибудь оператор ( т.е. действие ) программного кода не может быть выполнен , то компьютер автоматически переходит к выполнению следующего оператора . Если эту строку убрать из “ Проверка ” и нажать Проверка , то компьютер выдаст малопонятное сообщение об ошибке ( видимо , потому , что панель головного меню не может быть скрыта ) . Выполнив урок 11 , Вы узнали : 1) Полноэкранный режим . 2) Как копировать кнопку с панели на панель . 3) Как программно выводить на экран и убирать с него панель инстументов . 4) Цикл For Each k In N . 5) On Error Resume Next . Следующий итог К оглавлению
Урок 12 ThisDocument
Хотелось бы , чтобы компьютер автоматически переходил в полноэкранный режим при каждом открытии История.dot . К оглавлению 1) В модуль А введите новый макрос Sub Я ( ) On Error Resume Next ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True End Sub 2) Откройте окно проекта . 3) Двойным нажатием левой кнопки мыши откройте ThisDocument проекта “ А ( История ) ” ( если ThisDocument не виден в окне проекта , нажмите плюс напротив “ Microsoft Word Объекты ” ) . 4) В ThisDocument введите макрос Private Sub Document_New ( ) А.Я End Sub Private Sub Document_New() , расположенный в ThisDocument , - макрос , который автоматически выполняется при создании каждого нового текстового файла , в частности при открытии шаблона двойным нажатием левой кнопки мыши . 5) Закройте Word и вновь откройте История.dot - компьютер автоматически перейдёт в полноэкранный режим , выведет на экран панель “ История ” и скроет все остальные панели . 6) Выведите на экран несколько панелей и скройте панель “ История ” . Закройте Word и вновь откройте История.dot . 7) Перейдите в обычный ( неполноэкранный ) режим . Выведите на экран несколько панелей и скройте панель “ История ” . Закройте Word и вновь откройте История.dot . Строка ActiveWindow.View.FullScreen = True переводит компьютер в полноэкранный режим , а строка ActiveWindow.View.FullScreen = False в обычный ( неполноэкранный ) . На первый взгляд , строка ActiveWindow.View.FullScreen = False лишняя . Однако проведём эксперимент , используя оператор комментария . Оператор комментария - это апостроф ( ' ) ; всё , стоящее в строке командного кода после него , VBA игнорирует . 8) В начале строки ActiveWindow.View.FullScreen = False макроса Я поставьте апостроф , чтобы она выглядела так : ' ActiveWindow.View.FullScreen = False ( этим Вы как бы удалите её из программного кода ) . 9) Несколько раз закройте Word и вновь откройте История.dot - Вы увидите , что панель “ История ” скрывается головным меню . Уберите апостроф из макроса Я . 10) Установите курсор на начало строки On Error Resume Next макроса Я . 11) На клавиатуре нажмите Shift и , не отпуская её , нажимайте стрелку вниз ( без цифры ) , пока не выделится On Error Resume Next ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True 12) На клавиатуре нажмите Ctrl C - выделенный текст будет скопирован в “ буфер ” . Если выделенный текст исчез , то , скорее всего , Вы нажали не Ctrl C , а Ctrl X ( X - латинская ) , и выделенный текст был не скопирован , а “ вырезан ” в буфер . Нажмите Ctrl V - выделенный текст появится снова . 13) На клавиатуре нажмите какую-нибудь стрелку без цифры : стрелку влево , стрелку вправо , стрелку вверх или стрелку вниз - выделение снимется . 14) Откройте ThisDocument , установите курсор перед А.Я , на клавиатуре нажмите Home - курсор переместится в самое начало строки , на клавиатуре нажмите Shift End - вся строка выделится . 15) На клавиатуре нажмите Ctrl V - выделенная строка заменится на On Error Resume Next ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True Если перед End Sub появилась пустая строка ( курсор при этом будет в начале этой пустой строки ) , то на клавиатуре нажмите Delete - пустая строка исчезнет . 16) Повторите пункты 6 , 7 и посмотрите , что получится . Вы обнаружите , что при открытии История.dot компьютер не переходит в полноэкранный режим . Следовательно , строка ActiveWindow.View.FullScreen = True не выполняется ( возможно , не выполняется также и предыдущая строка ) . 17) Макрос Private Sub Document_New ( ) верните к первоначальному виду Private Sub Document_New ( ) А.Я End Sub Выполнив урок 12 , Вы узнали : 1) Модуль ThisDocument Макрос Private Sub Document_New ( ) 2) Как вызвать процедуру , находящуюся в другом модуле , ( для этого нужно набрать имя модуля , поставить точку и набрать имя процедуры ; при этом нельзя делать никаких пропусков , ни перед точкой , ни после неё ) . 3) Как программно переходить в полноэкранный режим и возвращаться в обычный . 4) Оператор комментария . 5) Как копировать программный код из одной процедуры в другую . 6) Что в модуле ThisDocument выполняются не все операторы ( чтобы компьютер смог их выполнить , надо написать процедуру , их содержащую , в стандартном модуле и затем вызвать эту процедуру в ThisDocument ) . Следующий итог К оглавлению
Урок 13 Ctrl Pause Break
К оглавлению 1) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) MsgBox " Выполнение вызванного Вами макроса может занять " & _ "слишком много времени ." & Аб & _ "Вы можете в любой момент прервать его работу . Для этого" & _ " достаточно нажать кнопку" & _ " ""Ctrl"" и , не отпуская её , кнопку ""Pause Break"" ." & Сб2 End Sub 2) Нажмите Проверка - появится справка , внимательно прочтите её . Левой кнопкой мыши нажмите ОК на справке - макрос “ Проверка ” будет полностью выполнен . 3) Вновь нажмите Проверка - появится уже знакомая Вам справка . На клавиатуре нажмите Ctrl Pause Break - появится справка с кнопками Продолжить , Завершить , Отладка , Справка . Левой кнопкой мыши нажмите Завершить - выполнение макроса будет кончено досрочно . Сейчас Вы просто потренировались досрочно кончать выполнение макроса , но в дальнейшем ( в том числе на настоящем уроке ) мы действительно будем писать макросы , каждый из которых для своего полного выполнения будет требовать нескольких минут или даже десятков минут , тогда Вам в самом деле может потребоваться досрочно кончить выполнение макроса . 4) В оператор Select Case zТипВопроса процедуры Г добавьте новые случаи : Case 4 Б "Первым русским царём был :" М 2 , "Владимир Мономах" , "Иван Грозный" , "Пётр Первый" П 3 Case 5 Б "Крестоносцев победил :" М 1 , "Александр Невский" , "Александр Македонский" , _ "Александр Третий" П 3 Case 6 Б "Ермак покорил Сибирь при :" М 2 , "Ярославе Мудром" , "Иване Грозном" , _ "Петре Первом" , "Николае Первом" П 3 Case 7 Б "Кроме Москвы , столицей России был :" М 3 , "Великий Новгород" , "Нижний Новгород" , _ "Санкт-Петербург" П 3 Case 8 Б "На месте столицы Римской империи " & _ "в настоящее время расположен :" М 3 , "город Москва" , "Париж" , "Рим" , _ "Константинополь" , "Стамбул" П 5 Case 9 Б "Фамилия последнего российского царя :" М 1 , "Романов" , "Рюрикович" , "Менделеев" П 4 Case 10 Б "Настоящая фамилия Сталина :" М 2 , "Осташвили" , "Джугашвили" , "Ульянов" П 3 Case 11 Б "В начале ХХ века великороссами звали :" М 1 , "русских" , "белоруссов" , "украинцев" П 3 Case 12 Б "Киев основан :" М 1 , "раньше Москвы" , "позже Москвы" П 2 Case 13 Б "Императрицу " , 150 , _ " дочь Петра Первого звали :" М 3 , "Анна" , "Екатерина" , "Елизавета" П 2 Case 14 Б "В каком году началась первая " & _ "( не Великая ) Отечественная Война России ?" М 3 , "в 1712" , "в 1749" , "в 1812" , "в 1858" П 3 Case 15 Б "В состав СССР никогда не входила :" М 3 , "Молдавия" , "Эстония" , "Монголия" П 4 Case 16 Б "Первым космонавтом был :" М 1 , "Юрий Гагарин" , "Герман Гагарин" , _ "Юрий Титов" , "Герман Титов" П 5 Case 17 Б "Первый искусственный спутник Земли" & _ " был запущен с космодрома :" М 1 , """Байконур""" , """Плесецк""" , """Кеннеди-центр""" П 5 Case 18 Б "Первым космическим туристом ( заплатившим" & _ " деньги за полёт в космос ) был :" М 1 , "Денис Тито" , "Денис Титов" , "Герман Титов" П 5 Case 19 Б "12 апреля :" М 2 , _ "был запущен первый искусственный спутник Земли" , _ "человек впервые облетел Землю вне атмосферы" , _ "люди впервые высадились на Луне" П 9 Case 20 Б "Первым американским космонавтом был :" М 3, "Джон Кеннеди", "Пол Маккартни", "Джон Гленн" П 5 5) Процедуру Проверка измените , чтобы она выглядела так : Sub Проверка ( ) MsgBox " Выполнение вызванного Вами макроса может занять " & _ "слишком много времени ." & Аб & _ "Вы можете в любой момент прервать его работу . Для этого" & _ " достаточно нажать кнопку" & _ " ""Ctrl"" и , не отпуская её , кнопку ""Pause Break"" ." & Сб2 Г 12 , True : Г 0 , True : Г 7 , True For k = 16 To 20 Г k , True Next k End Sub В строке Г 12 , True : Г 0 , True : Г 7 , True мы вызвали друг за другом три процедуры . Вызвать несколько процедур в одной строке можно следующим образом : □ ввести имя первой процедуры ; □ ввести пробел ; □ через запятые ввести значения параметров ; □ ввести “: ” ( двоеточие и пробел ) ; □ ввести имя второй процедуры и т.д. ( после значений параметров последней процедуры вводить “: ” нельзя ) . Процедура ( с параметрами или без ) - частный случай оператора . В одной строке ( через двоеточие ) можно вызвать несколько не только процедур , но и операторов некоторых других типов . 6) Нажмите Проверка и посмотрите , что получится . 7) В процедуре Г четвёртую с конца строку MsgBox "Ответ неверен ." & Сб2 замените на MsgBox "Ответ неверен . Повторите попытку ." & Сб2 Г zТипВопроса , True Сейчас мы второй раз использовали рекурсию ( впервые мы использовали её в процедуре Б ) . 8) Нажмите Проверка , на некоторые вопросы специально ответьте неправильно и посмотрите , что получится . 9) В начале модуля А строку Public gПравильный , gПауза замените на Public gПравильный , gПауза , gВерных , gНеверных 10) В конце процедуры Г Case gПравильный MsgBox "Ответ верен . Поздравляем Вас !" & Сб2 Case Else MsgBox "Ответ неверен . Повторите попытку ." & Сб2 Г zТипВопроса , True замените на Case gПравильный gВерных = gВерных + 1 MsgBox "Ответ верен . Поздравляем Вас !" & Сб2 , , _ "Верных ответов " & gВерных & " Неверных " & gНеверных Case Else gНеверных = gНеверных + 1 MsgBox "Ответ неверен . Повторите попытку ." & Сб2 , , _ "Верных ответов " & gВерных & " Неверных " & gНеверных Г zТипВопроса , True Сейчас в оператор MsgBox мы ввели третий аргумент “ Title ” - заголовок . 11) В макросе Проверка Sub Проверка ( ) замените на Sub Проверка ( ) gВерных = 0 : gНеверных = 0 Сейчас мы мы два оператора ( причём не процедуры ) записали в одну строку через двоеточие . 12) В макросе Проверка End Sub замените на MsgBox " Конец" & Аб & "Верных ответов " & _ gВерных & Аб & "Неверных ответов " & gНеверных & Сб2 End Sub 13) Нажмите Проверка и посмотрите , что получится . Выполнив урок 13 , Вы: 1) Научились досрочно кончать работу макроса . 2) В оператор Select Case zТипВопроса процедуры Г добавили новых случаев достаточно , чтобы продемонстрировать работу некоторых процедур . 3) Научились в одной строке вызывать несколько операторов . 4) Вспомнили , что такое рекурсия , и узнали пример её эффективного применения . 5) Научились справке MsgBox давать Ваш заголовок . 6) Написали вполне приличную обучающую программу . Хотя конечный результат нашей работы просматривается все яснее , это ещё не конец . Вы узнаете ещё несколько важных приёмов работы в VBA . Следующий итог К оглавлению
Задача 1 Число пропущенных вопросов
Выделите ещё одну дискету , на которой Вы сохраните результаты Вашей сегодняшней самостоятельной работы . Не заглядывая на следующую страницу , попытайтесь изменить шаблон так , чтобы в промежуточных и конечной справках давалось число не только верных и неверных ответов , но и число пропущенных вопросов ( вопрос пропускается , если пользователь нажимает Отмена ) . Ответ К оглавлению
Урок 14 ByVal , ByRef
Наш черновик обучающей программы плох тем , что в каждом вопросе ответы всегда идут в одном и том же порядке . Ученик может запомнить номера правильных ответов , не обращая внимания на содержание ответов . На настоящем уроке мы научим компьютер как бы случайно менять порядок следования ответов . К оглавлению 1) В модуль А введите новую процедуру : Sub Обмен ( Z2 , Z4 ) Z = Z2 Z2 = Z4 Z4 = Z End Sub 2) В процедуре Г первую строку Sub Г ( zТипВопроса , Optional zНаВремя = False ) замените на Sub Г ( zТипВопроса , Optional zНаВремя = False , _ Optional ByVal ZсКакимМенятьВерныйОтвет = 0 ) 3) В той же процедуре Г Б Chr ( 11 ) Selection.Font.Italic = True For k = 1 To UBound ( G ) Б k & " ) " Б G ( k ) , 11 Next k замените на ZсКакимМенятьВерныйОтвет = ZсКакимМенятьВерныйОтвет Mod ( UBound ( G ) + 1 ) If ZсКакимМенятьВерныйОтвет > 0 Then Обмен G ( gПравильный ) , G ( ZсКакимМенятьВерныйОтвет ) gПравильный = ZсКакимМенятьВерныйОтвет End If Б Chr ( 11 ) Selection.Font.Italic = True For k = 1 To UBound ( G ) Б k & " ) " Б G ( k ) , 11 Next k 4) В конце той же процедуры Г Справка2 "Ответ неверен . Повторите попытку ." Г zТипВопроса , True замените на Справка2 "Ответ неверен . Повторите попытку ." Г zТипВопроса , True , Timer 5) В процедуре Проверка Г 12 , True : Г 0 , True : Г 7 , True For k = 16 To 20 Г k , True Next k замените на Г 12 , True , Timer Г 0 , True , Timer Г 7 , True , Timer For k = 16 To 20 Г k , True , Timer Next k 6) Нажмите Проверка и запишите номера верных ответов . 7) Повторите пункт 6 - номера верных ответов будут другими . В пункте 2 мы в заголовок процедуры Г ввели слово ByVal , которое приводит к тому , что для вводимой за ним переменной ( в данном случае - ZсКакимМенятьВерныйОтвет ) при вызове процедуры создаётся копия , которая исчезает по окончании работы процедуры и никак не может повлиять на значение переменной , для которой эта копия создаётся . Слово , альтернативное ByVal , - ByRef ( в VBA оно даётся по умолчанию , т.е. если не вводится ни то , ни другое слово , то VBA считает , что введено ByRef ) . Переменную , вводимую за ByVal , называют переменной ByVal ; переменную , вводимую за ByRef , - переменной ByRef . В отличие от переменной ByVal , для переменной ByRef копия не создаётся . Иными словами , значение переменной ByRef процедура может изменить , а значение переменной ByVal - нет . Строка Г k , True , Timer не может изменить значение переменной Timer , так как третий аргумент процедуры Г - переменная ByVal . А вот строка Обмен G ( gПравильный ) , G ( ZсКакимМенятьВерныйОтвет ) может изменить значения как G ( gПравильный ) , так и G ( ZсКакимМенятьВерныйОтвет ) , так как оба аргумента процедуры Обмен - переменные ByRef . Если при вызове процедуры на месте аргумента ByRef стоит константа или выражение , включающее в себя несколько переменных , то эту константу или это выражение VBA всё равно считает переменной ByVal . Если в теле процедуры значение аргумента не меняется , то , как правило , всё равно , с каким ключом - ByVal или ByRef - вводится этот аргумент . Чтобы сократить код с помощью неуказания ключа ByVal или ByRef , учитывайте два предыдущих абзаца , а также то , что ByRef - ключ по умолчанию , ( это значит , что ByRef можно выпускать всегда ) . Выполнив урок 14 , Вы узнали : 1) Простой , но важный код , при выполнении которого две переменные меняются значениями . 2) ByVal и ByRef . Чётко понимать всё связанное с этими ключами очень важно . Часто программа работает неправильно потому , что программист забывает , что значение переменной ByRef может быть изменено процедурой . Следующий итог К оглавлению
Урок 15 Циклы Дробная и целая части
К оглавлению 1) Макрос Проверка переименуйте в Проверка2 , т.е. строку Sub Проверка ( ) замените на Sub Проверка2 ( ) 2) В модуль А введите новый макрос Sub Проверка ( ) For k = 1 To 8 Б k & " " Next k Б Chr ( 11 ) End Sub 3) Нажмите Проверка и посмотрите , что получится . 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) For k = 8 To 1 Б k & " " Next k Б Chr ( 11 ) End Sub 5) Нажмите Проверка и посмотрите , что получится . 6) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) For k = 8 To 1 Step -1 Б k & " " Next k Б Chr ( 11 ) End Sub 7) Нажмите Проверка и посмотрите , что получится . Значение параметра Step называется шагом . В VBA , как и во многих других языках , шагом по умолчанию является число 1 . 8) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 8 Б Z & " ) " While Z Mod 2 = 0 Б Z & " " Z = Z \ 2 Wend Б Chr ( 11 ) End Sub 9) Нажмите Проверка и посмотрите , что получится . 10) В макросе Проверка строку Z = 8 замените на Z = 9 и повторите пункт 9 . 11) В макросе Проверка строку Z = 9 замените на Z = 10 и повторите пункт 9 . 12) В макросе Проверка строку Z = 10 замените на Z = 11 и повторите пункт 9 . 13) В макросе Проверка строку Z = 11 замените на Z = 12 и повторите пункт 9 . 14) В макросе Проверка строку Z = 12 замените на Z = 42 и повторите пункт 9 . 15) В макросе Проверка строку Z = 42 замените на Z = 48 и повторите пункт 9 . Знак \ - знак целочисленного деления . Кроме знака целочисленного деления в VBA есть также знак “ простого ” ( обычного ) деления ( / ) . Если n и k - целые числа , и n без остатка делится на k , то n \ k даст тот же результат , что и n / k , но выполнено будет быстрее . Цикл While условие тело цикла Wend равносилен коду sМетка: If условие Then тело цикла GoTo sМетка End If и действует следующим образом : а ) Вначале проверяется истинность условия . б ) Если условие ложно , то выполняется строка кода , следующая за Wend . Если условие истинно , то выполняется тело цикла и компьютер возвращается к пункту а . Наш цикл While Z Mod 2 = 0 Б Z & " " Z = Z \ 2 Wend действует следующим образом : □ Вначале проверяется , чётно ли число Z . □ Если нечётно , то выполняется строка кода , следующая за Wend , ( вставляется символ создания новой строки ) . □ Если чётно , то сначала печатается Z , затем Z делится на 2 и наконец проверяется , чётно ли новое значение Z . 16) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 123.987 Б Z & " ) " & Int ( Z ) & " " & Z - Int ( Z ) , 11 End Sub 17) Нажмите Проверка и посмотрите , что получится . 18) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Dim Cr As Currency Z = 123.987 Cr = Z Б Z & " ) " & Int ( Cr ) & " " & Cr - Int ( Cr ) , 11 End Sub 19) Нажмите Проверка и посмотрите , что получится . Int - встроенная функция VBA ; Int ( аргумент ) равняется целой части аргумента , и , следовательно , аргумент - Int ( аргумент ) равняется дробной части аргумента . Выполнив пункты 16 и 17 , Вы убедились , что дробная часть не всегда вычисляется точно . Однако компьютер можно заставить точно вычислить дробную часть , придав аргументу тип Currency . В последнем варианте макроса Проверка , строка Dim Cr As Currency объявляет переменную Cr типа Currency ( необъявленные переменные , как правило , имеют тип Variant ) , затем переменная Z типа Variant принимает значение 123,987 ( в VBA десятичным знаком является не запятая , а точка ) , затем это значение принимает переменная Cr типа Currency , наконец вычисляются и печатаются целая и дробная части этого значения . Таким образом , чтобы точно вычислить дробную часть переменной типа Variant , надо значение этой переменной присвоить переменной типа Currency и только потом вычислять дробную часть . Знать это очень важно , так как с помощью ключа ParamArray можно вводить массив переменных только типа Variant . Десятичной дробью можно задать 2 целых числа ( одно - целой частью , другое - дробной ) и , следовательно , диапазон целых чисел с одного по другое ( например , дробью 7,2 можно задать набор 7 ; 6 ; 5 ; 4 ; 3 ; 2 ) . Делать это мы и научимся сейчас . 20) Прежде всего заметим , что строка Dim Cr As Currency почти ничего не делает , но занимает место . Однако в VBA тип переменной можно задать не только длинным оператором , но и приставив к концу имени переменной , при её первом упоминании в коде , специальный ( не букву и не цифру ) символ . В частности , тип Currency можно задать , приставив @ . Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 123.987 Cr@ = Z Б Z & " ) " & Int ( Cr ) & " " & Cr - Int ( Cr ) , 11 End Sub 21) Нажмите Проверка и посмотрите , что получится . Обратите внимание , что знак @ мы употребили лишь однажды . Таким образом , @ - не часть имени переменной , хотя пишется слитно с этим именем ( между именем и @ не должно быть ни одного пробела ) . 22) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 123.987 Cr@ = Z k2 = Int ( Cr ) k4 = Cr - k2 While k4 - Int ( k4 ) > 0 k4 = 10 * k4 Wend Б Z & " ) " & k2 & " " & k4, 11 End Sub 23) Нажмите Проверка и посмотрите , что получится . 24) В макросе Проверка строку Z = 123.987 замените на Z = 23.98 и повторите пункт 23 . 25) В макросе Проверка строку Z = 23.98 замените на Z = 230.98 и повторите пункт 23 . 26) В макросе Проверка строку Z = 230.98 замените на Z = 230.980 и , не закрывая окно Редактора , нажмите Ctrl S - ноль после 8 исчезнет . Таким образом , просто вставляется ноль на конец k2 , но не совсем просто - на конец k4 . 27) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 230.9801 Cr@ = Z k2 = Int ( Cr ) k4 = Cr - k2 While k4 - Int ( k4 ) > 0 And k4 - Int ( k4 ) <> 0.1 k4 = 10 * k4 Wend k4 = Int ( k4 ) Б Z & " ) " & k2 & " " & k4, 11 End Sub 28) Нажмите Проверка и посмотрите , что получится . Сейчас мы использовали две новые вещи : знак не равно ( <> ) и логическое И ( And ) . Если And соединяет два утверждения , то образуется новое утверждение , которое верно тогда и только тогда , когда верно каждое из двух соединённых утверждений . 29) В макросе Проверка строку Z = 230.9801 замените на Z = 997.7 и повторите пункт 28 . 30) В макросе Проверка строку Z = 997.7 замените на Z = 997.1 и повторите пункт 28 . 31) В макросе Проверка строку Z = 997.1 замените на Z = 997.10001 и повторите пункт 28 - вместо 1000 напечатается 0 , как будто после первой единицы не стоит 0001 . 32) В макросе Проверка строку Z = 997.10001 замените на Z = 997.1001 и повторите пункт 28 - напечатается 100 , как и должно быть . В пункте 31 нас постигла неудача потому , что переменная типа Currency не может иметь больше четырёх цифр после десятичного знака . 33) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 997.10001 Dc = CDec ( Z ) k2 = Int ( Dc ) k4 = Dc - k2 While k4 - Int ( k4 ) > 0 And k4 - Int ( k4 ) <> 0.1 k4 = 10 * k4 Wend k4 = Int ( k4 ) Б Z & " ) " & k2 & " " & k4, 11 End Sub 34) Нажмите Проверка и посмотрите , что получится . 35) В макросе Проверка строку Z = 997.10001 замените на Z = 997.9876543211 и повторите пункт 34 . Сейчас мы ввели переменную Dc типа Decimal . Переменную типа Decimal можно ввести только с помощью встроенной функции CDec . 36) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 997.10001 Dc = CDec ( Z ) k2 = Int ( Dc ) k4 = Dc - k2 While k4 - Int ( k4 ) > 0 And k4 - Int ( k4 ) <> 0.1 k4 = 10 * k4 Wend k4 = Int ( k4 ) Б Z & " ) " For k = k2 To k4 Step IIf ( k2 > k4 , -1 , 1 ) Б k & " " Next k Б Chr ( 11 ) End Sub 37) Нажмите Проверка и посмотрите , что получится . 38) В макросе Проверка строку Z = 997.10001 замените на Z = 1000.997 и повторите пункт 37 . Сейчас мы использовали новую для нас функцию - IIf . Эта функция имеет три аргумента . Крайне левый аргумент может иметь только одно из двух значений - True ( истина ) или False ( ложь ) . Если крайне левый аргумент равен True , то IIf принимает значение среднего аргумента ; если крайне левый аргумент равен False , то IIf принимает значение крайне правого аргумента . Таким образом , шаг нашего цикла For равен - 1 , если k2 > k4 , и 1 , если это неверно ( т.е. если k2 < k4 ) . Выполнив урок 15 , Вы узнали : 1) Параметр Step цикла For … Next . 2) Цикл While … Wend . 3) Знаки деления ( \ и / ) . 4) Встроенную функцию Int . 5) Тип Currency и два способа объявления типа локальной переменной . 6) Что десятичным знаком в VBA является не запятая , а точка . 7) And ( логическое И ) . 8) Тип Decimal и встроенную функцию CDec . 9) Встроенную функцию IIf . 10) Простой код , позволяющий десятичной дробью задать диапазон целых чисел . Теперь Вы знаете всё необходимое для самостоятельного выполнения Задачи 2 . Следующий итог К оглавлению
Задача 2 Простой способ задания диалога
Не заглядывая на следующую страницу , напишите процедуру Д , которая бы позволила в макросе Проверка2 MsgBox " Выполнение вызванного Вами макроса может занять " & _ "слишком много времени ." & Аб & _ "Вы можете в любой момент прервать его работу . Для этого" & _ " достаточно нажать кнопку" & _ " ""Ctrl"" и , не отпуская её , кнопку ""Pause Break"" ." & Сб2 Г 12, True, Timer Г 0, True, Timer Г 7, True, Timer For k = 16 To 20 Г k, True, Timer Next k заменить на Д 12, 0, 7, 16.201 Ответ К оглавлению
Урок 16 Нумерованные диалоги
К оглавлению 1) Вначале протестируйте процедуру Д . Для этого : □ В макросе Проверка строку Д 12 , 0 , 7 , 16.201 замените на Д 16.201 Нажмите Проверка и посмотрите , что получится , обращая внимание на порядок следования вопросов . □ В макросе Проверка строку Д 16.201 замените на Д 20.16 Нажмите Проверка и посмотрите , что получится , обращая внимание на порядок следования вопросов . Чтобы с помощью нашей процедуры Д задать диапазон вопросов , нужно : □ набрать номер первого вопроса диапазона ; □ не делая ни одного пропуска , поставить точку и набрать номер последнего вопроса диапазона ; □ если номер последнего вопроса диапазона кончается цифрой 0 или 1 , то , опять же не делая пропуска , ввести цифру 1 . Номер первого вопроса может быть как меньше номера последнего вопроса ( в этом случае вопросы вызываются в прямом порядке ) , так и больше ( тогда вопросы вызываются в обратном порядке ) . “.01” можно заменять на “.1” . Подобно тому , как мы уже пронумеровали вопросы , можно нумеровать диалоги . 2) В самом начале модуля А Public gПравильный , gПауза , gВерных , gНеверных , gПропущенных замените на Public gПравильный , gПауза , gВерных , gНеверных , gПропущенных Public gТипДиалога As Currency 3) Измените процедуру Д , чтобы она выглядела так : Sub Д ( zТипДиалога , ParamArray zТипыВопросов ( ) ) If zТипДиалога <> Int ( Abs ( gТипДиалога ) ) Then Exit Sub If gТипДиалога > 0 Then MsgBox " Выполнение вызванного Вами макроса может занять " & _ "слишком много времени ." & Аб & _ "Вы можете в любой момент прервать его работу . Для этого" & _ " достаточно нажать кнопку" & _ " ""Ctrl"" и , не отпуская её , кнопку ""Pause Break"" ." & Сб2 End If For k = 0 To UBound ( zТипыВопросов ) Dc = CDec ( zТипыВопросов ( k ) ) k2 = Int ( Dc ) k4 = Dc - k2 If k4 = 0 Then Г k2 , True , Timer Else While k4 - Int ( k4 ) > 0 And k4 - Int ( k4 ) <> 0.1 k4 = 10 * k4 Wend k4 = Int ( k4 ) For kk = k2 To k4 Step IIf ( k2 > k4 , -1 , 1 ) Г kk , True , Timer Next kk End If Next k End Sub Exit Sub - оператор досрочного выхода из процедуры . Abs - встроенная функция , равная модулю аргумента . 4) Введите новую процедуру ДД : Sub ДД ( ParamArray zТипыДиалогов ( ) ) gВерных = 0 : gНеверных = 0 : gПропущенных = 0 For k = 0 To UBound ( zТипыДиалогов ) gТипДиалога = zТипыДиалогов ( k ) Д 1 , 12 , 0 , 7 , 20.16 Д 2 , 1.6 , 8.111 , 13.15 Next k Справка2 " Конец" End Sub 5) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) ДД 1 End Sub 6) Нажмите Проверка и посмотрите , что получится . 7) В макросе Проверка ДД 1 замените на ДД 2 и повторите пункт 6 . 8) В макросе Проверка ДД 2 замените на ДД 1 , 2 и повторите пункт 6 , обращая внимание , что справка-предупреждение о долгом выполнении макроса появится дважды . 9) В макросе Проверка ДД 1 , 2 замените на ДД 1 , -2 и повторите пункт 6 , обращая внимание , что справка-предупреждение о долгом выполнении макроса появится лишь однажды . Выполнив урок 16 , Вы научились задавать тип глобальной переменной , программировать досрочный выход из процедуры ( Exit Sub ) и узнали Abs - новую для Вас встроенную функцию VBA . Кроме того , Вы узнали эффективный код ( процедура ДД и согласованная с ней процедура Д ) , позволяющий вызывать один только или несколько подряд диалогов . В этом коде мы использовали две важные идеи : 1) Вместо введения оператора выбора в процедуру ДД , мы ввели специальный , нумерующий аргумент в процедуру Д , что значительно сокращает код . 2) Тот или иной диалог мы вызываем через глобальную переменную , которая кроме целой части модуля имеет также знак и может иметь дробную часть , через которые процедуре Д можно передать дополнительную информацию , которая будет модифицировать работу процедуры Д . Мы уже использовали вторую идею , таким образом запрограммировав процедуру Д , что справка-предупреждение появляется только в том случае , если вызывающая глобальная переменная положительна . Однако пока мы никак не использовали то , что вызывающая глобальная переменная может иметь дробную часть . Этой переменной мы задали тип Currency с четырьмя знаками после десятичного знака , и , следовательно , дробная часть этой переменной может принять 10 000 разных значений ( включая ноль ) . Поэтому возможности модификации работы процедуры Д практически безграничны . Таким образом мы преодолели недостаток ParamArray , не позволяющий вводить новые , необязательные аргументы . Следующий итог К оглавлению
Урок 17 Выбор диалога
К оглавлению 1) Сразу после процедуры Справка2 введите новую процедуру Справка4 : Sub Справка4 ( zЧтоЗадать , zФормаЗадан , zСкакого , zПоКакое ) MsgBox " Вероятно , Вы некорректно ввели данные . Повторите , учитывая ," & _ " что " & zЧтоЗадать & " может быть " & zФормаЗадан & " только " & _ IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым" ) & _ " числом с " & zСкакого & " по " & zПоКакое & " , записанным только" & _ " арабскими цифрами ." & Сб2 End Sub 2) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Справка4 "Тип диалога" , "задан" , 1 , 2 End Sub 3) Нажмите Проверка - если Вы всё сделали правильно , то появится справка с текстом : Вероятно , Вы некорректно ввели данные . Повторите , учитывая , что Тип диалога может быть задан только натуральным ( целым положительным ) числом с 1 по 2 , записанным только арабскими цифрами . Чтобы убрать настоящую справку с экрана , нажмите кнопку ОК настоящей справки или кнопку “Пробел” , Esc или Enter клавиатуры . 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Справка4 "тип диалога" , "задан" , 0 , 2 End Sub 5) Нажмите Проверка - если Вы всё сделали правильно , то появится справка с текстом : Вероятно , Вы некорректно ввели данные . Повторите , учитывая , что тип диалога может быть задан только целым числом с 0 по 2 , записанным только арабскими цифрами . Чтобы убрать настоящую справку с экрана , нажмите кнопку ОК настоящей справки или кнопку “Пробел” , Esc или Enter клавиатуры . 6) В начале модуля А Public gТипДиалога As Currency замените на Public gТипДиалога As Currency Public gLong As Long Public gBoolean As Boolean Сейчас мы ввели две глобальные переменные новых для Вас типов - Long и Boolean . Переменная типа Long может принимать только целое значение ; она может принять любое целое значение с - 2 147 483 648 по 2 147 483 647 . Переменная типа Boolean может принять только одно из двух значений - True ( истина ) или False ( ложь ) . 7) В начале модуля А Public Const Сб2 = vbCrLf & Аб & "Чтобы убрать настоящую справку с экрана ," _ & vbCrLf & "нажмите кнопку ОК настоящей справки или" _ & vbCrLf & "кнопку ""Пробел"" , Esc или Enter клавиатуры ." замените на Public Const Сб2 = vbCrLf & Аб & "Чтобы убрать настоящую справку с экрана ," _ & vbCrLf & "нажмите кнопку ОК настоящей справки или" _ & vbCrLf & "кнопку ""Пробел"" , Esc или Enter клавиатуры ." Public Const Сб4 = " Введите натуральное число с " Public Const Сб5 = " Введите целое число с " 8) В модуль А введите новую процедуру : Sub Задать_gLong ( Optional zЧтоЗадать = "тип диалога" , _ Optional zФормаЗадан = "задан" , _ Optional zСкакого = 1 , Optional zПоКакое = 2 , _ Optional zКакоеПоУмолчанию = 1 , _ Optional zПояснение = "" , Optional zНаСколькоУвеличить_gLong = 0 ) sНачало: ' 1 gBoolean = True ' 2 Z = InputBox ( IIf ( zСкакого > 0 , Сб4 , Сб5 ) & zСкакого & _ " по " & zПоКакое & " ." & _ vbCrLf & zПояснение , _ " " & zЧтоЗадать , zКакоеПоУмолчанию ) ' 6 If Z = Empty Then Exit Sub ' 7 If Not IsNumeric ( Z ) Then GoTo sОшибка ' 8 gLong = Z ' 9 If gLong < zСкакого Or gLong > zПоКакое Then GoTo sОшибка ' 10 gLong = gLong + zНаСколькоУвеличить_gLong ' 11 gBoolean = False ' 12 Exit Sub ' 13 sОшибка: ' 14 Справка4 zЧтоЗадать, zФормаЗадан, zСкакого, zПоКакое ' 15 GoTo sНачало ' 16 End Sub 9) Макрос Проверка измените , чтобы он выглядел так : Sub Проверка ( ) Задать_gLong If gBoolean Then Exit Sub ДД gLong End Sub 10) Нажмите Проверка - появится диалоговое окно InputBox с заголовком “ тип диалога ” , с сообщением “ Введите натуральное число с 1 по 2 . ” и цифрой 1 в окошечке . Нажмите Отмена - работа макроса прервётся . 11) Нажмите Проверка и , после появления диалогового окна , на клавиатуре нажмите Esc - работа макроса прервётся , как будто Вы нажали Отмена . 12) Нажмите Проверка и , после появления диалогового окна , на клавиатуре нажмите Enter - вызовется первый диалог . 13) Нажмите Проверка и , после появления диалогового окна , на клавиатуре нажмите 1 , отпустите её и нажмите Enter - опять вызовется первый диалог . 14) Нажмите Проверка и , после появления диалогового окна , на клавиатуре нажмите 2 , отпустите её и нажмите Enter - вызовется второй диалог . 15) Нажмите Проверка и , после появления диалогового окна , на клавиатуре нажмите 3 , отпустите её и нажмите Enter - появится справка с текстом : Вероятно , Вы некорректно ввели данные . Повторите , учитывая , что тип диалога может быть задан только натуральным ( целым положительным ) числом с 1 по 2 , записанным только арабскими цифрами . Чтобы убрать настоящую справку с экрана , нажмите кнопку ОК настоящей справки или кнопку “Пробел” , Esc или Enter клавиатуры . 16) Любым из четырёх предложенных способов уберите эту справку и почти точно повторите пункт 15 , вместо “3” введя любой недопустимый текст , например “арбуз” , - опять появится та же самая справка ( первый или второй диалог могут быть вызваны при введении не только цифр 1 или 2 , но и некоторых десятичных дробей , например 1,2 ) . Работа процедуры Задать_gLong полностью соответствует её имени и заключается в том , что пользователь задаёт значение глобальной переменной gLong типа Long . Смысл аргументов следующий : zЧтоЗадать показывает пользователю , что именно он выбирает , вводя то или иное целое число , ( в рассмотренном сейчас случае он выбирает тип диалога , но в другом случае он может выбирать , например , число вопросов или длительность паузы ) . zФормаЗадан тесно связан с первым аргументом и необходим , чтобы текст справки , появляющейся в случае некорректного ввода , был грамматически правильным . zСкакого , zПоКакое задают , с какого по какое целое число пользователь может выбрать . zКакоеПоУмолчанию - это число , которое появится в окошечке диалогового окна InputBox . Если пользователь , не введя никакого числа , нажмёт Enter или ОК , то компьютер будет считать , что пользователь ввёл zКакоеПоУмолчанию . zПояснение - это текст , который появится в диалоговом окне InputBox после “ Введите … число с … по … . ” . Этот текст может быть полезен , чтобы пояснить пользователю смысл вводимого им числа . zНаСколькоУвеличить_gLong - это число , которое будет прибавлено к gLong , ( если это число будет отрицательно , то gLong уменьшится , а не увеличится ) . Этот аргумент предусмотрен на случай очень большого числа типов . Пусть , например , имеется 10 диалогов , посвящённых истории Франции , под номерами с 1 020 по 1 029 . Тогда , чтобы пользователь не утомлялся введением четырёхзначного числа , разумно написать макрос : Sub Франция() Задать_gLong , , 0, 9, , , 1020 If gBoolean Then Exit Sub ДД gLong End Sub и создать для него кнопку Франция . Таким образом , относительно короткая процедура Задать_gLong обладает большой гибкостью и многими возможностями . Возможно , развивая наш шаблон История.dot , Вы так и не воспользуетесь всеми возможностями этой процедуры . Однако она может оказаться очень полезной при создании других шаблонов . Чтобы сейчас было удобнее объяснить текст процедуры Задать_gLong , мы с помощью оператора комментария ( ' ) пронумеровали все строки её тела кроме третьей , четвёртой и пятой ( в конце этих трёх строк нельзя ввести комментарий , так как они кончаются символом переноса “ _” , попробуйте пронумеровать эти три строки - у Вас ничего не получится ) . Первая строка фактически ничего не делает , так как содержит только метку . Вторая строка глобальной переменной gBoolean приваивает значение True . Если работа процедуры Задать_gLong будет завершена нормально , то этой переменной строка 12 присвоит значение False . Если же пользователь нажмёт Отмена , то работа процедуры будет прервана досрочно и gBoolean останется равной True . Благодаря этому , процедура , вызвавшая Задать_gLong , получает возможность узнать , нажал ли пользователь Отмена , и изменить свою работу в соответствии с этим . Например , в нашем макросе Проверка за строкой Задать_gLong идёт строка If gBoolean Then Exit Sub и если пользователь нажмёт Отмена , работа макроса будет прервана досрочно . Третья , четвёртая , пятая и шестая строки тела процедуры Задать_gLong вызывают диалоговое окно InputBox и локальной переменной Z присваивают значение функции InputBox , т.е. значение , зависящее от того , что сделал пользователь после того , как диалоговое окно InputBox появилось на экране . Напомню , что , в отличие от глобальной , локальная переменная , не являющаяся аргументом ByRef , “ умирает ” по окончании работы процедуры и никак не влияет на работу другой процедуры , даже если в той есть переменная с тем же именем . Так как Z отсутствует в заголовке процедуры Задать_gLong , то она не является её аргументом . Если пользователь нажал Отмена , то функция InputBox ( а за ней и переменная Z ) примет значение Empty . В таком случае утверждение Z = Empty окажется верным и работа процедуры прервётся на строке 7 , при этом значение gLong останется неизменным , gBoolean останется равной True . Строка 8 содержит новую для Вас встроенную функцию IsNumeric , которая принимает значение True , если её аргументу VBA может сопоставить какое-нибудь число , и значение False , если VBA не может сопоставить её аргументу никакого числа . Если в окошечко InputBox пользователь введёт явно не числовой текст , например “ Мерседес ” , то IsNumeric ( Z ) примет значение False , Not IsNumeric ( Z ) окажется равным True и процедура перейдёт к выполнению строки 15 , следующей за меткой sОшибка . Строка 15 вызывает справку , объясняющую пользователю , что он ввёл неверные данные и что он может ввести только целое число . Затем строка 16 переводит работу процедуры на строку 2 , следующей за меткой sНачало , т.е. работа процедуры начинается с начала . Если текст , введённый пользователем , может быть интерпретирован как какое-нибудь число , то строка 9 это число округлит до целого и это округлённое значение присвоит глобальной переменной gLong . Строка 10 проверяет , входит ли это число , округлённое до целого , в допустимый диапазон . Если не входит ( т.е. если меньше нижней границы диапазона , zСкакого , или больше верхней , zПоКакое ) , то процедура переходит к выполнению строки 15 ( чтобы потом начать работу с начала ) . Or - логическое ИЛИ . Таким образом , теперь Вы знаете 3 логические операции VBA : Not ( НЕВЕРНО , ЧТО ) , And ( И ) и Or ( ИЛИ ) . Это основные логические операции VBA , с помощью которых можно легко записать любое , сколь угодно сложное утверждение , ( кроме них , в VBA имеется ещё 3 логические операции , без которых можно обойтись ) . Если пользователь корректно ввёл данные , то строка 11 должным образом изменяет или не изменяет значение gLong ( если zНаСколькоУвеличить_gLong = 0 , то значение gLong не изменится ) , строка 12 присваивает gBoolean значение False и строка 13 кончает работу процедуры ( Exit Sub - выход из процедуры ) . 17) Уберите комментарии ( нумерацию строк ) из процедуры Задать_gLong . Цель следующего пункта - сократить программный код . Часто бывает непросто сразу написать сложную , с длинным кодом сложной структуры , процедуру . В таком случае можно : □ написать , протестировать и исправить более простую процедуру , выполняющую часть поставленной задачи , или несколько простых процедур , каждая из которых будет выполнять свою часть поставленной задачи . □ написать , протестировать и исправить конечную процедуру , вызывающую более простую процедуру или несколько более простых процедур . После этого бывает полезно вызовы более простых процедур заменить их телами , удалить эти более простые процедуры и таким образом сократить программный код . 18) Выделите всё тело процедуры Справка4 : MsgBox " Вероятно , Вы некорректно ввели данные . Повторите , учитывая ," & _ " что " & zЧтоЗадать & " может быть " & zФормаЗадан & " только " & _ IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым" ) & _ " числом с " & zСкакого & " по " & zПоКакое & " , записанным только" & _ " арабскими цифрами ." & Сб2 На клавиатуре нажмите Ctrl C - выделенный текст будет скопирован в буфер . На клавиатуре нажмите стрелку вправо , влево , вверх или вниз - выделение снимется . 19) Над окном кода имеется 2 маленьких окошечка , в левом из них левой кнопкой мыши нажмите стрелку вниз - появится список процедур . В этом списке левой кнопкой мыши нажмите Задать_gLong - курсор перейдёт в начало первой строки тела этой процедуры . 20) В процедуре Задать_gLong выделите всю строку ( от начала ) Справка4 zЧтоЗадать , zФормаЗадан , zСкакого , zПоКакое 21) На клавиатуре нажмите Ctrl V - выделенная строка заменится на содержимое буфера . В результате этого процедура Задать_gLong должна принять вид : Sub Задать_gLong ( Optional zЧтоЗадать = "тип диалога" , _ Optional zФормаЗадан = "задан" , _ Optional zСкакого = 1 , Optional zПоКакое = 2 , _ Optional zКакоеПоУмолчанию = 1 , _ Optional zПояснение = "" , Optional zНаСколькоУвеличить_gLong = 0 ) sНачало: gBoolean = True Z = InputBox ( IIf ( zСкакого > 0 , Сб4 , Сб5 ) & zСкакого & _ " по " & zПоКакое & " ." & _ vbCrLf & zПояснение , _ " " & zЧтоЗадать , zКакоеПоУмолчанию ) If Z = Empty Then Exit Sub If Not IsNumeric ( Z ) Then GoTo sОшибка gLong = Z If gLong < zСкакого Or gLong > zПоКакое Then GoTo sОшибка gLong = gLong + zНаСколькоУвеличить_gLong gBoolean = False Exit Sub sОшибка: MsgBox " Вероятно , Вы некорректно ввели данные . Повторите , учитывая ," & _ " что " & zЧтоЗадать & " может быть " & zФормаЗадан & " только " & _ IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым" ) & _ " числом с " & zСкакого & " по " & zПоКакое & " , записанным только" & _ " арабскими цифрами ." & Сб2 GoTo sНачало End Sub 22) Протестируйте новый вариант этой процедуры ( для этого несколько раз нажмите Проверка , каждый раз по-новому задавая тип диалога ) и убедитесь , что она работает прежним образом . 23) Удалите процедуру Справка4 . Для этого выделите её текст полностью , включая Sub и End Sub , и на клавиатуре нажмите Delete . 24) Макрос Проверка переименуйте в Диалоги и на нашей панели История создайте для него ( макроса Диалоги ) кнопку Д . 25) Нажимая на новую кнопку , протестируйте новый макрос , то есть убедитесь , что макрос Диалоги работает так же , как работал макрос Проверка . Выполнив урок 17 , Вы узнали и повторили : 1) Встроенную функцию IIf . Эта функция имеет три обязательных аргумента и ни одного необязательного . Иначе говоря , при вызове её необходимо задавать 3 и только 3 аргумента . Крайне левый аргумент имеет тип Boolean и может иметь только одно из двух значений : True или False . Средний и крайне правый аргументы могут принимать любые значения . Если крайне левый аргумент имеет значение True ( истина ) , то IIf равна своему среднему аргументу . Если крайне левый аргумент имеет значение False ( ложь ) , то IIf равна своему крайне правому аргументу . Например , наша IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым" ) принимает значение "натуральным ( целым положительным )" , если zСкакого > 0 , и "целым" , если zСкакого < 0 . 2) Типы переменных Long и Boolean . 3) Встроенную функцию IsNumeric . 4) Что если переменной типа Long присваивается число , то это число округляется до целого , так как переменная типа Long может принимать только целые значения . 5) Логические операции Or , And , Not . 6) Как быстро находить текст процедуры по её имени . 7) Как копировать кусок программного кода из одного места модуля в другое ( Ctrl C , Ctrl V ) . 8) Как писать процедуру “ по частям ” . 9) Относительно короткую , но гибкую , эффективную процедуру , позволяющую легко и просто запрограммировать диалог с пользователем , в ходе которого он может осмысленно задать целое число . Следующий итог К оглавлению
Дополнительный урок 17 А Традиционная обработка ошибок
При недостатке времени этот урок можно пропустить . Опытный программист сказал бы , что на уроке 17 мы использовали нетрадиционную обработку ошибок ( исключительных ситуаций , созданных , например , некорректными действиями пользователя ) . Обычно ошибки обрабатываются с помощью оператора On Error , мы же обошлись без него . Сейчас мы используем оператор On Error и убедимся , что обработка ошибок , применённая нами на уроке 17 , в данном случае лучше традиционной . К оглавлению 1) Выделите процедуру Задать_gLong полностью , включая End Sub , Sub и пустую строку перед Sub . Чтобы программный код лучше воспринимался зрительно , между процедурами ( т.е. между End Sub и Sub ) должно быть по одной пустой строке . Если этих пустых строк у Вас нет , вставьте их сейчас . 2) На клавиатуре нажмите Ctrl C - выделенный текст скопируется в буфер . 3) Не закрывая окно Редактора , левой кнопкой мыши нажмите Правка , Закомментировать блок - весь выделенный текст закомментируется ( т.е. в начало каждой строки выделенного текста вставится оператор комментария ( ' ) ) , и VBA станет его игнорировать . 4) На клавиатуре нажмите стрелку вправо - выделение снимется и курсор окажется на пустой строке ( если курсор окажется в конце строки End Sub , то ещё раз нажмите стрелку вправо ) . 5) На клавиатуре нажмите Ctrl V - из буфера скопируется копия процедуры Задать_gLong . 6) Измените эту копию , чтобы она выглядела так : Sub Задать_gLong ( Optional zЧтоЗадать = "тип диалога" , _ Optional zФормаЗадан = "задан" , _ Optional zСкакого = 1 , Optional zПоКакое = 2 , _ Optional zКакоеПоУмолчанию = 1 , _ Optional zПояснение = "", Optional zНаСколькоУвеличить_gLong = 0 ) sНачало : On Error GoTo sОшибка gBoolean = True Z = InputBox ( IIf ( zСкакого > 0 , Сб4 , Сб5 ) & zСкакого & _ " по " & zПоКакое & " ." & _ vbCrLf & zПояснение , _ " " & zЧтоЗадать , zКакоеПоУмолчанию ) If Z = Empty Then Exit Sub gLong = Z If gLong < zСкакого Or gLong > zПоКакое Then GoTo sОшибка gLong = gLong + zНаСколькоУвеличить_gLong gBoolean = False Exit Sub On Error GoTo 0 ' 0 - цифра ноль . sОшибка : MsgBox " Вероятно , Вы некорректно ввели данные . Повторите , учитывая ," & _ " что " & zЧтоЗадать & " может быть " & zФормаЗадан & " только " & _ IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым") & _ " числом с " & zСкакого & " по " & zПоКакое & " , записанным только" & _ " арабскими цифрами ." & Сб2 GoTo sНачало End Sub 7) На нашей панели История левой кнопкой мыши нажмите Д - появится знакомое Вам диалоговое окно InputBox с заголовком “ тип диалога ” и сообщением “ Введите натуральное число с 1 по 2 . ” . 8) В окошечко этого диалогового окна введите слово “ четыре ” и на клавиатуре нажмите Enter - появится знакомая Вам справка о некорректном введении данных . На клавиатуре нажмите Enter - справка уберётся и вновь появится диалоговое окно InputBox . 9) В окошечко этого диалогового окна введите “ IV ” и на клавиатуре нажмите Enter - появится справка с сообщением : Ошибка выполнения ‘13’ : Несоответствие типа и четырьмя кнопками : Продолжить , Завершить , Отладка , Справка . 10) Левой кнопкой мыши нажмите Отладка - в окне Редактора выделится строка gLong = Z . Скорей всего , слово “ Отладка ” на справке было в прямоугольнике с пунктирной границей . Это значит , что кнопка Отладка находилась “ в фокусе ” . Если кнопка находится в фокусе , то вместо её нажатия левой кнопкой мыши можно нажать Enter на клавиатуре - результат будет тот же . Вместо того , чтобы нажать Отладка , Вы могли нажать Enter на клавиатуре ( конечно , если Отладка находилась в фокусе ) . 11) В окне Редактора левой кнопкой мыши нажмите кнопку “ Сброс ” ( кнопку с синим квадратиком , при наведении на неё мыши должна “ всплыть ” подсказка “ Сброс ” ) - выделение со строки gLong = Z снимется . 12) Разверните окна Редактора и кода . Закомментируйте новую версию процедуры Задать_gLong ( см. пункт 3 ) . 13) Выделите старую версию процедуры Задать_gLong . Левой кнопкой мыши нажмите Правка , Раскомментировать блок - процедура раскомментируется , т.е. операторы комментария ( ' ) , стоявшие в начале каждой строки , исчезнут , и старая версия процедуры станет “ видимой ” для VBA . 14) На клавиатуре нажмите стрелку вправо - с раскомментированной процедуры снимется выделение . 15) Закройте окно Редактора и повторите пункты 7 … 9 - после выполнения пункта 9 появится не совершенно непонятная простому пользователю справка с “ Ошибкой выполнения ‘13’ ” , а наша вполне понятная справка о некорректности введения данных . Оператор On Error GoTo Метка охраняемый блок On Error GoTo 0 ( 0 - цифра 0 ) действует следующим образом : On Error GoTo Метка открывает охраняемый блок , On Error GoTo 0 закрывает его . Если при выполнении охраняемого блока возникает исключительная ситуация ( ошибка ) , то действие программы переходит из охраняемого блока на строку сразу после “ Метка: ” . Например , в нашем случае ошибка возникает при попытке компьютера выполнить строку gLong = Z , если значению Z не может быть сопоставлено никакое число . В таком случае компьютер всегда вроде бы должен переходить к выполнению оператора MsgBox , следующему за меткой sОшибка . Однако , как мы только что убедились , это происходит только в первый раз , а при возникновении на той же строке второй подобной же ошибки компьютер “ по собственной инициативе ” решает разъяснить суть ошибки по-другому . Таким образом , оператор On Error GoTo Метка имеет много малопонятных тонкостей , делающих его действие малопредсказуемым , и его лучше не применять . Запомните также , что On Error GoTo 0 всегда только закрывает охраняемый блок и никогда не переводит действие программы на строку за меткой 0: , даже если такая метка имеется . 16) Если Вы больше не хотите сравнивать работу старой и новой версий процедуры Задать_gLong , то выделите весь закомментированный текст новой версии и на клавиатуре нажмите Delete - новая версия процедуры Задать_gLong будет удалена . Выполнив урок 17 А , Вы узнали : 1) Как закомментировать и раскомментировать большой кусок программного кода ; как создать близкие , но всё же отличные друг от друга версии одной и той же процедуры ( Ctrl C , Ctrl V ) и сравнить их работу . 2) Оператор On Error GoTo Метка . . . On Error GoTo 0 и почему его надо избегать . 3) Что значит , что кнопка находится в фокусе , и какой есть признак того , что кнопка находится в фокусе . Следующий итог К оглавлению
Урок 18 Усовершенствованный выбор диалога
Главный недостаток нашей процедуры Задать_gLong в том , что она задаёт значение глобальной переменной , которая , естественно , имеет только одно имя . Этот недостаток почти незаметен , если требуется задать значение только одной переменной . Однако если требуется задать значения нескольких переменных , то после строк Задать_gLong … придётся писать , например , строки Z1 = gLong Z2 = gLong Z3 = gLong . . . К оглавлению 1) Из начала модуля А удалите : Public gLong As Long Public gBoolean As Boolean 2) Процедуру Задать_gLong переименуйте в Задать и измените её , чтобы она выглядела так : Sub Задать ( Z , Optional zЧтоЗадать = "тип диалога" , _ Optional zФормаЗадан = "задан" , _ Optional zСкакого = 1 , Optional zПоКакое = 2 , _ Optional zКакоеПоУмолчанию = 1 , _ Optional zПояснение = "" , Optional zНаСколькоУвеличитьZ = 0 , _ Optional zНаСколькоУмножитьZ = 1 ) sНачало : Z = InputBox ( IIf ( zСкакого > 0 , Сб4 , Сб5 ) & zСкакого & _ " по " & zПоКакое & " ." & _ vbCrLf & zПояснение , _ " " & zЧтоЗадать , zКакоеПоУмолчанию ) If Z = Empty Then Exit Sub If Not IsNumeric ( Z ) Then GoTo sОшибка Z = CDec ( Z ) If Z < zСкакого Or Z > zПоКакое Or Z > Int ( Z ) Then GoTo sОшибка Z = Z + zНаСколькоУвеличитьZ Z = Z * zНаСколькоУмножитьZ Exit Sub sОшибка : MsgBox " Вероятно , Вы некорректно ввели данные . Повторите , учитывая ," & _ " что " & zЧтоЗадать & " может быть " & zФормаЗадан & " только " & _ IIf ( zСкакого > 0 , "натуральным ( целым положительным )" , "целым" ) & _ " числом с " & zСкакого & " по " & zПоКакое & " , записанным только" & _ " арабскими цифрами ." & Сб2 GoTo sНачало End Sub 3) Измените макрос Диалоги , чтобы он выглядел так : Sub Диалоги ( ) Задать zТипДиалога If zТипДиалога = Empty Then Exit Sub ДД zТипДиалога End Sub 4) Нажимая Д на панели История , протестируйте процедуры Диалоги и Задать . Вы сможете обнаружить , что справка о некорректности введения данных выдаётся не только во всех тех случаях , когда выдавалась и раньше , ( при введении нечисловых текстов , например “ арбуз ” , и слишком больших или слишком малых чисел ) , но и при введении почти любых десятичных дробей ( например , 1,2 ) . 5) Измените процедуру ДД , чтобы она выглядела так : Sub ДД ( ParamArray zТипыДиалогов ( ) ) If zТипыДиалогов ( 0 ) = Empty Then Exit Sub gВерных = 0 : gНеверных = 0 : gПропущенных = 0 For k = 0 To UBound ( zТипыДиалогов ) If zТипыДиалогов ( k ) = Empty Then Exit For gТипДиалога = zТипыДиалогов ( k ) Д 1 , 12 , 0 , 7 , 20.16 Д 2 , 1.6 , 8.111 , 13.15 Next k Справка2 " Конец" End Sub Сейчас мы использовали новый для Вас оператор Exit For . Этот оператор обеспечивает досрочный выход из цикла , т.е. независимо от значения счётчика переводит действие процедуры на строку , следующую за Next , ( например , в нашей процедуре ДД - на строку Справка2 " Конец" ) . Если Exit For находится во внутреннем цикле , т.е. в цикле , который находится внутри другого , внешнего цикла , то обеспечивает досрочный выход только из внутреннего цикла , но не из внешнего . 6) Измените макрос Диалоги , чтобы он выглядел так : Sub Диалоги ( ) Задать Z1 , "тип первого диалога" : If Z1 = Empty Then GoTo S Задать Z2 , "тип второго диалога" : If Z2 = Empty Then GoTo S Задать Z3 , "тип третьего диалога" S: ДД Z1 , Z2 , Z3 End Sub 7) Нажимая Д на панели История , протестируйте новую версию программного кода . Убедитесь , что Вы можете задать три диалога , два , один или ни одного ( т.е. прервать работу макроса Диалоги , нажав Отмена в первом диалоговом окне ) . Чтобы задать только один диалог , нажмите Отмена во втором диалоговом окне . Чтобы задать два и только два диалога , нажмите Отмена в третьем диалоговом окне . Задавая два диалога , Вы можете задать второй диалог после первого , первый после второго , первый после первого или второй после второго . Задавая три диалога , Вы имеете 8 возможностей . Выполнив урок 18 , Вы узнали : 1) Оператор Exit For досрочного выхода из цикла . 2) Процедуру Задать , более гибкую чем наша более ранняя процедура Задать_gLong . Следующий итог К оглавлению
Урок 19 Изменение паузы
Благодаря аргументу zНаСколькоУмножитьZ процедуры Задать , мы можем задавать не только целые , но и дробные значения переменных ( при этом в окошечко диалогового окна InputBox мы по-прежнему будем вводить только целое число ) . Цель настоящего урока - дать пользователю возможность самостоятельно регулировать длительность пауз , т.е. время , на которое вопросы появляются на экране . Пользователь будет регулировать длительность пауз , задавая значение глобальной переменной , могущей принимать как целые , так и дробные значения . К оглавлению 1) В начале модуля А строку Public gПравильный , gПауза , gВерных , gНеверных , gПропущенных замените на Public gПравильный , gВерных , gНеверных , gПропущенных Public gПауза , gМножительПаузы 2) Измените процедуру П , чтобы она выглядела так : Sub П ( zПауза ) gПауза = zПауза * gМножительПаузы End Sub 3) В макросе Я CommandBars("История").Visible = True замените на CommandBars("История").Visible = True gМножительПаузы = 1 Макрос Я выполняется при создании каждого нового документа в шаблоне История.dot , так как на него , на макрос Я , ссылается макрос Document_New модуля ThisDocument . 4) На панели История нажмите Д и задайте один , два или три диалога . Вы увидите , что макрос Диалоги перестал нормально работать : вопросы появляются на совсем краткое время . Это происходит потому , что gМножительПаузы имеет значение ноль или близкое к нему . 5) Закройте Word и вновь откройте История.dot . Повторите пункт 4 и убедитесь , что макрос Диалоги работает нормально , так как при создании нового документа переменной gМножительПаузы было присвоено значение 1 . 6) В модуль А введите новый макрос : Sub ЗадатьМножительПаузы ( ) Задать gМножительПаузы , "множитель паузы" , , 5 , 100 , 10 , , , 0.1 End Sub и на панели История создайте для него кнопку Пауза . 7) Левой кнопкой мыши нажмите Пауза - откроется диалоговое окно InputBox с заголовком “ множитель паузы ” , с сообщением “ Введите натуральное число с 5 по 100 . ” и числом 10 в окошечке . 8) Введите число 100 и на клавиатуре нажмите Enter . 9) На панели История нажмите Д и задайте только один диалог ( первый ) . Засеките , на сколько времени появится первый вопрос , и на клавиатуре нажмите Ctrl Pause Break . Если Вы всё сделали правильно , то первый вопрос появится на 20 секунд . 10) Нажав Пауза , задайте множитель паузы числом 50 и повторите пункт 9 - вопрос появится на 10 секунд . 11) Закройте Word и вновь откройте История.dot . 12) На панели История нажмите Д и задайте только один ( второй ) диалог . Дойдите до третьего вопроса и засеките , на сколько времени появится третий вопрос . На клавиатуре нажмите Ctrl Pause Break . Если Вы всё сделали правильно , то третий вопрос появится на 7 … 8 секунд ( разброс вызван тем , что компьютеры имеют разное “ железо ” : процессор , оперативную память и т.д. ) ; это наша длительность паузы по умолчанию , которую мы задаём строкой П 7 . 13) Нажав Пауза , задайте множитель паузы числом 5 и повторите пункт 12 - третий вопрос появится на 3 … 4 секунды . 14) На панели История нажмите Д , задайте любой один диалог и убедитесь , что вопросы появляются на совсем краткое время : Ctrl Pause Break обнуляет все глобальные переменные , в том числе и gМножительПаузы . 15) Измените макрос ЗадатьМножительПаузы , чтобы он выглядел так : Sub ЗадатьМножительПаузы ( Optional zУсловиеВыполнения = True ) If zУсловиеВыполнения Then Задать gМножительПаузы , "множитель паузы" , , 5 , 100 , 10 , , , 0.1 End If End Sub При этом он перестанет быть макросом , так как получит аргумент . 16) Нажмите кнопку Пауза и убедитесь , что её работа не изменилась , хотя вызываемая ею процедура перестала быть макросом . 17) Откройте диалоговое окно Настройка и убедитесь , что создать новую кнопку для процедуры ЗадатьМножительПаузы известным Вам образом уже не возможно . 18) Измените процедуру П , чтобы она выглядела так : Sub П ( zПауза ) ЗадатьМножительПаузы gМножительПаузы < 0.5 Or gМножительПаузы > 10 gПауза = zПауза * gМножительПаузы End Sub 19) Не нажимая на Пауза , нажмите Д и выберите какой-нибудь диалог - если в пункте 16 Вы не задали множитель паузы , то после предупреждающей справки появится диалоговое окно InputBox , которое можно вызвать кнопкой Пауза . В окошечко введите натуральное число с 5 по 100 и на клавиатуре нажмите Enter - диалог пройдёт как обычно . 20) Если при выполнении пункта 19 диалоговое окно InputBox не появилось , работу диалога прервите сочетанием клавиш Ctrl Pause Break и выполните пункт 19 в полном объёме . 21) На панели История нажмите Д , выберите какой-нибудь диалог - диалоговое окно InputBox не появится . Таким образом , процедура П ( а через неё и макрос Диалоги ) вызывает процедуру ЗадатьМножительПаузы в том и только в том случае , если значение переменной gМножительПаузы выходит за пределы диапозона допустимых значений . Выполнив урок 19 , Вы узнали : 1) Как задавать значения глобальных переменных при создании нового документа . 2) Как с помощью нашей процедуры “ Задать ” задать дробное число . 3) Что Ctrl Pause Break обнуляет все глобальные переменные . 4) Что кнопкой можно вызывать не только макрос , но и процедуру с аргументами , если среди них нет обязательных ( т.е. если каждый аргумент введен с ключом Optional ) , однако новую кнопку для такой процедуры создать вручную уже нельзя . 5) Что любой макрос можно превратить в процедуру с аргументом , введя необязательный аргумент zУсловиеВыполнения по умолчанию равный True . Это можно делать с двумя целями : во-первых , чтобы удалить имя макроса из окна “ Настройка ” , чтобы в нём было легче находить имена новых макросов ; во-вторых , чтобы сократить употребление If … Then … . Достижение второй цели особенно важно , если If … Then … не умещается на одной строке ( в таком случае вместо одной строки придётся писать три ) . Естественно , аргумент zУсловиеВыполнения можно вводить не только в макросы , но и в другие процедуры . Следующий итог К оглавлению
Урок 20 Подтипы вопросов
Наш шаблон как обучающая программа имеет крупный недостаток . Наш шаблон меняет порядок следования вариантов ответа , поэтому ученик вынужден читать эти варианты . Однако каждый набор вариантов ответа имеет всегда один и тот же вопрос . Поэтому ученик может читать только варианты ответа , не обращая внимания на вопрос . Сейчас мы научим наш шаблон к одному и тому же набору вариантов ответа давать разные варианты вопроса . К оглавлению 1) В модуле А Public gТипДиалога As Currency замените на Public gТипДиалога As Currency Public gПодТипВопроса As Long 2) В процедуре Г Sub Г ( zТипВопроса , Optional zНаВремя = False , _ Optional ByVal ZсКакимМенятьВерныйОтвет = 0 ) замените на Sub Г (zТипВопроса , Optional zНаВремя = False , _ Optional ByVal ZсКакимМенятьВерныйОтвет = 0 , _ Optional zПодТипВопроса = 1 ) gПодТипВопроса = zПодТипВопроса - 1 If gПодТипВопроса < 0 Then gПодТипВопроса = 0 3) В модуль А введите новую процедуру : Sub ББ ( ParamArray zВарианты ( ) ) gПодТипВопроса = gПодТипВопроса Mod ( UBound ( zВарианты ) + 1 ) Б zВарианты ( gПодТипВопроса ) End Sub 4) Измените процедуру М , чтобы она выглядела так : Sub М ( zНомерПравильногоОтвета , ParamArray zОтветы ( ) ) ReDim G ( 1 To UBound ( zОтветы ) + 1 ) For k = 0 To UBound ( zОтветы ) G ( k + 1 ) = zОтветы ( k ) Next k Select Case zНомерПравильногоОтвета Case 0 gПравильный = gПодТипВопроса Mod k + 1 Case 1 To 9 gПравильный = zНомерПравильногоОтвета End Select End Sub По выходе из цикла , переменная k имеет значение UBound ( zОтветы ) + 1 = UBound ( G ) . 5) В операторе Select Case zТипВопроса процедуры Г Case 0 Б "В каком веке Москва вновь стала столицей России ?" М 3 , "в восемнадцатом" , "в девятнадцатом" , "в двадцатом" П 2 замените на Case 0 Б "В каком веке " ББ "Москва вновь стала" , "Санкт-Петербург стал" Б " столицей России ?" М 0 , "в двадцатом" , "в восемнадцатом" , "в девятнадцатом" П 2 6) В той же процедуре Г четвёртую с конца строку Г zТипВопроса , True , Timer замените на Г zТипВопроса , True , Timer , zПодТипВопроса 7) В процедуре ДД Д 2 , 1.6 , 8.111 , 13.15 замените на Д 2 , 1.6 , 8.111 , 13.15 Д 3 , 0 8) Измените макрос Диалоги , чтобы он выглядел так : Sub Диалоги ( ) Задать Z1 , "тип первого диалога" , , , 3 : If Z1 = Empty Then GoTo S Задать Z2 , "тип второго диалога" , , , 3 : If Z2 = Empty Then GoTo S Задать Z3 , "тип третьего диалога" , , , 3 S: ДД Z1 , Z2 , Z3 End Sub 9) В процедуре Д Г k2 , True , Timer замените на Г k2 , True , Timer , Timer 10) В той же процедуре Д Г kk , True , Timer замените на Г kk , True , Timer , Timer 11) На панели История нажмите Д и задайте один , третий диалог . Несколько раз ответьте неправильно и убедитесь , что после сообщения о неправильности ответа всегда появляется один и тот же вопрос . 12) Несколько раз повторите пункт 11 и убедитесь , что появляется то “ Москва вновь стала ” , то “ Санкт-Петербург стал ” . Выполнив урок 20 , Вы не узнали ничего принципиально нового в синтаксисе VBA , но узнали , как , введя подтип , можно сократить код , ( если бы мы не ввели аргумент zПодТипВопроса , то вместо одного случая ( Case ) нам пришлось писать бы два и вместо шести строк программного кода - восемь более длинных ; введя не 2 , а большее число подтипов , мы можем добиться большего сокращения кода ) . Вы узнали новые примеры применения ключа ParamArray . Обратите внимание , что мы написали процедуру ББ - аналог процедуры Б , но не писали аналог процедуры М , а лишь слегка изменили её . Легко изменить М мы смогли благодаря тому , что она имеет аргумент до ParamArray . Мы почти закончили программу . Осталось : 1) Другие типы вопросов разбить на подтипы . 2) Написать процедуру , которая бы писала ( не на краткое время , а “ на совсем ” ) проверочные , предназначенные для распечатки на бумаге . 3) Создать систему навигации по этим проверочным ( так как типов и подтипов вопросов можно ввести много и их можно по-разному комбинировать , то проверочных запрограммировать можно невероятно много ) . Наша цель - создать основы , “ скелет ” программы . В дальнейшем историк-непрограммист относительно легко сможет расширять её возможности , добавляя новые типы и подтипы вопросов . Следующий итог К оглавлению
Урок 21 Разбиение на подтипы ( начало )
Если вопрос имеет два подтипа , то его хоть как-то можно протестировать диалогом . Однако если вопрос имеет три , четыре , десять или двадцать подтипов , то протестировать все его подтипы диалогом весьма трудно , так как вызов того или иного подтипа фактически случаен , так как зависит от переменной Timer , т.е. от числа секунд , прошедших с полуночи . Поэтому на настоящем уроке наш первый шаг - написать тестирующую программу . К оглавлению 1) В модуль А введите новую процедуру Проверка : Sub Проверка ( ) Г 0 , , , 1 Б "gПравильный = " & gПравильный End Sub 2) На панели История нажмите Проверка - сначала появится диалогое окно InputBox с предложением задать множитель паузы , потом появится текст : В каком веке Москва вновь стала столицей России ? 1 ) в двадцатом 2 ) в восемнадцатом 3 ) в девятнадцатом gПравильный = 1 ( перед вопросом будет пустая строка ) . Как видите , подтип 1 вопроса 0 работает правильно : gПравильный равен номеру верного варианта ответа . 3) Уберите с экрана весь текст , в макросе Проверка цифру 1 ( задающую подтип вопроса ) замените на 2 , повторите пункт 2 - появится текст : В каком веке Санкт-Петербург стал столицей России ? 1 ) в двадцатом 2 ) в восемнадцатом 3 ) в девятнадцатом gПравильный = 2 4) Почти повторите пункт 3 , заменив 2 ( подтип ) на 3 - появится текст как в пункте 2 ( т.е. как при подтипе 1 ) . 5) Почти повторите пункт 3 , заменив 3 на 4 , - появится текст как в пункте 3 ( т.е. как при подтипе 2 ) . 6) Продолжите так же ещё с несколькими натуральными числами ( 5 ; 6 ; 7 ; 8 и т.д. ) и убедитесь , что в качестве подтипа нолевого вопроса всякое нечётное натуральное число эквивалентно единице , а всякое чётное натуральное число эквивалентно двум . 7) Уберите с экрана весь текст , измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 0 , , , 0 Б "gПравильный = " & gПравильный End Sub На панели Истории нажмите Проверка - появится текст как в пункте 2 ( т.е. как при подтипе 1 ) . 8) Уберите с экрана весь текст , измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 0 , , , -1 Б "gПравильный = " & gПравильный End Sub На панели Истории нажмите Проверка - появится текст как в пункте 2 ( т.е. как при подтипе 1 ) . 9) Продолжите так же ещё с несколькими отрицательными целыми числами ( - 2 ; - 3 ; - 4 и т.д. ) и убедитесь , что каждое из них в качестве подтипа вопроса эквивалентно единице . В пункте 2 мы столкнулись с неприятной “ мелочью ” , которая , однако , может оказаться совсем не мелочью для конечного пользователя , поставив его в полный тупик : вследствие обнуления глобальной переменной gМножительПаузы компьютер предложил задать её значение . С одной стороны , обнуление глобальной переменной происходит по очень многим причинам ( например , в нашем случае это произошло потому , что мы ввели новую процедуру ; обнуление глобальных переменных происходит также в случае прерывания работы макроса сочетанием клавиш Ctrl Pause Break ) . С другой стороны , когда пользователь выводит вопросы “ на совсем ” ( для распечатки на бумаге ) , ни переменная gМножительПаузы , ни переменная gПауза ему фактически не нужны . Поэтому разумно не включать работу процедуры П , когда вопросы выводятся “ на совсем ” . 10) Чтобы обнулить gМножительПаузы , на панели История нажмите Д и сразу же ( при появлении диалогового окна с заголовком “ тип первого диалога ” ) на клавиатуре нажмите Ctrl Pause Break - появится справка с четырьмя кнопками и сообщением “ Выполнение программы прервано ” . На этой справке левой кнопкой мыши нажмите Завершить . 11) На панели История нажмите Проверка . Если ещё раз появится справка с сообщением “ Выполнение программы прервано ” , то опять нажмите Завершить . 12) В результате выполнения пункта 11 либо появится диалоговое окно InputBox с заголовком “ множитель паузы ” , либо работа макроса Проверка прекратится . Если случится последнее , то ещё раз нажмите Проверка - появится только что упомянутое диалоговое окно . 13) На клавиатуре нажмите Enter - переменной gМножительПаузы будет присвоено значение 1 , а работа макроса Проверка завершится нормальным образом . В результате выполнения пунктов 10 … 13 Вы убедились , что обнуление переменной gМножительПаузы нарушает работу макроса Проверка . 14) В начале модуля А Public gПауза , gМножительПаузы замените на Public gПауза , gМножительПаузы , gНаВремя 15) В начале процедуры Г gПодТипВопроса = zПодТипВопроса - 1 If gПодТипВопроса < 0 Then gПодТипВопроса = 0 замените на gПодТипВопроса = zПодТипВопроса - 1 If gПодТипВопроса < 0 Then gПодТипВопроса = 0 gНаВремя = zНаВремя 16) Измените процедуру П , чтобы она выглядела так : Sub П ( zПауза ) If gНаВремя Then ЗадатьМножительПаузы gМножительПаузы < 0.5 Or gМножительПаузы > 10 gПауза = zПауза * gМножительПаузы End If End Sub 17) Повторите пункты 10 , 11 - либо макрос Проверка выполнится нормальным образом , либо его работа прекратится . Если случится последнее , то ещё раз нажмите Проверка - макрос выполнится нормальным образом ( диалоговое окно InputBox с заголовком “ множитель паузы ” не появится ) . 18) Нажимая Д на панели История , убедитесь , что работа диалогов не изменилась . Первый шаг ( написать тестирующую программу ) выполнен . Второй шаг настоящего урока - протестировать процедуру М с нолевым значением первого аргумента . 19) В оператор Select Case zТипВопроса процедуры Г добавьте новый случай : Case 21 Б "Реки " ББ "Индии :" , "Китая :" , "Двуречья :" М 0 , "Инд , Ганг" , "Хуанхе , Янцзы" , "Тигр , Евфрат" П 2 20) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 21 , , , 1 Б "gПравильный = " & gПравильный End Sub 21) Повторите пункты со второго по девятый и убедитесь , что подтипам 1 , 4 , 7 , … ; 0 , -1 , -2 , -3 … соответствует вопрос : Реки Индии : 1 ) Инд , Ганг 2 ) Хуанхе , Янцзы 3 ) Тигр , Евфрат gПравильный = 1 подтипам 2 , 5 , 8 , … - вопрос : Реки Китая : 1 ) Инд , Ганг 2 ) Хуанхе , Янцзы 3 ) Тигр , Евфрат gПравильный = 2 подтипам 3 , 6 , 9 , … - вопрос : Реки Двуречья : 1 ) Инд , Ганг 2 ) Хуанхе , Янцзы 3 ) Тигр , Евфрат gПравильный = 3 22) В операторе Select Case zТипВопроса процедуры Г Case 16 Б "Первым космонавтом был :" М 1 , "Юрий Гагарин" , "Герман Гагарин" , _ "Юрий Титов" , "Герман Титов" П 5 замените на Case 16 ББ "Первым космонавтом был :" , _ "Вторым космонавтом был :" , _ "Из двух первых космонавтов в самолёте разбился :" М 0 , "Юрий Гагарин" , "Герман Титов" П 5 23) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 16 , , , 1 Б "gПравильный = " & gПравильный End Sub 24) Повторите пункты со второго по девятый и убедитесь , что подтипам 1 , 4 , 7 , … ; 0 , -1 , -2 , -3 … соответствует вопрос : Первым космонавтом был : 1 ) Юрий Гагарин 2 ) Герман Титов gПравильный = 1 подтипам 2 , 5 , 8 , … - вопрос : Вторым космонавтом был : 1 ) Юрий Гагарин 2 ) Герман Титов gПравильный = 2 подтипам 3 , 6 , 9 , … - вопрос : Из двух первых космонавтов в самолёте разбился : 1 ) Юрий Гагарин 2 ) Герман Титов gПравильный = 1 Сейчас мы убедились , что процедура М с нолевым значением первого аргумента и процедура ББ работают правильно и в том случае , если вариантов вопроса больше чем правильных ответов . Однако процедура М с нолевым значением первого аргумента имеет существенный недостаток : если вариантов вопроса больше чем правильных ответов , то общее число ответов должно быть равно числу правильных ( т.е. не может быть больше ) . Сейчас мы преодолеем этот недостаток . 25) Измените процедуру М , чтобы она выглядела так : Sub М ( zНомерПравильногоОтвета , ParamArray zОтветы ( ) ) ReDim G ( 1 To UBound ( zОтветы ) + 1 ) For k = 0 To UBound ( zОтветы ) G ( k + 1 ) = zОтветы ( k ) Next k Select Case zНомерПравильногоОтвета Case -9 To -2 gПравильный = gПодТипВопроса Mod -zНомерПравильногоОтвета + 1 Case 0 gПравильный = gПодТипВопроса Mod k + 1 Case 1 To 9 gПравильный = zНомерПравильногоОтвета End Select End Sub 26) В операторе Select Case zТипВопроса процедуры Г Case 16 ББ "Первым космонавтом был :" , _ "Вторым космонавтом был :" , _ "Из двух первых космонавтов в самолёте разбился :" М 0 , "Юрий Гагарин" , "Герман Титов" П 5 замените на Case 16 ББ "Первым космонавтом был :" , _ "Вторым космонавтом был :" , _ "Из двух первых космонавтов в самолёте разбился :" М -2 , "Юрий Гагарин" , "Герман Титов" , _ "Юрий Титов" , "Герман Гагарин" П 5 27) Повторите пункты 23 , 24 и убедитесь , что подтипам 1 , 4 , 7 , … ; 0 , - 1 , - 2 , - 3 , … соответствует вопрос : Первым космонавтом был : 1 ) Юрий Гагарин 2 ) Герман Титов 3 ) Юрий Титов 4 ) Герман Гагарин gПравильный = 1 подтипам 2 , 5 , 8 , … - вопрос : Вторым космонавтом был : 1 ) Юрий Гагарин 2 ) Герман Титов 3 ) Юрий Титов 4 ) Герман Гагарин gПравильный = 2 подтипам 3 , 6 , 9 , … - вопрос : Из двух первых космонавтов в самолёте разбился : 1 ) Юрий Гагарин 2 ) Герман Титов 3 ) Юрий Титов 4 ) Герман Гагарин gПравильный = 1 Сейчас мы выполнили третий шаг настоящего урока : модифицировали процедуру М таким образом , что преодолели её недостаток при нолевом значении её первого аргумента ; теперь мы можем задать любое число вариантов ответа , даже если число вариантов вопроса больше числа правильных ( разных ) ответов . При выполнении пункта 22 мы столкнулись с небольшим , но неприятным недостатком нашего шаблона : первый и второй варианты вопроса имеют довольно большую общую часть “ космонавтом был : ” , которую мы вынуждены были повторить дважды , так как в третий вариант вопроса она не входит , ( если бы третий вариант вопроса , подобно первому и второму , кончался на “ космонавтом был : ” , то можно было бы после процедуры ББ поставить строку Б “ космонавтом был:” ) . Было бы приятно иметь процедуру , которая бы вставляла общую часть вариантов вопроса и в том случае , если эта общая часть является общей не для всех вариантов вопроса . Четвёртый шаг настоящего урока состоит в написании и тестировании такой процедуры . В конкретном данном случае от её применения мы не получим большого выигрыша , но при большем числе вариантов вопроса польза от её применения может быть значительной . При написании программы главное внимание , конечно , надо уделять продумыванию общей её структуры и её ключевых моментов - очевидно очень эффективных приёмов ( с такими очевидно очень эффективными приёмами мы познакомимся на двух следующих уроках ) . Однако не следует пренебрегать и “ мелочной ” мыслью , если она приходит в голову : большое число мелочей в сумме могут дать большой эффект ; кроме того , что вначале кажется мелочью , потом может оказаться очень важным ; если какая-то мысль приходит нам в голову , то Богу или иным сущностям это зачем-то нужно . 28) В модуль А введите новую процедуру : Sub Б2 ( zВариантовВопроса , zСкакого , zПоКакой , ParamArray zТекстЧисло ( ) ) Z = gПодТипВопроса Mod zВариантовВопроса + 1 If Z >= zСкакого And Z <= zПоКакой Then For k = 0 To UBound ( zТекстЧисло ) If k Mod 2 = 0 Then Selection.TypeText zТекстЧисло ( k ) Else Б Chr ( zТекстЧисло ( k ) ) End If Next k End If End Sub Для понимания первой строки тела процедуры нужно знать порядок выполнения арифметических операций : В VBA в первую очередь выполняется возведение в степень ( ^ ) . Во вторую очередь - смена знака ( - ) . В третью очередь - умножение ( * ) и обычное деление ( / ) . В четвёртую очередь - деление нацело ( \ ) . В пятую очередь - нахождение остатка от деления нацело ( mod ) . В шестую , последнюю очередь - сложение ( + ) и вычитание ( - ) . В выражении gПодТипВопроса Mod zВариантовВопроса + 1 сначала находится остаток , потом - прибавление единицы , так как операция mod имеет больший приоритет чем операция + . >= - знак больше или равно ; <= - знак меньше или равно . 29) В операторе Select Case zТипВопроса процедуры Г Case 16 ББ "Первым космонавтом был :" , _ "Вторым космонавтом был :" , _ "Из двух первых космонавтов в самолёте разбился :" М -2 , "Юрий Гагарин" , "Герман Титов" , _ "Юрий Титов" , "Герман Гагарин" П 5 замените на Case 16 ББ "Первым" , "Вторым" , _ "Из двух первых космонавтов в самолёте разбился :" Б2 3 , 1 , 2 , " космонавтом был :" М -2 , "Юрий Гагарин" , "Герман Титов" , _ "Юрий Титов" , "Герман Гагарин" П 5 30) Повторите пункт 27 - если Вы всё сделали правильно , то получите те же самые варианты вопроса , соответствующие тем же подтипам . Процедуры Б и Б2 содержат довольно большую общую часть кода , которую разумно вставить в новую процедуру и затем вызывать эту процедуру из Б и Б2 . 31) В модуль А введите новую процедуру : Sub БА ( zТекстЧисло , zUBound , Optional zУсловиеВыполнения = True ) If Not zУсловиеВыполнения Then Exit Sub For k = 0 To zUBound If k Mod 2 = 0 Then Selection.TypeText zТекстЧисло ( k ) Else Б Chr ( zТекстЧисло ( k ) ) End If Next k End Sub 32) Измените процедуры Б и Б2 , чтобы они выглядели так : Sub Б ( ParamArray zТекстЧисло ( ) ) Z = zТекстЧисло ( ) БА Z , UBound ( Z ) End Sub Sub Б2 ( zВариантовВопроса , zСкакого , zПоКакой , ParamArray zТекстЧисло ( ) ) Z = gПодТипВопроса Mod zВариантовВопроса + 1 ZZ = zТекстЧисло ( ) БА ZZ , UBound ( ZZ ) , Z >= zСкакого And Z <= zПоКакой End Sub 33) Повторите пункт 27 - если Вы всё сделали правильно , то получите те же самые варианты вопроса , соответствующие тем же подтипам . 34) В начале модуля А строку Public G ( ) замените на Public G ( ) , GG 35) Измените процедуры БА , Б , Б2 , чтобы они выглядели так : Sub БА ( Optional zУсловиеВыполнения = True ) If Not zУсловиеВыполнения Then Exit Sub For k = 0 To UBound ( GG ) If k Mod 2 = 1 Then GG ( k ) = Chr ( GG ( k ) ) Selection.TypeText GG ( k ) Next k End Sub Sub Б ( ParamArray zТекстЧисло ( ) ) GG = zТекстЧисло БА End Sub Sub Б2 ( zВариантовВопроса , zСкакого , zПоКакой , ParamArray zТекстЧисло ( ) ) Z = gПодТипВопроса Mod zВариантовВопроса + 1 GG = zТекстЧисло БА Z >= zСкакого And Z <= zПоКакой End Sub 36) Повторите пункт 27 - если Вы всё сделали правильно , то получите те же самые варианты вопроса , соответствующие тем же подтипам . Сейчас Вы познакомились с примерами правильной передачи массива , заданного ключом ParamArray , в другую процедуру . Попробуйте передать такой массив иным образом - скорей всего , у Вас ничего не получится . Так как мы научились быстро ( коротким программным кодом ) вызывать процедуру БА , должным образом работающую с массивом zТекстЧисло , то легко и “ дёшево ” ( без значительного увеличения размера шаблона в байтах ) можем писать модификации процедуры Б . 37) В модуль А введите новую процедуру Sub Б4 ( zПоКакой , ParamArray zТекстЧисло ( ) ) GG = zТекстЧисло БА gПодТипВопроса < zПоКакой End Sub 38) В куске программного кода Case 16 ББ "Первым" , "Вторым" , _ "Из двух первых космонавтов в самолёте разбился :" Б2 3 , 1 , 2 , " космонавтом был :" М -2 , "Юрий Гагарин" , "Герман Титов" , _ "Юрий Титов" , "Герман Гагарин" П 5 оператора Select Case zТипВопроса процедуры Г строку Б2 3 , 1 , 2 , " космонавтом был :" замените на Б4 2 , " космонавтом был :" 39) Повторите пункт 27 - если Вы всё сделали правильно , то получите те же самые варианты вопроса , соответствующие тем же подтипам . Четвёртый шаг настоящего урока выполнен . Пятый шаг будет состоять в изменении процедуры П . Третьему подтипу шестнадцатого типа вопроса соответствует вопрос более длинный чем второму и первому подтипам . Пауза же для всех этих подтипов одинакова , хотя для прочтения более длинного третьего подтипа ученику , естественно , требуется больше времени . Цель пятого шага - так изменить процедуру П , чтобы она позволяла задавать разные паузы разным подтипам . 40) Измените процедуру П , чтобы она выглядела так : Sub П ( ParamArray zПаузы ( ) ) If gНаВремя Then ЗадатьМножительПаузы gМножительПаузы < 0.5 Or gМножительПаузы > 10 gПауза = zПаузы ( gПодТипВопроса Mod ( UBound ( zПаузы ) + 1 ) ) * gМножительПаузы End If End Sub 41) В куске программного кода Case 16 ББ "Первым" , "Вторым" , _ "Из двух первых космонавтов в самолёте разбился :" Б4 2 , " космонавтом был :" М -2 , "Юрий Гагарин" , "Герман Титов" , _ "Юрий Титов" , "Герман Гагарин" П 5 оператора Select Case zТипВопроса процедуры Г строку П 5 замените на П 5 , 5 , 15 42) В процедуре ДД строку Д 3 , 0 замените на Д 3 , 16 43) На панели История несколько раз нажав Д и задавая диалог 3 , убедитесь , что вопрос подтипа 1 , как и вопрос подтипа 2 , появляется на экране на 5 секунд , а вопрос подтипа 3 - на 15 . Мы задали различающие в три раза паузы , чтобы легко убедиться , что они действительно разные . Но теперь мы убедились и нам незачем задавать настолько различающиеся паузы . Поэтому : 44) Строку П 5 , 5 , 15 замените на П 5 , 5 , 7 Пятый шаг настоящего урока выполнен . Шестой шаг настоящего урока - логическое продолжение третьего шага . Если шестнадцатый тип вопроса разбить на большее число подтипов , не меняя нашей “ технологии ” , т.е. просто увеличив число аргументов процедуры ББ , то число ответов “ Юрий Гагарин ” будет примерно равно числу ответов “ Герман Титов ” . Если аргументов процедуры ББ будет три ( как в сделанном нами случае ) , то ответов “ Юрий Гагарин ” будет 2 , а ответов “ Герман Титов ” - 1 . Если аргументов процедуры ББ будет 4 , то ответов “ Юрий Гагарин ” будет 2 и ответов “ Герман Титов ” - тоже 2 . Если аргументов процедуры ББ будет 5 , то ответов “ Юрий Гагарин ” будет 3 , ответов “ Герман Титов ” - 2 . Если аргументов процедуры ББ будет 6 , то ответов “ Юрий Гагарин ” будет 3 и ответов “ Герман Титов ” - тоже 3 . … Если учитель желает больше внимания уделить Юрию Гагарину , т.е. составить больше вопросов с правильным ответом “ Юрий Гагарин ” чем с правильным ответом “ Герман Титов ” , то ему придётся использовать какую-то другую технологию , т.е. использовать какую-то возможность , которую мы ему пока не предоставили . Одну из таких возможностей мы сейчас и предоставим . 45) В модуль А введите новую процедуру : Sub ББ4 ( ParamArray zВопросНомерответа ( ) ) Z = zВопросНомерответа ZZ = ( gПодТипВопроса Mod ( UBound ( Z ) + 1 ) \ 2 ) * 2 Б Z ( ZZ ) gПравильный = Z ( ZZ + 1 ) End Sub 46) В операторе Select Case zТипВопроса процедуры Г Case 3 Б "Индия была колонией :" М 4 , "Франции" , "Германии" , "России" , "Англии" , "Испании" , _ "Италии" , "Швеции" П 7 замените на Case 3 ББ4 "В 1913 году Финляндия была в составе" , 3 , _ "В 1699 году территория современного Санкт-Петербурга" & _ " была в составе" , 7 , _ "Наполеон был императором" , 1 , _ "Индия была колонией" , 4 , _ "В январе 1649 года Оливер Кромвель казнил короля" , 4 , _ "В 1952 году Уинстон Леонард Спенсер Черчилль был " & _ "премьер-министром" , 4 Б " :" М -1 , "Франции" , "Германии" , "России" , "Англии" , "Испании" , _ "Италии" , "Швеции" П 7 47) Проверьте третий тип вопроса и убедитесь , что подтипам 1 , 7 , 13 , … ; 0 , - 1 , - 2 , - 3 , … соответствует вопрос : В 1913 году Финляндия была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 3 подтипам 2 , 8 , 14 , … - вопрос : В 1699 году территория современного Санкт-Петербурга была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 7 подтипам 3 , 9 , 15 , … - вопрос : Наполеон был императором : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 1 подтипам 4 , 10 , 16 , … - вопрос : Индия была колонией : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции Правильный = 4 подтипам 5 , 11 , 17 , … - вопрос : В январе 1649 года Оливер Кромвель казнил короля : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 4 подтипам 6 , 12 , 18 , … - вопрос : В 1952 году Уинстон Леонард Спенсер Черчилль был премьер-министром : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 4 48) Пока варианты вопроса находятся в первоначальном , сравнимом виде , для каждого подтипа третьего типа вопроса задайте свою паузу , т.е. строку П 7 замените на П 8 , 10 , 7 , 7 , 9 , 10 49) Чтобы немного сократить код , ББ4 "В 1913 году Финляндия была в составе" , 3 , _ "В 1699 году территория современного Санкт-Петербурга" & _ " была в составе" , 7 , _ "Наполеон был императором" , 1 , _ "Индия была колонией" , 4 , _ "В январе 1649 года Оливер Кромвель казнил короля" , 4 , _ "В 1952 году Уинстон Леонард Спенсер Черчилль был " & _ "премьер-министром" , 4 замените на ББ4 "В 1913 году Финляндия" , 3 , _ "В 1699 году территория современного Санкт-Петербурга" , 7 , _ "Наполеон был императором" , 1 , _ "Индия была колонией" , 4 , _ "В январе 1649 года Оливер Кромвель казнил короля" , 4 , _ "В 1952 году Уинстон Леонард Спенсер Черчилль был " & _ "премьер-министром" , 4 Б2 6 , 1 , 2 , " была в составе" 50) Повторите пункт 47 . Выполнив урок 21 , Вы : 1) В совершенстве освоили досрочное прерывание работы макроса . 2) Написали и освоили процедуру , позволяющую тестировать разбиение типа вопроса на подтипы . 3) Создали несколько способов разбиения типа вопроса на подтипы . 4) Узнали приоритет ( порядок выполнения ) арифметических операций . Следующий итог К оглавлению
Задача 3 Модификация процедуры ББ4
Строка Б2 6 , 1 , 2 , " была в составе" употреблённая вместо двух была в составе почти не сокращает код . Попробуйте строку Б2 6 , 1 , 2 , " была в составе" заменить на Б4 2 , " была в составе" и протестируйте подтипы 1 , 2 , 7 и 8 третьего типа вопроса - подтипы 1 и 2 останутся прежними , а в подтипах 7 и 8 исчезнет " была в составе" . Так измените процедуру ББ4 , чтобы в подтипах 7 и 8 ( 13 и 14 , 19 и 20 , 25 и 26 и т.д. ) вновь появился текст " была в составе" , ( старый код ББ4 сохраните под именем ББ5 ) . Ответ К оглавлению
Урок 22 Разбиение на подтипы ( продолжение )
К оглавлению 1) Измените процедуру М , чтобы она выглядела так : Sub М ( zНомерПравильногоОтвета , ParamArray zОтветы ( ) ) ReDim G ( 1 To UBound ( zОтветы ) + 1 ) For k = 0 To UBound ( zОтветы ) If IsArray ( zОтветы ( k ) ) Then G( k + 1 ) = zОтветы( k ) (gПодТипВопроса Mod ( UBound ( zОтветы( k ) ) + 1 ) ) Else G ( k + 1 ) = zОтветы ( k ) End If Next k Select Case zНомерПравильногоОтвета Case -9 To -2 gПравильный = gПодТипВопроса Mod -zНомерПравильногоОтвета + 1 Case 0 gПравильный = gПодТипВопроса Mod k + 1 Case 1 To 9 gПравильный = zНомерПравильногоОтвета End Select End Sub IsArray - встроенная функция VBA , равная True , если её аргумент является массивом , и False в противном случае . 2) В операторе Select Case zТипВопроса процедуры Г Case 3 ББ4 "В 1913 году Финляндия" , 3 , _ "В 1699 году территория современного Санкт-Петербурга" , 7 , _ "Наполеон был императором" , 1 , _ "Индия была колонией" , 4 , _ "В январе 1649 года Оливер Кромвель казнил короля" , 4 , _ "В 1952 году Уинстон Леонард Спенсер Черчилль был " & _ "премьер-министром" , 4 Б4 2 , " была в составе" Б " :" М -1 , "Франции" , "Германии" , "России" , "Англии" , "Испании" , _ "Италии" , "Швеции" П 8 , 10 , 7 , 7 , 9 , 10 замените на Case 3 ББ5 "В 1913 году Финляндия" , 3 , _ "В 1699 году территория современного Санкт-Петербурга" , 7 , _ "Наполеон был императором" , 1 , _ "Индия была колонией" , 4 , _ "В январе 1649 года Оливер Кромвель казнил короля" , 4 , _ "В 1952 году Уинстон Леонард Спенсер Черчилль был " & _ "премьер-министром" , 4 Б2 6 , 1 , 2 , " была в составе" Б " :" М -1 , "Франции" , "Германии" , "России" , "Англии" , "Испании" , _ Array ( "Италии" , "Греции" , "Болгарии" , "Турции" , "Монголии" ) , _ "Швеции" П 8 , 10 , 7 , 7 , 9 , 10 Array - встроенная функция VBA , позволяющая задать массив простым перечислением . В нашем случае Array ( "Италии" , "Греции" , "Болгарии" , "Турции" , "Монголии" ) равна массиву из пяти элементов с номерами 0 , 1 , 2 , 3 , 4 ( элемент “Италии” имеет номер 0 , элемент “Монголии” - номер 4 ) . 3) Проверьте третий тип вопроса и убедитесь , что подтипам 1 , 31 , 61 , … ; 0 , - 1 , - 2 , - 3 , … соответствует вопрос : В 1913 году Финляндия была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 3 подтипам 2 , 32 , 62 , … - вопрос : В 1699 году территория современного Санкт-Петербурга была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Греции 7 ) Швеции gПравильный = 7 подтипам 3 , 33 , 63 , … - вопрос : Наполеон был императором : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Болгарии 7 ) Швеции gПравильный = 1 подтипам 4 , 34 , 64 , … - вопрос : Индия была колонией : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Турции 7 ) Швеции gПравильный = 4 подтипам 5 , 35 , 65 , … - вопрос : В январе 1649 года Оливер Кромвель казнил короля : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Монголии 7 ) Швеции gПравильный = 4 подтипам 6 , 36 , 66 , … - вопрос : В 1952 году Уинстон Леонард Спенсер Черчилль был премьер-министром : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Италии 7 ) Швеции gПравильный = 4 подтипам 7 , 37 , 67 , … - вопрос : В 1913 году Финляндия была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Греции 7 ) Швеции gПравильный = 3 подтипам 8 , 38 , 68 , … - вопрос : В 1699 году территория современного Санкт-Петербурга была в составе : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Болгарии 7 ) Швеции gПравильный = 7 подтипам 9 , 39 , 69 , … - вопрос : Наполеон был императором : 1 ) Франции 2 ) Германии 3 ) России 4 ) Англии 5 ) Испании 6 ) Турции 7 ) Швеции gПравильный = 1 Продолжая аналогично проверять подтипы , убедитесь , что третий вопрос имеет ровно 30 ( = 5 • 6 ) разных подтипов . Выполнив урок 22 , Вы узнали : 1) IsArray 2) Array 3) Что элемент массива в свою очередь может быть массивом . Обратите внимание , как в процедуре М - см. пункт 1 - мы вызвали элемент массива , который ( массив ) сам является элементом массива : сначала мы вызвали внутренний массив ( набрали имя внешнего массива , открыли скобки , указали номер внутреннего массива , закрыли скобки ) , затем - сам элемент ( открыли вторую пару скобок , указали номер элемента , закрыли вторую пару скобок ) . Следующий итог К оглавлению
Задача 4 Наименьшее общее кратное
1) В третьем случае оператора Select Case zТипВопроса процедуры Г строку Array ( "Италии" , "Греции" , "Болгарии" , "Турции" , "Монголии" ) , _ замените на Array ( "Италии" , "Греции" , "Болгарии" , "Турции" ) , _ 2) Проверьте третий тип вопроса и убедитесь , что он имеет только 12 разных подтипов . Подумайте , почему подтипов 12 , а не 24 ( = 6 • 4 ) . 3) Верните процедуру Г к предыдущему состоянию со строкой Array ( "Италии" , "Греции" , "Болгарии" , "Турции" , "Монголии" ) , _ К оглавлению
Задача 5 Модификация Б2
Под именем Б5 в модуль А введите модификацию процедуры Б2 такую , чтобы в третьем случае оператора Select Case zТипВопроса процедуры Г строку Б2 6 , 1 , 2 , " была в составе" можно было заменить на Б5 6 , 2 , " была в составе" Ответ К оглавлению
Урок 23 Разбиение на подтипы ( продолжение )
На сегодняшнем уроке мы создадим вопрос , который будет иметь более четырёх тысяч подтипов . К оглавлению 1) В модуль А введите новую процедуру : Sub ББ2 ( ParamArray zВарианты ( ) ) Б zВарианты ( gПодТипВопроса Mod ( UBound ( zВарианты ) + 1 ) ) End Sub 2) В оператор Select Case zТипВопроса процедуры Г введите новый случай : Case 22 ББ2 "В ХХ веке президентом США" , _ "В составе ""Битлз""" , _ "Генеральным секретарём ЦК КПСС" Б " был :" М -3 , Array ( "Теодор Рузвельт" , _ "Франклин Делано Рузвельт" , _ "Джон Кеннеди" , "Джеймс Картер" , _ "Билл Клинтон" , "Джордж Буш" , _ "Рональд Рейган" ) , _ Array ( "Джон Леннон" , "Пол Маккартни" , _ "Джордж Харрисон" , "Ринго Стар" ) , _ Array ( "Иосиф Сталин" , "Леонид Брежнев" , _ "Юрий Андропов" , "Константин Черненко" , _ "Михаил Горбачёв" ) , _ Array ( "Василий Сталин" , "Катрин Денёв" , _ "Андрей Губин" , "Андрей Макаревич" , _ "Мик Джагер" , "Борис Гребенщиков" , _ "Владимир Ленин" , "Борис Ельцин" , _ "Дмитрий Менделеев" , "Александр Керенский" , _ "Сергей Королёв" ) П 3 3) Проверьте 20 … 40 подтипов 22-го типа вопроса и убедитесь , что сам вопрос имеет период 3 , первый вариант ответа ( президенты США ) - период 7 , второй вариант ответа ( члены “ Битлз ” ) - период 4 , третий вариант ответа ( генеральные секретари ) - период 5 , четвёртый вариант ответа ( ответы , не являющиеся правильными ни для какого варианта вопроса ) - период 11 . Числа 3 ; 7 ; 4 ; 5 ; 11 - взаимно простые . Поэтому общее число разных подтипов 22-го вопроса равно 3 • 7 • 4 • 5 • 11 = 4620 . Выполнив урок 23 , Вы научились создавать тип вопроса с очень большим числом подтипов ( Вам легко ещё в 13 - или 17 , 23 , 29 , … - раз увеличить число разных подтипов 22-го вопроса , введя пятый вариант ответа , подобный четвёртому ) . Следующий итог К оглавлению
Урок 24 Разбиение на подтипы ( продолжение )
Хотя группа “ Битлз ” всегда состояла из четырёх человек , всего “ битлов ” было пять : до Ринго Стара барабанщиком был Питер Бест . Однако если во второй вариант вопроса просто добавить “ Питер Бест ” , это будет плохо , так как в четыре раза сократится число разных подтипов вопроса , так как число указанных “ битлов ” сравняется с числом генеральных секретарей . К оглавлению 1) В процедуре М If IsArray ( zОтветы ( k ) ) Then G ( k + 1 ) = zОтветы ( k ) ( gПодТипВопроса Mod ( UBound ( zОтветы ( k ) ) + 1 ) ) замените на If IsArray ( zОтветы ( k ) ) Then If IsNumeric ( zОтветы ( k ) ( 0 ) ) Then G ( k + 1 ) = zОтветы ( k ) ( gПодТипВопроса Mod zОтветы ( k ) ( 0 ) _ Mod ( UBound ( zОтветы ( k ) ) ) + 1 ) Else G ( k + 1 ) = zОтветы ( k ) ( gПодТипВопроса Mod ( UBound ( zОтветы ( k ) ) + 1 ) ) End If 2) В 22-ом случае оператора Select Case zТипВопроса процедуры Г Array ( "Джон Леннон" , "Пол Маккартни" , _ "Джордж Харрисон" , "Ринго Стар" ) , _ замените на Array ( 8 , "Джон Леннон" , "Пол Маккартни" , _ "Джордж Харрисон" , "Ринго Стар" , "Питер Бест" ) , _ 3) Проверьте 20 … 40 подтипов 22-го типа вопроса и убедитесь , что второй вариант ответа ( члены “ Битлз ” ) имеет период 8 , третий вариант ответа ( генеральные секретари ) - по-прежнему период 5 . К оглавлению
Задача 6 Число разных подтипов
Сколько разных подтипов имеет 22-й вопрос сейчас ? Ответ К оглавлению
Урок 25 Разбиение на подтипы ( продолжение )
Настоящий урок - логическое продолжение шестого шага урока 21 . Тогда мы ввели процедуру , позволяющую каждому варианту вопроса сопоставить номер правильного ответа . Сейчас мы введём процедуру , позволяющую каждому варианту вопроса сопоставить текст правильного ответа . К оглавлению 1) В начале модуля А Public gПравильный , gВерных , gНеверных , gПропущенных замените на Public gПравильный , gОтвет Public gВерных , gНеверных , gПропущенных 2) В модуль А введите 2 новые процедуры : Sub ББ7 ( ParamArray zВопросОтвет ( ) ) Z = zВопросОтвет gПодТипВопроса = gПодТипВопроса Mod ( UBound ( Z ) + 1 ) \ 2 ZZ = gПодТипВопроса * 2 Б Z ( ZZ ) gОтвет = Z ( ZZ + 1 ) End Sub Sub ББ8 ( ParamArray zВопросОтвет ( ) ) Z = zВопросОтвет ZZ = ( gПодТипВопроса Mod ( UBound ( Z ) + 1 ) \ 2 ) * 2 Б Z ( ZZ ) gОтвет = Z ( ZZ + 1 ) End Sub 3) В операторе Select Case zТипВопроса процедуры Г Case 20 Б "Первым американским космонавтом был :" М 3 , "Джон Кеннеди" , "Пол Маккартни" , "Джон Гленн" П 5 замените на Case 20 ББ8 "Первым" , "Юрий Гагарин" , _ "Первым американским" , "Джон Гленн" , _ "Вторым" , "Герман Титов" Б " космонавтом был :" М 3 , _ Array ( "Джон Кеннеди" , "Пол Маккартни" , "Билл Гейтс" , "Исаак Ньютон" ) , _ Array ( "Владимир Комаров" , "Алексей Леонтьев" , "Борис Стругацкий" , _ "Александр Пушкин" , "Михаил Ломоносов" ) , _ gОтвет П 5 4) Проверьте 20 … 40 подтипов 20-го типа вопроса и убедитесь , что сам вопрос и соответствующий ему третий вариант ответа имеют период 3 ; первый вариант ответа - период 4 ; второй вариант ответа - период 5 . К оглавлению
Задача 7 Число разных подтипов
Сколько разных подтипов имеет 20-й вопрос сейчас ? К оглавлению
Урок 26 Разбиение на подтипы ( конец )
Мы уже имеем много возможностей вставлять в вопросы их общую часть . Однако варианты ответа вынуждены перечислять в полном виде , даже если они имеют большую общую часть . На сегодняшнем уроке мы дадим себе ( и специалисту-историку , который , возможно , захочет наполнить наш шаблон “ реальным содержанием ” ) возможность более кратко задавать перечень вариантов ответа , если они имеют общую часть . К оглавлению 1) В модуль А введите новую процедуру : Sub ММ ( Optional zНачало = "" , Optional zКонец = "" , _ Optional zСкакого = 1 , Optional zПоКакое = 0 ) For k = zСкакого To IIf ( zПоКакое = 0 , UBound ( G ) , zПоКакое ) G ( k ) = zНачало & G ( k ) & zКонец Next k End Sub 2) В операторе Select Case zТипВопроса процедуры Г Case 5 Б "Крестоносцев победил :" М 1 , "Александр Невский" , "Александр Македонский" , _ "Александр Третий" П 3 замените на Case 5 ББ "Учеником Аристотеля" , "Российским императором" , "Крестоносцев победил :" Б4 2 , " был :" М 0 , "Македонск" , "Трет" , "Невск" ММ "Александр " , "ий" П 3 3) Проверьте 10 … 20 подтипов 5-го типа вопроса и убедитесь , что он имеет три и только три разных подтипа : Учеником Аристотеля был : 1 ) Александр Македонский 2 ) Александр Третий 3 ) Александр Невский gПравильный = 1 Российским императором был : 1 ) Александр Македонский 2 ) Александр Третий 3 ) Александр Невский gПравильный = 2 Крестоносцев победил : 1 ) Александр Македонский 2 ) Александр Третий 3 ) Александр Невский gПравильный = 3 На уроках с 20 по 26 мы создали и протестировали много способов разбиения типа вопроса на подтипы . Этих способов вполне достаточно , так как они позволяют разбить тип вопроса на тысячи и даже миллионы подтипов . На 20-м уроке мы поставили перед собой три задачи : 1) Типы вопросов разбить на подтипы . 2) Написать процедуру , которая бы писала ( не на краткое время , а “ на совсем ” ) проверочные , предназначенные для распечатки на бумаге . 3) Создать систему навигации по этим проверочным ( так как типов и подтипов вопросов можно ввести много и их можно по-разному комбинировать , то проверочных запрограммировать можно невероятно много ) . Первый пункт мы выполнили ( точнее , мы создали способы разбиения на подтипы , которыми относительно легко пользоваться ) . Со следующего урока перейдём к выполнению 2-го пункта . Следующий итог К оглавлению
Урок 27 Процедура , задающая 2 целых числа по десятичной дроби
В дальнейшем мы введём процедуру ГГ , которая будет задавать перечень вопросов простым перечислением ( например , ГГ 2.23 , 15.93 , 1.297 ) , в котором целые части будут задавать типы вопросов , а дробные - подтипы . Однако такой способ задания целых чисел мы уже используем в процедуре Д . Значит , такой способ мы будем использовать по меньшей мере дважды . Поэтому разумно вынести его в отдельную процедуру . К оглавлению 1) В модуль А введите новую процедуру : Sub ДваЦелыхЧислаИзДесятичнойДроби ( zДробь , _ zЦелаяЧасть , zИзДробнойЧасти , zИзНолевойДробной ) Dc = CDec ( zДробь ) zЦелаяЧасть = Int ( Dc ) zИзДробнойЧасти = Dc - zЦелаяЧасть If zИзДробнойЧасти = 0 Then zИзДробнойЧасти = zИзНолевойДробной Else While zИзДробнойЧасти - Int ( zИзДробнойЧасти ) > 0 _ And zИзДробнойЧасти - Int ( zИзДробнойЧасти ) <> 0.1 zИзДробнойЧасти = 10 * zИзДробнойЧасти Wend zИзДробнойЧасти = Int ( zИзДробнойЧасти ) End If End Sub 2) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) ДваЦелыхЧислаИзДесятичнойДроби 5 , k2 , k4 , k2 Б k2 & " ; " & k4 , 11 End Sub 3) Нажмите Проверка - на экране появится строка 5 ; 5 4) В макросе Проверка 5 замените на 5.2 , нажмите Проверка - появится строка 5 ; 2 5) В макросе Проверка 5.2 замените на 5.1 , нажмите Проверка - появится строка 5 ; 0 6) В макросе Проверка 5.1 замените на 5.11 , нажмите Проверка - появится строка 5 ; 1 7) В процедуре Д For k = 0 To Ubound ( zТипыВопросов ) Dc = CDec ( zТипыВопросов ( k ) ) k2 = Int ( Dc ) k4 = Dc - k2 If k4 = 0 Then Г k2 , True , Timer , Timer Else While k4 - Int ( k4 ) > 0 And k4 - Int ( k4 ) <> 0.1 k4 = 10 * k4 Wend k4 = Int ( k4 ) For kk = k2 To k4 Step IIf ( k2 > k4 , - 1 , 1 ) Г kk , True , Timer , Timer Next kk End If Next k замените на For k = 0 To Ubound ( zТипыВопросов ) ДваЦелыхЧислаИзДесятичнойДроби zТипыВопросов ( k ) , k2 , k4 , k2 For kk = k2 To k4 Step IIf ( k2 > k4 , -1 , 1 ) Г kk , True , Timer , Timer Next kk Next k 8) Несколько раз нажмите Д на панели История и убедитесь , что все наши диалоги ( с первого по третий ) работают почти по-прежнему или , если не помните старую их работу или не можете её представить после разбиения некоторых вопросов на подтипы , что они работают “ нормально ” . Вы могли бы не спеша , “ корректно ” , сравнить старую и новую работы процедуры Д , при введении новой версии оператора For k = 0 To Ubound ( zТипыВопросов ) сохранив старую , чтобы сначала вызвать тот или иной диалог , закомментировав новую версию оператора , ( и таким образом узнать работу диалога при старой версии оператора ) , - потом вызвать тот же диалог , раскомментировав новую версию и закомментировав старую , ( и таким образом узнать работу диалога при новой версии оператора ) . Вы можете и сейчас применить этот метод , скопировав старую версию оператора с дискеты . Однако это очень трудоёмко . Если Вам жалко времени , проверьте хотя бы число вопросов в каждом диалоге при новой версии процедуры Д . Если Вы точно следовали моим указаниям , три диалога в Вашем шаблоне задаются тремя строками процедуры ДД : Д 1 , 12 , 0 , 7 , 20.16 Д 2 , 1.6 , 8.111 , 13.15 Д 3 , 16 Первая из этих трёх строка задаёт первый диалог ( первое число - номер диалога ) , состоящий из 8-и вопросов : 12-го , нолевого , 7-го и с 20-го по 16-й . Вторая строка задаёт второй диалог , состоящий из 13-и вопросов : с 1-го по 6-й , с 8-го по 11-й , с 13-го по 15-й . Третья строка задаёт третий диалог , состоящий только из одного , 16-го вопроса . Наш набор диалогов плох : во-первых , он охватывает не все вопросы ; во-вторых , третий диалог входит в первый . Поэтому : 9) В процедуре ДД строку Д 3 , 16 замените на Д 3 , 21.22 10) Вызовите третий диалог и убедитесь , что он состоит из двух вопросов и эти вопросы именно 21-й и 22-й ( чтобы хорошо представить возможные варианты содержания этих вопросов , посмотрите соответствующие случаи - Case - в процедуре Г ) . Выполнив урок 27 , Вы узнали относительно короткий , но эффективный код процедуры ДваЦелыхЧислаИзДесятичнойДроби , позволяющей десятичной дробью задать 2 целых числа . Эта процедура может быть очень полезна не только для нашего шаблона , но и для других Ваших шаблонов . Эта процедура полезна всегда , когда при долгом перечислении ( ключ ParamArray ) требуется ввести 2 целых числа , по-разному интерпретируемых . В частности она полезна , если требуется задать “ тип ” и “ подтип ” какой-нибудь процедуры или диапазон ( с такого-то по такой-то ) целых чисел . Следующий итог К оглавлению
Урок 28 Первый тип контрольной
К оглавлению 1) В модуль А введите новую процедуру : Sub ГГ ( ParamArray Типы ( ) ) For k = 0 To Ubound ( Типы ) ДваЦелыхЧислаИзДесятичнойДроби Типы ( k ) , zТип , zПодТип , 1 Г zТип , , , zПодТип Next k End Sub 2) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) ГГ 22.3 , 21 , 20.2 , 19 End Sub 3) Нажмите Проверка на панели История - появится 4 вопроса . 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 22 , , , 3 End Sub Закройте окно Редактора , установите курсор на пустую строку между первым и вторым вопросом , нажмите Проверка и убедитесь , что появился тот же самый подтип вопроса . 5) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 22 , , , 2 End Sub Закройте окно Редактора , нажмите Проверка и убедитесь , что появился другой подтип вопроса . К оглавлению
Урок 29 Нумерация вопросов
К оглавлению 1) В начале модуля А Public G ( ) , GG замените на Public G ( ) , GG Public gk 2) В процедуре Г Optional zПодТипВопроса = 1 ) gПодТипВопроса = zПодТипВопроса - 1 If gПодТипВопроса < 0 Then gПодТипВопроса = 0 gНаВремя = zНаВремя Б Chr ( 13 ) Selection.Font.Italic = False замените на Optional zПодТипВопроса = 1 , _ Optional zНумероватьВопросы = False ) gПодТипВопроса = zПодТипВопроса - 1 If gПодТипВопроса < 0 Then gПодТипВопроса = 0 gНаВремя = zНаВремя Б Chr ( 13 ) Selection.Font.Italic = False If zНумероватьВопросы Then Б gk + 1 & ") " 3) Измените процедуру ГГ , чтобы она выглядела так : Sub ГГ ( zНумероватьВопросы , ParamArray Типы ( ) ) For gk = 0 To Ubound ( Типы ) ДваЦелыхЧислаИзДесятичнойДроби Типы ( gk ) , zТип , zПодТип , 1 Г zТип , , , zПодТип , zНумероватьВопросы Next gk End Sub 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) ГГ True , 22.3 , 21 , 20.2 , 19 End Sub 5) Нажмите Проверка на панели История - появятся знакомые Вам ( по прошлому уроку ) вопросы , но пронумерованные . К оглавлению
Урок 30 Автоматическое создание макроса
Когда мы выводим вопросы в диалоговом режиме на время , почти необходимо варианты ответа нумеровать . Однако в контрольной на бумаге обычно удобнее иметь перед вариантом ответа не номер , а квадратик ( в который ученик может поставить галочку ) . На настоящем уроке мы сделаем шаг к тому , чтобы компьютер умел вставлять вместо номера квадратик . К оглавлению 1) Указатель мыши подведите к верхнему краю экрана - появится головное меню . Левой кнопкой мыши нажмите Сервис , Параметры - появится диалоговое окно Параметры . 2) Левой кнопкой мыши нажмите слово Вид в верхнем левом углу этого диалогового окна . 3) В нижнем левом углу этого диалогового окна левой кнопкой мыши поставьте галочку перед словами “ строка состояния ” , в этом же диалоговом окне левой кнопкой мыши нажмите ОК - в низу экрана появится строка состояния . 4) Левой кнопкой мыши дважды нажмите ЗАП в строке состояния - появится маленькое диалоговое окно “ Запись макроса ” . 5) В этом диалоговом окне левой кнопкой мыши нажмите стрелку вниз - раскроется список , левой кнопкой мыши нажмите “ Документов , основанных на История.dot ” . 6) Левой кнопкой мыши нажмите ОК - появится маленькая панель с двумя кнопками и заголовком “ Остано... ” . Сейчас мы приготовили компьютер к тому , чтобы записать макрос по принципу “ Делай как я ” . 7) Указатель мыши подведите к верхнему краю экрана - появится головное меню . Левой кнопкой мыши нажмите Вставка , Символ - появится диалоговое окно Символ . 8) В левом верхнем углу этого диалогового окна левой кнопкой мыши нажмите Символы . 9) Левой кнопкой мыши установите : Шрифт: (обычный текст) Набор: Геометрические фигуры 10) Найдите ячейку с крупным полым квадратом ( скорей всего , она будет седьмой слева ) и левой кнопкой мыши нажмите её . Левой кнопкой мыши нажмите Вставить , Закрыть - в текст вставится квадратик , а диалоговое окно Символ закроется . 11) На панельке “ Остано... ” левой кнопкой мыши нажмите левую кнопку ( “ Остановить запись ” ) - панелька “ Остано… ” уберётся с экрана , автоматическая запись макроса кончится . 12) Открыв окно Редактора ( Alt F11 ) , откройте окно проекта ( Ctrl R ) и убедитесь , что в проекте А(История) появился новый модуль - NewMacros . Дважды нажав левой кнопкой мыши имя этого модуля , откройте его - Вы увидите , что он состоит только из одного макроса , похожего на Sub Макрос1 ( ) ' ' Макрос1 Макрос ' Макрос записан 05.04.02 Иван ' Selection.InsertSymbol CharacterNumber:=9633 , Unicode:=True End Sub Я оговорился : “ похожего на ” , так как , скорей всего , в Вашем макросе будет другой комментарий . Однако всё остальное ( первая , последняя и предпоследняя строки ) , скорей всего , будет то же самое . 13) Для этого макроса на панели История создайте кнопку Макрос . 14) Левой кнопкой мыши несколько раз нажмите эту кнопку - на экране появится столько квадратиков , сколько раз Вы нажали кнопку . 15) В этом макросе ( “ Маскрос1 ” ) уберите комментарий , Макрос1 станет выглядеть так : Sub Макрос1 ( ) Selection.InsertSymbol CharacterNumber:=9633 , Unicode:=True End Sub 16) Закройте окно Редактора , на клавиатуре нажмите Enter , левой кнопкой мыши несколько раз нажмите Макрос и убедитесь , что работа макроса не изменилась . 17) Открыв окно Редактора , установите курсор сразу после Selection.InsertSymbol , на клавиатуре нажмите Delete и сразу же Пробел - появится окошечко с надписью “ InsertSymbol ( CharacterNumber As Long , [ Font ] , [ Unicode ] , [ Bias ] ) ”. Благодаря этому окошечку мы узнали , что CharacterNumber является первым аргументом , а Unicode - третим . 18) Измените Макрос1 , чтобы он выглядел так : Sub Макрос1 ( ) Selection.InsertSymbol 9633 , , True End Sub Убедитесь , что работа макроса не изменилась . Выполнив урок 30 , Вы научились автоматически записывать макрос по принципу “ Делай как я ” и дорабатывать макрос , записанный автоматически . Автоматическая запись макроса часто оказывает большую ( а иногда и незаменимую ) помощь программисту , так как , создавая “ черновой ” вариант макроса , даёт сведения по VBA , которые бывает трудно или просто невозможно получить иным образом . Например , мы сейчас узнали оператор Selection.InsertSymbol , список его аргументов и конкретный код ( 9633 ) символа квадратик . Следующий итог К оглавлению
Урок 31 Квадратик вместо номера ответа
К оглавлению 1) В начале процедуры Г модуля А Optional zНумероватьВопросы = False ) замените на Optional zНумероватьВопросы = False , _ Optional zКвадратики = False ) 2) В конце той же процедуры Г For k = 1 To Ubound ( G ) Б k & " ) " Б G ( k ) , 11 Next k замените на For k = 1 To Ubound ( G ) If zКвадратики Then Selection.InsertSymbol 9633 , , True Else Б k & " )" End If Б " " & G ( k ) , 11 Next k Строку Selection.InsertSymbol 9633 , , True Вы можете скопировать из макроса Макрос1 модуля NewMakros . 3) Измените процедуру ГГ , чтобы она выглядела так : Sub ГГ ( zНумероватьВопросы , zКвадратики , ParamArray Типы ( ) ) For gk = 0 To Ubound ( Типы ) ДваЦелыхЧислаИзДесятичнойДроби Типы ( gk ) , zТип , zПодТип , 1 Г zТип , , , zПодТип , zНумероватьВопросы , zКвадратики Next gk End Sub 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) ГГ True , True , 22.3 , 21 , 20.2 , 19 End Sub 5) Закройте окно Редактора , левой кнопкой мыши нажмите Проверка - появится четыре вопроса , в которых перед каждым вариантом ответа будет стоять квадратик , а не номер варианта ответа . 6) Распечатайте на принтере эти вопросы и убедитесь , что неудобно , затруднительно уместить галочку в квадратике , так как квадратики слишком малы , ( конечно , можно поставить галочку , выходящую за пределы квадратика , но ученик может не догадаться это сделать ) . Распечатать на принтере Вы , скорей всего , можете , например , следующим образом : □ Включите принтер , вставьте в него стандартный машинописный лист бумаги . □ На клавиатуре нажмите Ctrl и , не отпуская её , латинскую P - появится диалоговое окно Печать . □ На левом краю этого диалогового окна ( примерно посередине между верхом и низом ) найдите слово текущая и левой кнопкой мыши нажмите на него - в переключателе перед этим словом появится точка ; это значит , что будет напечатана только одна страница ( та , на которой находится курсор ) . □ В правом нижнем углу этого диалогового окна левой кнопкой мыши нажмите ОК - страница , на которой находится курсор , будет напечатана ; диалоговое окно уберётся с экрана . 7) В конце процедуры Г For k = 1 To Ubound ( G ) If zКвадратики Then Selection.InsertSymbol 9633 , , True Else Б k & " )" End If Б " " & G ( k ) , 11 Next k замените на For k = 1 To Ubound ( G ) If zКвадратики Then Selection.Font.Size = 34 Selection.InsertSymbol 9633 , , True Selection.Font.Size = 16 Else Б k & " )" End If Б " " & G ( k ) , 11 Next k 8) Закройте окно Редактора , очистите экран , левой кнопкой мыши нажмите Проверка - появится четыре знакомых Вам вопроса , но с крупными квадратиками . Распечатайте эти вопросы и убедитесь , что теперь поставить галочку в квадратик вполне удобно . Чтобы очистить экран : □ Указатель мыши подведите к верхнему краю экрана - появится головное меню . Левой кнопкой мыши нажмите Правка , Выделить все - выделится весь текст на экране . □ На клавиатуре нажмите Delete - весь выделенный текст удалится . Выполнив урок 31 , Вы научились программно устанавливать размер шрифта . Следующий итог К оглавлению
Урок 32 Удаление модуля
Макрос Макрос1 нам уже не нужен , так как мы скопировали строку Selection.InsertSymbol 9633 , , True , которая и составляет всё его содержание . К оглавлению 1) Открыв окно Редактора , откройте окно кода . Правой кнопкой мыши нажмите NewMacros проекта А(История) - появится списочек . 2) В этом списочке левой кнопкой мыши нажмите Удалить NewMacros - появится вопрос “ Выполнить экспорт NewMacros перед удалением ? ” 3) Левой кнопкой мыши нажмите Нет - вопрос и модуль NewMacros исчезнут . Выполнив урок 32 , Вы научились удалять модуль . На панели История мы оставили кнопку Макрос . Она Вам пригодится , если Вы автоматически запишите ещё какой-нибудь макрос , ( в этом случае - если Вы сохраните вновь созданный макрос в История.dot - компьютер вновь создаст модуль NewMacros , в который запишет вновь созданный макрос под тем же именем Макрос1 , и вызвать этот макрос можно будет сохранённой сейчас кнопкой ) . Следующий итог К оглавлению
Задача 8
Сколько массивов может быть передано процедуре с помощью ключа ParamArray ? Ответ К оглавлению
Урок 33 Автотекст ( начало )
Мы предусмотрели два способа ответа на вопрос : подчёркивая номер правильного ответа или ставя галочку в квадратик перед правильным ответом . Поэтому надо предусмотреть 2 пояснения для ученика , поясняющие ему , как надо отвечать на вопросы . К оглавлению 1) В текстовом файле ( т.е. не открывая окно Редактора ) установите размер шрифта 12 ( это можно сделать , выведя на экран панель Форматирование или левой кнопкой мыши нажав Формат , Шрифт ) и наберите строку В каждом вопросе подчеркните номер верного ответа . 2) На клавиатуре нажмите Ctrl Shift Home - вся набранная строка выделится . 3) На клавиатуре нажмите Alt F3 - появится диалоговое окно “ Создание элемента автотекста ” с окошечком , в котором выделен текст “ В каждом ” . 4) На клавиатуре нажмите русскую н - текст “ В каждом ” заменится на “ н ” . 5) Левой кнопкой мыши нажмите ОК - диалоговое окно исчезнет , будет создан новый элемент автотекста . 6) На клавиатуре нажмите Delete - вся набранная строка удалится . 7) Выведите на экран панель Форматирование , если она ещё не выведена , и посмотрите ,какой размер имеет шрифт . Если этот размер не равен 16 ( скорей всего , он будет равен 12 ) , то установите значение 16 . 8) Протестируйте новый элемент автотекста : □ На клавиатуре нажмите сначала русскую н , затем ( отпустив н ) - F3 . На экране появится знакомая Вам строка , символы которой будут иметь размер 12 , но окошечко на панели Форматирование покажет размер 16 . □ Левой кнопкой мыши нажмите Проверка - к уже появившейся строке добавятся знакомые Вам вопросы , размер шрифта которых будет равен 16 , а не 12 . 9) Сейчас Вы создали элемент автотекста В каждом вопросе подчеркните номер верного ответа . с именем “ н ” . Аналогично создайте и проверьте элемент В каждом вопросе поставьте галочку в квадратик перед верным ответом . с именем “ г ” . Однако созданные нами элементы автотекста сохранились не в шаблоне История.dot , а в Normal.dot . Поэтому : 10) Левой кнопкой мыши нажмите Формат , Стиль - появится диалоговое окно “ Стиль ” . 11) В этом диалоговом окне левой кнопкой мыши нажмите Организатор - появится диалоговое окно “ Организатор ” . 12) В диалоговом окне “ Организатор ” левой кнопкой мыши нажмите Автотекст - в левом большом окошечке ( “ В История.dot ” ) будет пусто , в правом большом - список элементов автотекста шаблона Normal.dot . 13) В правом большом окошечке найдите слово “ г ” и нажмите его левой кнопкой мыши . Затем нажмите кнопку Копировать - элемент автотекста будет скопирован в История.dot . 14) Точно так же скопируйте элемент автотекста “ н ” . 15) Левой кнопкой мыши нажмите Закрыть - диалоговое окно уберётся с экрана . 16) Закройте Word , удалите Normal.dot , вновь откройте История.dot и убедитесь , что созданные Вами элементы автотекста работают правильно . При открытии Word после удаления Normal.dot компьютер создаёт новый , стандартный Normal.dot . Выполнив пункт 16 , Вы убедились , что созданные Вами элементы автотекста сохранились не только в Normal.dot , но и в История.dot тоже . Выполнив урок 33 , Вы : 1) Научились создавать элемент автотекста и пользоваться им . 2) Узнали , что созданные элементы автотекста сохраняются не в шаблоне созданном пользователем , а в Normal.dot . 3) Вспомнили , как открыть диалоговое окно Организатор , ( это окно мы открывали ещё на первом уроке ) и научились использовать его для копирования элементов автотекста из одного шаблона в другой . 4) Вспомнили , что после удаления изменённого или стандартного Normal.dot при открытии Word ( в том числе при открытии шаблона созданного пользователем ) создаётся новый , стандартный Normal.dot . Следующий итог К оглавлению
Урок 34 Автотекст ( продолжение )
К оглавлению 1) Не открывая История.dot , удалите Normal.dot и переименуйте История.dot в Normal.dot . 2) Двойным нажатием левой кнопкой мыши откройте Normal.dot . 3) На клавиатуре нажмите сначала Enter , затем стрелку влево - при нажатии Enter курсор переместится вниз , при нажатии стрелки влево вернётся в начало файла . Скорей всего , на Вашей клавиатуре имеется три стрелки влево : одна на белой кнопке и две на серых . На белой кнопке кроме стрелки должна быть ещё цифра 4 . Ни на одной , ни на другой серой кнопке не должно быть ничего кроме стрелки . Этими признаками и следует руководствоваться - если Ваша клавиатура не вполне стандартна , то цвет кнопок может быть другим . Одна из серых кнопок удаляет предыдущий символ , другая - просто переводит курсор на один символ влево . Рядом с последней находятся три кнопки со стрелками : вверх , вниз и вправо . Вот эту-то серую кнопку со стрелкой влево , расположенную рядом с тремя кнопками со стрелками , которая , не удаляя предыдущего символа , просто переводит курсор на один символ влево , - и принято называть стрелкой влево . 4) Наберите строку Фамилия , имя ______________________________________ 5) Нажмите Shift Enter - будет создана новая строка без создания нового абзаца ( курсор окажется на новой строке , но не под левым краем первой строки , а заметно левее ) . 6) Наберите строку Класс __________________ , сделав в её начале достаточное число пропусков , чтобы текстовый файл принял вид Фамилия , имя ______________________________________ Класс __________________ 7) Нажмите Ctrl Home - курсор переместится в начало текстового файла ( перед Фамилия ) . 8) Нажмите Ctrl Shift End - выделится три строки : строка , начинающаяся словом “ Фамилия ” ; строка , начинающаяся словом “ Класс ” , и пустая строка . 9) Нажмите Shift Стрелка Влево - выделение снимется с пустой строки , но останется на двух предыдущих . 10) Левой кнопкой мыши нажмите Формат , Абзац - появится диалоговое окно “ Абзац ” . 11) В левом верхнем углу этого диалогового окна левой кнопкой мыши нажмите Отступы и интервалы . 12) Левой кнопкой мыши установите Интервал междустрочный Двойной . 13) Левой кнопкой мыши нажмите ОК - диалоговое окно закроется , выделенные строки раздвинутся . 14) Из выделенного текста создайте новый элемент автотекста с именем “ ф ” . 15) Очистите экран . 16) Нажмите сначала ф , затем F3 - появятся две строки Фамилия , имя ______________________________________ Класс __________________ , а курсор будет находиться не в конце второй строки , а на третьей . 17) Нажмите сначала г , затем F3 - появится текст В каждом вопросе поставьте галочку в квадратик перед верным ответом . Обратите внимание , что курсор стоит сразу после точки , а не на следующей строке . 18) Левой кнопкой мыши нажмите Проверка - появятся знакомые Вам 4 вопроса . Если Вы всё сделали правильно , то первые три вопроса будут на 1-й странице , 4-й - на 2-й . 19) Закройте Word , переименуйте Normal.dot в История.dot . Выполнив урок 34 , Вы : 1) Научились вызывать диалоговое окно “ Абзац ” и устанавливать междустрочный интервал . 2) Научились в элемент автотекста включать символ перехода в новый абзац . 3) Узнали второй способ сохранения элементов автотекста в шаблоне пользователя . Этот второй способ заключается в том , что : □ сначала шаблон пользователя переименовывается в Normal.dot , □ затем создаются элементы автотекста , которые сохраняются в Normal.dot , ( при этом в процессе работы Normal.dot можно часто сохранять той же командой , которой сохраняется шаблон пользователя ; в нашем случае Вы могли сохранять Normal.dot нажимая Ш на панели История ) □ и наконец Normal.dot переименовывается в начальное имя шаблона пользователя . Этот способ практически необходим , когда требуется создать не несколько , а сотни или тысячи элементов автотекста . Следующий итог К оглавлению
Урок 35 Автотекст ( конец )
К оглавлению Левой кнопкой мыши нажмите Вставка в головном меню - появится выпадающее меню . Наведите указатель мыши на Автотекст - появится довольно большой список элементов автотекста , хотя в шаблоне История.dot всего три элемента автотекста . Наведите мышь на Колонтитул - появится список собственно элементов автотекста , каждый из которых можно вызвать нажатием левой кнопкой мыши . Каждая из строчек со стрелкой вправо : Внимание , г , Колинтитул , н , Обычный , Приветствие , Прощание , Строка ссылки , Тема , Указания - меню , при наведении на которое указателя мыши раскрывается свой список собственно элементов автотекста ( иногда состоящий только из одного элемента ) ; поэтому кнопки Вставка , Автотекст открывают список элементов автотекста , в котором трудно ориентироваться , так как он содержит много элементов из шаблона Normal.dot . Упростить этот список можно удалив все элементы автотекста из Normal.dot . Чтобы это сделать : 1) Вызовите диалоговое окно “ Организатор ” ( Формат , Стиль , Организатор ) . 2) Левой кнопкой мыши нажмите Автотекст . 3) В правом большом окошечке - список элементов автотекста шаблона Normal.dot . Левой кнопкой мыши нажмите первый элемент этого списка - - Страница - , этот элемент выделится . 4) На правом краю правого большого окошечка - полоса прокрутки , на верху которой стрелка вверх , в низу - стрелка вниз . Левой кнопкой мыши нажмите стрелку вниз и держите её нажатой , пока весь список не прокрутится до конца , т.е. пока бегунок - полоска на полосе прокрутки между стрелками - не упрётся в нижнюю стрелку . 5) На клавиатуре нажмите кнопку Shift и , не отпуская её , левой кнопкой мыши нажмите Ценное - последний элемент списка элементов автотекста шаблона Normal.dot в правом большом окошечке ; выделится весь список . 6) Левой кнопкой мыши нажмите Удалить - появится вопрос : “ Удалить автотекст - СТРАНИЦА - ? ” . Левой кнопкой мыши нажмите Да для всех - все элементы автотекста шаблона Normal.dot будут удалены . 7) В правом нижнем углу диалогового окна “ Организатор ” левой кнопкой мыши нажмите Закрыть - диалоговое окно закроется . 8) Левой кнопкой мыши нажмите Вставка , указатель мыши наведите на Автотекст - появится список элементов автотекста всего из трёх меню , каждое меню будет содержать только один элемент . 9) Левой кнопкой мыши нажмите эти элементы : сначала ф ( меню Обычный ) , потом н и наконец г - появится текст : Фамилия , имя _______________________________ Класс __________ В каждом вопросе подчеркните номер верного ответа .В каждом вопросе поставьте галочку в квадратик перед верным ответом . 10) При закрытии Word компьютер либо автоматически сохранит Normal.dot , либо спросит , сохранить ли изменения в Normal.dot . В последнем случае лучше левой кнопкой мыши нажать Да - тогда изменения в Normal.dot сохранятся и у Вас не будет лишних элементов автотекста и при следующих открытиях История.dot . Выполнив урок 35 , Вы : 1) Узнали , зачем удалять элементы автотекста Normal.dot , и научились это делать . 2) Научились вызывать элемент автотекста с помощью меню “ Автотекст ” . Следующий итог К оглавлению
Урок 36 Первый способ навигации по проверочным
Из плана , заявленного на уроках 20 и 26 , мы выполнили 2 первых пункта , а именно - специалисту-историку дали возможности : □ разбивать тип вопроса на подтипы ( причем , при желании , на очень большое число подтипов ) . □ довольно легко программировать автоматическое создание проверочной и совсем легко вставлять стандартные “ шапки ” в начало проверочных . Остался третий пункт - создать систему навигации по проверочным , т.е. систему поиска нужной проверочной . К оглавлению 1) В модуль А введите новый макрос : Sub яьКосмос ( ) Задать Z , "номер проверочной" , , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГ True , True , 16 , 20.2 , 18 Case 2 ГГ True , True , 16.2 , 20 , 19 Case 3 ГГ True , True , 16.3 , 20.3 , 17 End Select End Sub 2) Для этого макроса на панели История создайте кнопку Космос . 3) Левой кнопкой мыши нажимая Космос , убедитесь , что Вы можете вызвать любую из трёх разных проверочных или отменить печать проверочной и что задать номер проверочной Вы можете только цифрой 1 , 2 или 3 . Хотелось бы , чтобы учитель мог в диалоговом режиме выбрать не только набор вопросов , но и будут ли пронумерованы вопросы и ответы ( или будут квадратики ) . Чтобы учитель это смог : 4) В модуль А введите новую процедуру : Sub ДаНет ( zРезультат , zВопрос ) zРезультат = MsgBox ( zВопрос , 292 ) = 6 End Sub 5) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной" , , , 3 If Z = Empty Then Exit Sub ДаНет Z2 , "Нумеровать вопросы ?" ДаНет Z4 , _ "Перед вариантами ответа вставлять квадратики ?" Select Case Z Case 1 ГГ Z2 , Z4 , 16 , 20.2 , 18 Case 2 ГГ Z2 , Z4 , 16.2 , 20 , 19 Case 3 ГГ Z2 , Z4 , 16.3 , 20.3 , 17 End Select End Sub 6) Несколько раз нажав Космос , убедитесь , что Вы можете выбирать , нумеровать ли вопросы или ответы , точнее - что Вы можете выбрать любой из четырёх вариантов : □ нумеруются как вопросы , так и ответы ; □ нумеруются только вопросы ; □ нумеруются только ответы ; □ не нумеруются ни вопросы , ни ответы . Чтобы лучше понять смысл внесённых в код изменений : 7) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б MsgBox ( "Значение функции MsgBox" , 292 ) , 11 End Sub 8) Закрыв окно Редактора , левой кнопкой мыши нажмите сначала Проверка , Да ; затем - Проверка , Нет . В результате выполнения пунктов 7 и 8 Вы узнали , что функция MsgBox ( zВопрос , 292 ) принимает значение 6 ( если пользователь нажал Да ) или 7 ( если пользователь нажал Нет ) . Встроенная в VBA функция MsgBox имеет 5 аргументов ( из них только первый обязателен ) и предоставляет много возможностей для организации диалога . Однако в мало каком шаблоне используются все возможности MsgBox ; далеко не каждый хороший программист свободно владеет всеми возможностями MsgBox . Вообще , VBA имеет так много возможностей и тонкостей , что , видимо , никто не знает VBA полностью . Не ставьте цель изучить “ весь VBA ” : изучайте и обязательно осваивайте ( путём работы на компьютере ) только то , что Вам нужно для написания конкретной программы . Хотя заглянуть в хорошую книгу по программированию иногда бывает необходимо , сведения по работе VBA стремитесь получать из компьютера : из встроенной справочной системы ( доступ к ней Вы можете получить , нажав левой кнопкой мыши знак вопроса в окне Редактора ) , автоматически записывая макросы или создавая тестирующие макросы ( например , выполнив пункты 7 и 8 настоящего урока , Вы протестировали MsgBox ) . Утверждение MsgBox ( zВопрос , 292 ) = 6 будет истинно ( примет значение True ) , если пользователь нажал Да , и ложно ( примет значение False ) , если пользователь нажал Нет . В строке zРезультат = MsgBox ( zВопрос , 292 ) = 6 порядок действий справа налево : сначала проверяется , истинно ли утверждение MsgBox ( zВопрос , 292 ) = 6 , затем значение этого утверждения ( True или False ) присваивается переменной zРезультат . Осталось пояснить , почему макрос яьКосмос мы назвали яьКосмос , а не просто Космос . Во-первых , в VBA есть синтаксическое требование : в одном модуле не может быть двух процедур с одним и тем же именем ( впрочем , следует избегать совпадающие имена и у процедур в разных модулях ) . Поэтому разумно разбить процедуры на группы и для каждой группы , кроме одной из них , ввести свой префикс - стандартное начало имени , которым будет начинаться имя каждой процедуры из этой группы . Если одну группу процедур мы оставим без префикса , то в каждой другой группе должен быть “ неестественный ” префикс , т.е. не должно быть так , чтобы реальное слово русского языка путём прибавления к нему префикса могло превратиться в другое реальное слово . Например , префикс “ при ” - “ естественный ” , т.е. плохой , так как , например , слово “ Ход ” превратится в “ приХод ” ( в именах процедур и переменных VBA не отличает большую букву от малой : например , “ приХод ” , “ приход ” , “ ПриХод ” , “ Приход ” - для VBA совпадающие имена ) . Префикс “ яь ” - совершенно неестественный , так как ни одно русское слово не начинается с “ яь ” . Во-вторых , макрос яьКосмос - “ конечный ” , т.е. для него мы создали кнопку . Посмотрите список макросов История.dot ( Настройка , Команды , История.dot , Макросы ) - он довольно большой ( и содержит не только макросы , но и процедуры , все аргументы которых вводятся ключом ParamArray , - например А.А.Б ) . Чтобы в этом списке было легко найти “ яьКосмос ” , мы и использовали именно такой ( “ яь ” ) префикс , благодаря чему “ яьКосмос ” стоит последним в списке ( обратите внимание , что и после “ Я ” тоже ) . После мягкого знака в русском алфавите есть ещё три буквы , и у нас в запасе ещё три неестественных префикса - “ яэ ” , “ яю ” и “ яя ” . Префиксы нужны не только для того , чтобы макрос легко было найти в окне “ Настройка ” , но и для того , чтобы легко было найти процедуру в окне Редактора ( список процедур модуля Вы можете увидеть и использовать , левой кнопкой мыши нажав стрелку вниз на правом конце правого верхнего оконца окна Редактора ) . Выполнив урок 36 , Вы : 1) Научились , используя оператор Select Case , несколько макросов заменять одним , чтобы создать одну кнопку вместо нескольких . 2) Узнали , как просто значение утверждения ( True или False ) присвоить переменной . 3) Узнали кое-что о функции MsgBox . 4) Узнали пример тестирования VBA . 5) Узнали , зачем имена процедур начинать с префиксов и какими принципами следует руководствоваться выбирая префикс . Следующий итог К оглавлению
Урок 37 Совершенствование первого способа навигации по проверочным
В макросе яьКосмос трижды пишется Z2 , Z4 , что совершенно неинформативно . Потери памяти на многократное повторение одного и того же куска кода в данном случае малы , так как яьКосмос содержит всего три случая . Однако другой подобный макрос ( или яьКосмос в будущем ) может иметь десятки или сотни случаев , и тогда потери памяти на многократное повторение куска кода будут значительны . Хотелось бы иметь возможность избегать такие многократные повторения . К оглавлению 1) В начале модуля А строку Public G ( ) , GG замените на Public G ( ) , GG , GГГ 2) В модуль А введите новую процедуру : Sub ГГА ( zНумероватьВопросы , zКвадратики ) For gk = 0 To Ubound ( GГГ ) ДваЦелыхЧислаИзДесятичнойДроби GГГ ( gk ) , zТип , zПодТип , 1 Г zТип , , , zПодТип , zНумероватьВопросы , zКвадратики Next gk End Sub 3) Измените процедуру ГГ , чтобы она выглядела так : Sub ГГ ( zНумероватьВопросы , zКвадратики , ParamArray zТипы ( ) ) GГГ = zТипы ГГА zНумероватьВопросы , zКвадратики End Sub 4) Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . 5) В модуль А введите новую процедуру : Sub ГГG ( ParamArray zТипы ( ) ) GГГ = zТипы End Sub 6) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной" , , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГG 16 , 20.2 , 18 Case 2 ГГG 16.2 , 20 , 19 Case 3 ГГG 16.3 , 20.3 , 17 End Select ДаНет Z2 , "Нумеровать вопросы ?" ДаНет Z4 , "Перед вариантами ответа вставлять квадратики ?" ГГА Z2 , Z4 End Sub 7) Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . Выполнив урок 37 , Вы написали две процедуры - ГГА и ГГG , позволяющие значительно сократить код ( если процедуры , подобные яьКосмос , будут иметь много случаев ) . Следующий итог К оглавлению
Задача 9 ДаНет с ParamArray
Используя ParamArray , так измените ДаНет , чтобы в яьКосмос строки ДаНет Z2 , "Нумеровать вопросы ?" ДаНет Z4 , "Перед вариантами ответа вставлять квадратики ?" можно было заменить на ДаНет Z2 , "Нумеровать вопросы ?" , _ Z4 , "Перед вариантами ответа вставлять квадратики ?" Ответ К оглавлению

Урок 38 Процедуры-функции К оглавлению 1) Процедуру ДаНет замените на Function фДаНет ( zВопрос ) фДаНет = MsgBox ( zВопрос , 292 ) = 6 End Function 2) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной" , , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГG 16 , 20.2 , 18 Case 2 ГГG 16.2 , 20 , 19 Case 3 ГГG 16.3 , 20.3 , 17 End Select ГГА фДаНет ( "Нумеровать вопросы ?" ) , _ фДаНет ( "Перед вариантами ответа вставлять квадратики ?" ) End Sub 3) Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . Выполнив три первых пункта настоящего урока , Вы познакомились с процедурами-функциями . По синтаксису процедура-функция отличается от процедуры Sub прежде всего двумя моментами : □ Если процедура Sub начинается с Sub и кончается End Sub , то процедура-функция начинается с Function и кончается End Function . □ Если при вызове процедуры Sub её аргументы просто перечисляются через запятые сразу после имени процедуры , то при вызове процедуры-функции тоже перечисляются через запятые сразу после её имени , но обычно заключаются в скобки . Если процедура Sub имеет только один аргумент , то синтаксически допустим её вызов с аргументом , заключённым в скобки . Но при таком вызове она будет работать по-другому : 4) В модуль А введите новую процедуру : Sub Квадрат ( Z ) Z = Z * Z Б Z , 11 End Sub 5) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 Квадрат Z Квадрат Z Квадрат Z End Sub Закройте окно Редактора , нажмите Проверка - появятся числа 4 ; 16 ; 256 ( 4 = 2 * 2 ; 16 = 4 * 4 ; 256 = 16 * 16 ) . 6) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 Квадрат ( Z ) Квадрат ( Z ) Квадрат ( Z ) End Sub Закройте окно Редактора , нажмите Проверка - появится три четвёрки . 7) В макросе Проверка строку Z = 2 замените на Z = 3 Закройте окно Редактора , нажмите Проверка - появится три девятки . Таким образом ,аргумент ByRef процедуры Sub , будучи при её вызове заключён в скобки , ведёт себя как аргумент ByVal . Если процедура Sub имеет несколько аргументов , то можно ли , вызывая её , любой из её аргументов заключить в скобки и , если да , будет ли аргумент в скобках вести себя как аргумент ByVal ? 8) Измените процедуру Квадрат , чтобы она выглядела так : Sub Квадрат ( Z , R ) Z = Z * Z R = R * R Б Z & " ' " & R , 11 End Sub 9) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Квадрат Z , R Квадрат Z , R Квадрат Z , R End Sub Закройте окно Редактора , нажмите Проверка - появятся пары чисел 4 ' 25 ; 16 ' 625 ; 256 ' 390625 . 10) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Квадрат ( Z ) , ( R ) Квадрат ( Z ) , ( R ) Квадрат ( Z ) , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появится три одинаковых пары чисел 4 ' 25 . 11) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Квадрат ( Z ) , R Квадрат ( Z ) , R Квадрат ( Z ) , R End Sub Закройте окно Редактора , нажмите Проверка - появятся пары чисел 4 ' 25 ; 4 ' 625 ; 4 ' 390625 . 12) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Квадрат Z , ( R ) Квадрат Z , ( R ) Квадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся пары чисел 4 ' 25 ; 16 ' 25 ; 256 ' 25 . Выходит , вызывая процедуру Sub с несколькими аргументами , можно любой её аргумент ( необязательно один ) заключить в скобки и таким образом заставить его вести себя как аргумент ByVal . Это позволяет в некоторых случаях вместо нескольких процедур создать одну . Например , в каком-нибудь шаблоне может понадобиться в одних случаях возводить переменные в квадрат и печатать их новые значения , а в других - печатать значения квадратов , не изменяя значения самих переменных . При такой потребности необязательно писать процедуры КвадратByRef и КвадратByVal , которые бы различались только тем , что в заголовке процедуры КвадратByVal переменные объявлялись бы с ключом ByVal . Достаточно написать одну процедуру Квадрат , в которой все аргументы ByRef , и в случае необходимости , вызывая её , некоторые или все аргументы по одному заключать в скобки . Наша процедура Квадрат , благодаря такому значению заключения аргумента в скобки , может заменить три процедуры : процедуру с двумя аргументами ByRef , процедуру с двумя аргументами ByVal и процедуру с аргументом ByRef и аргументом ByVal . Вообще , лучше писать небольшое число хорошо продуманных , гибких процедур с достаточным числом аргументов чем необъятное число негибких процедур с малым числом аргументов . Скобки для аргумента - фактически неявный , нигде не объявленный аргумент , который ничего не стоит , так как нисколько не увеличивает программный код . 13) Измените процедуру Квадрат , чтобы она выглядела так : Sub Квадрат ( ParamArray Z ( ) ) For k = 0 To Ubound ( Z ) Z ( k ) = Z ( k ) * Z ( k ) Б Z ( k ) & IIf ( k < Ubound ( Z ) , " ' " , Chr ( 11 ) ) Next k End Sub 14) Убедитесь , что макрос Проверка по-прежнему выглядит так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Квадрат Z , ( R ) Квадрат Z , ( R ) Квадрат Z , ( R ) End Sub Если это не так , приведите его к этому виду . Закройте окно Редактора , нажмите Проверка - появятся пары чисел 4 ' 25 ; 16 ' 25 ; 256 ' 25 . Сейчас мы убедились , что аргумент ParamArray , при вызове процедуры Sub заключённый в скобки , ведёт себя как аргумент ByVal . Так просто преодолевается главный недостаток ParamArray , заключающийся в том , что при написании процедуры аргументы ParamArray не могут быть введены с ключом ByVal . Главное отличие процедуры-функции от процедуры Sub в том , что процедура Sub только действует , а процедура-функция и действует , и может принимать значение . Поэтому процедура-функция универсальнее : всё или почти всё , что можно сделать с помощью процедуры Sub , можно сделать и с помощью процедуры-функции , но не всё , что можно сделать с помощью процедуры-функции , можно сделать с помощью процедуры Sub . В частности , как мы убедились в начале настоящего урока , процедура-функция , в отличие от процедуры Sub , может быть аргументом процедуры Sub или другой процедуры-функции . Вам не будет очень трудно писать процедуры-функции , так как почти всё , что можно применить при написании процедуры Sub , ( ParamArray , циклы , условный оператор и т.д. ) можно применить и при написании процедуры-функции . Однако при написании и применении процедур-функций обнаруживается больше подводных камней чем при написании и применении процедур Sub . Чтобы убедиться в истинности двух предыдущих абзацев : 15) Процедуру Квадрат замените на Function фКвадрат ( ParamArray Z ( ) ) For k = 0 To Ubound ( Z ) Z ( k ) = Z ( k ) * Z ( k ) Б Z ( k ) & IIf ( k < Ubound ( Z ) , " ' " , Chr ( 11 ) ) Next k End Function 16) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 фКвадрат Z , ( R ) фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся те же самые пары чисел 4 ' 25 ; 16 ' 25 ; 256 ' 25 . Таким образом , если неверно , что все аргументы процедуры-функции заключены в общую пару скобок , то процедура-функция работает совершенно так же как процедура Sub . 17) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 фКвадрат ( Z , ( R ) ) фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Компьютер сообщит о синтаксической ошибке ( следовательно , если процедура-функция используется в качестве процедуры Sub , то её аргументы нельзя заключить в общую пару скобок ) . Левой кнопкой мыши нажмите ОК - сообщение об ошибке исчезнет . 18) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Б фКвадрат ( Z , ( R ) ) , 11 фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся те же самые пары чисел 4 ' 25 ; 16 ' 25 ; 256 ' 25 . Однако между первой и второй парами чисел , в отличие от текста появившегося при выполнении пункта 16 , появится пустая строка . 19) Измените процедуру-функцию фКвадрат , чтобы она выглядела так : Function фКвадрат ( ParamArray Z ( ) ) For k = 0 To Ubound ( Z ) Z ( k ) = Z ( k ) * Z ( k ) Б Z ( k ) & IIf ( k < UBound ( Z ) , " ' " , Chr ( 11 ) ) Next k фКвадрат = Z ( 0 ) \ 2 End Function Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ' 25 ; 2 ; 16 ' 25 ; 256 ' 25 . 20) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 фКвадрат Z , ( R ) Б фКвадрат ( Z , ( R ) ) , 11 фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ' 25 ; 16 ' 25 ; 8 ; 256 ' 25 . Таким образом , строка Б фКвадрат ( Z , ( R ) ) , 11 действует следующим образом : сначала действует процедура-функция , затем - вызывающая её процедура Б ( которая , в данном случае , печатает значение процедуры-функции и создаёт новую строку ) . Говорить надо именно “ создаёт новую строку ” , а не “ переводит курсор на новую строку ” , так как создать новую строку - значит вставить символ Chr ( 11 ) , а перевести курсор на какую-то строку - значит просто переместить курсор , никак не изменяя текст . Изменится ли такой порядок , если процедура-функция вычислит своё значение не в конце , а в начале ? 21) Измените процедуру-функцию фКвадрат , чтобы она выглядела так : Function фКвадрат ( ParamArray Z ( ) ) фКвадрат = 0 For k = 0 To Ubound ( Z ) Z ( k ) = Z ( k ) * Z ( k ) Б Z ( k ) & IIf ( k < Ubound ( Z ) , " ' " , Chr ( 11 ) ) Next k End Function Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ' 25 ; 16 ' 25 ; 0 ; 256 ' 25 . Таким образом , порядок действий не изменился . Если процедура-функция , имея только один аргумент , используется в качестве процедуры Sub , то можно ли его заключить в скобки ? 22) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 фКвадрат ( Z ) фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ; 4 ' 25 ; 16 ' 25 . Таким образом , если процедура-функция , имея только один аргумент , используется в качестве процедуры Sub , то , как и в случае использования процедуры Sub , его можно заключить в скобки и он будет вести себя как аргумент ByVal . 23) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Б фКвадрат ( Z ) , 11 фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ; 0 ; 16 ' 25 ; 256 ' 25 . Обратите внимание , что аргумент Z , оставаясь заключённым в скобки , перестал вести себя как аргумент ByVal . Таким образом , применение процедуры-функции действительно имеет подводные камни , которых не имеет применение процедуры Sub . 24) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б Chr ( 13 ) Z = 2 R = 5 Б фКвадрат ( ( Z ) ) , 11 фКвадрат Z , ( R ) фКвадрат Z , ( R ) End Sub Закройте окно Редактора , нажмите Проверка - появятся числа : 4 ; 0 ; 4 ' 25 ; 16 ' 25 . Таким образом , в результате заключения в ещё одну пару скобок аргумент Z снова стал вести себя как аргумент ByVal . Во всех именах процедур-функций мы будем использовать префикс “ ф ” , чтобы имя процедуры-функции случайно не совпало с именем какой-нибудь процедуры Sub и чтобы , просматривая программный код , было легко определить , что используется - процедура Sub или процедура-функция . 25) Удалите процедуру-функцию фКвадрат и тело макроса Проверка . Удалить тело макроса Проверка - значит привести этот макрос к виду : Sub Проверка ( ) End Sub Внимательно прочитав и выполнив урок 38 , Вы : 1) Познакомились с процедурами-функциями . 2) Экспериментально исследовали процедуры Sub и процедуры-функции , в результате чего узнали : □ Что аргумент процедуры Sub , заключённый в скобки , ведёт себя как аргумент ByVal . В частности , аргумент ParamArray , заключённый в скобки , тоже ведёт себя как аргумент ByVal . □ Что процедура-функция пишется почти так же как процедура Sub . □ Что процедура-функция может использоваться как процедура Sub . В этом случае её аргументы не заключаются в общую пару скобок ( если аргумент один , то его можно заключить в скобки - тогда он будет вести себя как аргумент ByVal ) . □ Порядок действий , когда действующая процедура-функция вызывается процедурой Sub в качестве аргумента . □ Что если единственный аргумент процедуры-функции , вызванной процедурой Sub в качестве аргумента , заключён в две пары скобок , то ведёт себя как аргумент ByVal . 3) Узнали , зачем имена всех процедур-функций начинать префиксом . Следующий итог К оглавлению

Задача 10 фДаНет с ParamArray
В задаче 9 мы написали удобную процедуру Sub ДаНет с ParamArray , а на уроке 38 заменили её процедурой-функцией фДаНет , позволяющей обходиться без дополнительных переменных . Измените фДаНет , чтобы её можно было использовать как так , как мы использовали её на уроке 38 , так и так , как мы использовали процедуру ДаНет в задаче 9 . Ответ К оглавлению
Урок - задача 39 Единая нумерация вопросов нескольких проверочных
Откройте окно редактора и найдите в нём код процедуры ГГА . Не открывая следующую страницу настоящей книги , постарайтесь вспомнить , зачем в ГГА мы в качестве счётчика цикла используем глобальную переменную gk , а не какую-нибудь локальную ( например , k ) . Если Вы не вспомнили самостоятельно , то , видимо , в своё время Вам в начало процедуры ГГА ( а до этого в начало процедуры ГГ ) следовало ввести комментарий ( сейчас вводить его не надо , так как процедуру ГГА мы сейчас переделаем ) : ' gk -- глобальная переменная ' которую использует процедура Г ' чтобы нумеровать вопросы ' номер вопроса = gk + 1 Комментарии увеличивают размер ( в байтах ) программы и требуют время для своего написания , но иногда они необходимы , чтобы вспомнить потом принцип работы той или иной процедуры . Однако придерживайтесь принципа , что отсутствие комментария лучше плохого комментария ; старайтесь обходиться без комментариев : □ используя “ говорящие ” имена переменных и процедур ; □ создавая , по возможности , может быть и большие по объёму , но простые по структуре , понятные процедуры ( неограниченные по объёму , но относительно простые процедуры , подобные нашей процедуре Г , можно писать , используя оператор выбора Select Case ) . Сейчас каждая вызываемая нами проверочная нумерует вопросы с единицы , независимо от того , вызывали ли мы какую-нибудь проверочную до этого . Если бы нумерация вопросов проверочной начиналась с числа , следующего за номером последнего вопроса предыдущей проверочной , то из отдельных проверочных можно было бы легко составлять большие книги . К оглавлению 1) В начале модуля А строку Public gk замените на Public gk , gПомнитьНумерациюВопросов 2) Измените процедуру ГГА , чтобы она выглядела так : Sub ГГА ( zНумероватьВопросы , zКвадратики ) Z = IIf ( gПомнитьНумерациюВопросов , gk , 0 ) For gk = Z To Ubound ( GГГ ) + Z ДваЦелыхЧислаИзДесятичнойДроби GГГ ( gk - Z ) , zТип , zПодТип , 1 Г zТип , , , zПодТип , zНумероватьВопросы , zКвадратики Next gk End Sub 3) Закройте окно Редактора . Несколько раз нажав Космос ( и отвечая Да на вопрос “ Нумеровать вопросы ? ” ) , убедитесь , что процесс нумерации вопросов не изменился . 4) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) gПомнитьНумерациюВопросов = True End Sub 5) Закройте окно Редактора . Нажмите Проверка - никаких видимых изменений не произойдёт , но gПомнитьНумерациюВопросов примет значение True . Несколько раз нажав Космос ( и отвечая Да на вопрос “ Нумеровать вопросы ? ” ) , убедитесь , что возникла единая нумерация вопросов нескольких проверочных ( первый вопрос второй проверочной нумеруется числом 4 , первый вопрос третьей проверочной - 7 и т.д. ) . 6) В модуль А введите новую процедуру-функцию : Function фNot ( ParamArray zЛогическиепеременные ( ) ) фNot = Not zЛогическиепеременные ( 0 ) For k = 0 To Ubound ( zЛогическиепеременные ) zЛогическиепеременные ( k ) = фNot Next k End Function 7) В модуль А введите новый макрос : Sub ПомнитьНумерациюВопросов ( ) фNot gПомнитьНумерациюВопросов End Sub 8) Создайте для него панель “ГлобальныеПеременные” и на ней кнопку Помнить . Новую панель закрепите под панелью “История” . 9) Убедитесь , что Помнить переключает способ нумерации вопросов . Для этого : несколько раз нажмите Космос ( отвечая Да на вопрос “ Нумеровать вопросы ? ” ) ; очистите экран , один раз нажмите Помнить и опять несколько раз нажмите Космос ; ещё раз очистите экран , один раз нажмите Помнить и опять несколько раз нажмите Космос . У нашей кнопки Помнить крупный недостаток : она никак не показывает , каково значение gПомнитьНумерациюВопросов в данный момент . 10) Измените макрос ПомнитьНумерациюВопросов , чтобы он выглядел так : Sub ПомнитьНумерациюВопросов ( ) CommandBars ( "ГлобальныеПеременные" ).Controls ( 1 ).Caption = _ IIf ( фNot ( gПомнитьНумерациюВопросов ) , "V" , " " ) & " Помнить" End Sub 11) Повторите пункт 9 и убедитесь , что значению True переменной gПомнитьНумерациюВопросов соответствует галочка , а значению False - отсутствие галочки на Помнить . Выполнив урок 39 , Вы : 1) Вспомнили , что процедуры могут обмениваться данными не только через аргументы , но и через глобальные переменные . 2) Узнали короткий , но эффективный код процедуры-функции фNot , позволяющей одновременно менять значения произвольного числа логических переменных , ( эта процедура оказывается особенно полезной , когда переменные имеют длинные имена ) . 3) Научились программно менять надпись на кнопке . В окончательной редакции макроса ПомнитьНумерациюВопросов мы использовали преимущество процедуры-функции перед процедурой Sub . Если бы фNot была процедурой Sub , нам бы вместо Sub ПомнитьНумерациюВопросов ( ) CommandBars ( "ГлобальныеПеременные" ).Controls ( 1 ).Caption = _ IIf ( фNot ( gПомнитьНумерациюВопросов ) , "V" , " " ) & " Помнить" End Sub пришлось ввести Sub ПомнитьНумерациюВопросов ( ) фNot gПомнитьНумерациюВопросов CommandBars ( "ГлобальныеПеременные" ).Controls ( 1 ).Caption = _ IIf ( gПомнитьНумерациюВопросов , "V" , " " ) & " Помнить" End Sub и таким образом дважды повторить длинное имя переменной . Следующий итог К оглавлению
Урок 40 НумероватьВопросы , Квадратики
Если из многих проверочных составлять большую книгу , то перед вставкой каждой проверочной отвечать на вопросы о нумерации и квадратиках утомительно . На настоящем уроке употребление соответствующих локальных переменных мы заменим употреблением глобальных , значения которых можно будет задавать подобно тому , как на прошлом уроке мы задавали значение gПомнитьНумерациюВопросов . К оглавлению 1) В начале модуля А Public gk , gПомнитьНумерациюВопросов замените на Public gk , gПомнитьНумерациюВопросов Public gНумероватьВопросы , gКвадратики 2) В модуль А введите новый макрос : Sub НумероватьВопросы ( ) CommandBars ( "ГлобальныеПеременные" ).Controls ( 2 ).Caption = _ IIf ( фNot ( gНумероватьВопросы ) , "V" , " " ) & " Нумеровать" End Sub Обратите внимание , что в скобках после Controls стоит 2 , а не 1 . 3) Создайте для него кнопку Нумеровать на правом краю панели ГлобальныеПеременные , чтобы кнопка Помнить была между Нумеровать и началом ( левым краем ) панели . Между кнопками установите вертикальную черту ( Начать группу ) . 4) Несколько раз нажав Нумеровать , убедитесь , что галочка появляется или исчезает после каждого нажатия . 5) В модуль А введите новый макрос : Sub КвадратикиПередОтветами ( ) CommandBars ( "ГлобальныеПеременные" ).Controls ( 3 ).Caption = _ IIf ( фNot ( gКвадратики ) , "V" , " ") & " Квадратики" End Sub 6) Создайте для него кнопку Квадратики на правом краю панели ГлобальныеПеременные , чтобы кнопки Помнить и Нумеровать были между Квадратики и началом ( левым краем ) панели . Между Квадратики и Нумеровать установите вертикальную черту ( Начать группу ) . 7) Несколько раз нажав Квадратики , убедитесь , что галочка появляется или исчезает после каждого нажатия . Мы выбираем длинные , “ говорящие ” имена макросов не только затем , чтобы легче было понимать программный код , но и потому , что при наведении указателя мыши на кнопку появляется имя макроса , которое можно использовать как подсказку для пользователя . Если на Вашем компьютере такие подсказки не появляются , то в диалоговом окне “ Настройка ” левой кнопкой мыши нажмите Параметры , левой кнопкой мыши поставьте галочку перед “ Отображать подсказки для кнопок ” , левой кнопкой мыши нажмите Закрыть - диалоговое окно закроется ; наведите указатель мыши на какую-нибудь из наших кнопок - на экран выведется маленький жёлтый прямоугольник с именем макроса . 8) Измените заголовок процедуры Г , чтобы он выглядел так : Sub Г ( zТипВопроса , Optional zНаВремя = False , _ Optional ByVal ZсКакимМенятьВерныйОтвет = 0 , _ Optional zПодТипВопроса = 1 ) При этом процедура Г лишится двух необязательных аргументов - zНумероватьВопросы и zКвадратики . 9) В начале процедуры Г If zНумероватьВопросы Then Б gk + 1 & ") " замените на If gНумероватьВопросы And Not zНаВремя Then Б gk + 1 & ") " 10) В конце процедуры Г If zКвадратики Then замените на If gКвадратики And Not zНаВремя Then ( если Вы всегда строго следовали моим указаниям , то это 27-я снизу строка процедуры ) . 11) Удалите процедуры ГГ , ГГG . 12) Измените ( включая имя ) процедуру ГГА , чтобы она выглядела так : Sub ГГ ( ParamArray zТипы ( ) ) Z = IIf ( gПомнитьНумерациюВопросов , gk , 0 ) For gk = Z To Ubound ( zТипы ) + Z ДваЦелыхЧислаИзДесятичнойДроби zТипы ( gk - Z ) , zТип , zПодТип , 1 Г zТип , , , zПодТип Next gk End Sub 13) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной" , , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГ 16 , 20.2 , 18 Case 2 ГГ 16.2 , 20 , 19 Case 3 ГГ 16.3 , 20.3 , 17 End Select End Sub 14) В начале модуля А Public G ( ) , GG , GГГ замените на Public G ( ) , GG 15) Закройте окно Редактора . Меняя значения глобальных логических переменных кнопками на панели ГлобальныеПеременные и нажимая Космос на панели История , убедитесь , что макрос Космос работает должным образом . 16) Несколько раз нажав Д на панели История , убедитесь , что работа макроса Диалоги не изменилась . Внимательно прочитав и выполнив урок 40 , Вы узнали : 1) Что число в скобках после Controls указывает на положение кнопки на панели инструментов , являясь порядковым номером кнопки . 2) Как имя макроса использовать в качестве подсказки для пользователя . Следующий итог К оглавлению
Урок 41 gПечатьОтветов
Трудно представить практическое применение большой книги с нашими вопросами , в которой бы не указывались номера верных ответов . А вот книга , в которой сразу после вопроса указывается номер правильного ответа , может быть использована не специалистом-историком для проведения викторин или учениками для взаимного обучения ( при этом первый ученик читает вопрос , второй отвечает и первый ученик говорит , верно ли ответил второй ученик ) . К оглавлению 1) В начале модуля А Public gНумероватьВопросы , gКвадратики замените на Public gНумероватьВопросы , gКвадратики Public gПечатьОтветов 2) В процедуре Г End If End Sub замените на Exit Sub End If If gПечатьОтветов Then Selection.TypeBackspace Б Chr ( 13 ) & gk + 1 & ") " & gПравильный , 11 End If End Sub Selection.TypeBackspace удаляет символ перед курсором ( в данном случае Chr ( 11 ) - символ создания новой строки ) . 3) В модуль А введите новый макрос : Sub ПечатьНомеровВерныхОтветов ( ) CommandBars ( "ГлобальныеПеременные" ).Controls ( 4 ).Caption = _ IIf ( фNot ( gПечатьОтветов ) , "V" , " " ) & " Ответы" End Sub 4) На правом краю панели ГлобальныеПеременные создайте для него кнопку Ответы , отделив её от Квадратики . 5) Кнопки панели ГлобальныеПеременные установите в состояние : Помнить - без галочки Нумеровать - с галочкой Квадратики - без галочки Ответы - с галочкой 6) Нажав Космос , выведите на экран одну проверочную - появится тройка вопросов , пронумерованных с одного по три , с пронумерованными ответами и номерами верных ответов ; например , такая : 1) Первым космонавтом был : 1 ) Юрий Гагарин 2 ) Герман Титов 3 ) Юрий Титов 4 ) Герман Гагарин 1) 1 2) Первым американским космонавтом был : 1 ) Пол Маккартни 2 ) Алексей Леонтьев 3 ) Джон Гленн 2) 3 3) Первым космическим туристом ( заплатившим деньги за полёт в космос ) был : 1 ) Денис Тито 2 ) Денис Титов 3 ) Герман Титов 3) 1 Конечно , если Вы выбрали не первую , а вторую или третью проверочную , то содержание их будет другое , но форма должна быть той же . Если это не так , то , скорее всего , галочки на кнопках не соответствуют значениям глобальных переменных . Два или три раза нажав каждую кнопку , установите состояние кнопок в соответствии с пунктом 5 - таким образом для каждой кнопки наличие или отсутствие галочки Вы приведёте в соответствие значению глобальной переменной . Очистите экран и повторите пункт 6 - на экране появится тройка вопросов заявленной в пункте 6 формы . Наш шаблон уже очень сложен ; выполнение даваемых мной инстукций требует большого внимания ; скорей всего , мой и Ваш шаблоны уже различаются . Наверно , Вы уже сталкивались с тем , что компьютер не всегда действует так , как я это описываю . Возможные причины этого : □ Вы неверно выполнили мои инструкции ( возможно , не на последнем уроке , а на предыдущих ) . □ В книге опечатки ( возможны как в описании поведения компьютера , так и в инструкциях для Ваших действий ) . □ Пытаясь решить предложенную мной задачу , Вы внесли в шаблон изменения , которые потом не исправили ( т.е. не вернули шаблон в состояние , в котором он был перед Вашими попытками решить задачу ) , ( чтобы этого избежать , нужно моё решение задачи вносить не в шаблон , который получился в результате Ваших попыток решения задачи , а в шаблон , который был перед Вашими попытками ) . □ У меня установлен Word 97 , у Вас - Word 2000 . □ У меня и Вас разные хранимые вне шаблона настройки компьютера ( частично этого можно избежать , постоянно следя , чтобы Normal.dot был стандартным ; однако некоторые настройки хранятся как вне нашего шаблона , так и вне Normal.dot ) . □ У меня и Вас разные значения глобальных переменных . Преодолеть первые три причины поможет прилагаемый к книге компакт-диск , на котором записаны состояния нашего шаблона на конец выполнения каждого урока и каждой задачи. Чтобы преодолеть последние три причины , Вам надо в разумной степени и разумным образом отклоняться от моих инструкций ; программирование - неизбежно творческий процесс : постоянно приходится решать новые проблемы или проблемы , решение которых Вы уже успели забыть ; пусть небольшие отклонения от моих инструкций послужат Вам тренировкой в творчестве . 7) Установите галочку на Помнить , не меняя состояния других кнопок . 8) Не очищая экран , на клавиатуре нажмите Ctrl End - курсор переместится в конец текста ( т.е. в конец третьего , последнего вопроса проверочной ) . 9) Нажав Космос , выведите на экран одну проверочную - появится тройка вопросов , пронумерованных с четырёх по шесть , с пронумерованными ответами и номерами верных ответов . 10) Очистите экран . Несколько раз нажав Д на панели История , убедитесь , что работа макроса Диалоги не изменилась . Если у Вас есть время , убедитесь , что работа макроса Диалоги не меняется и при других значениях глобальных переменных , задаваемых кнопками Помнить , Нумеровать , Квадратики , Ответы ; подумайте почему . Выполнив урок 41 , Вы узнали : 1) Selection.TypeBackspace . 2) Новый способ обеспечения независимости работы макроса Диалоги от значения глобальной переменной . Раньше для этого мы использовали аргумент zНаВремя процедуры Г , вводя его в условный оператор . Например , в строке If gНумероватьВопросы And Not zНаВремя Then Б gk + 1 & ") " оператор Б gk+1 & “) ” может выполняться , только если zНаВремя = False ; если же zНаВремя = True , то оператор Б gk+1 & “) ” , вставляющий номер вопроса , не выполняется ни при каком значении переменной gНумероватьВопросы . На настоящем уроке мы тоже использовали аргумент zНаВремя , но опосредственно , не вводя его в условный оператор . В конец оператора If zНаВремя Then . . . End If мы ввели оператор досрочного выхода из процедуры Exit Sub . Теперь , если zНаВремя = True , то оператор If zНаВремя Then . . . End If выполняется , то происходит досрочный выход из процедуры , то часть кода между If zНаВремя Then . . . End If и End Sub не выполняется независимо ни от каких других условий . Следующий итог К оглавлению
Урок 42 Быстрое приведение кнопок в соответствие значениям глобальных переменных
Вероятно , Вы уже сталкивались с тем , что галочки на кнопках панели ГлобальныеПеременные не всегда соответствуют значениям глобальных переменных . Чтобы быть уверенным в соответствии , нужно каждую кнопку нажать хотя бы раз . На настоящем уроке мы сделаем так , что привести в соответствие значениям глобальных переменных галочки на всех 4-х кнопках можно будет нажав всего одну кнопку ( любую из 4-х ) . К оглавлению 1) В модуль А введите новый макрос : Sub ГП ( ) Set R = CommandBars ( "ГлобальныеПеременные" ).Controls R ( 1 ).Caption = IIf ( gПомнитьНумерациюВопросов , "V" , " ") & " Помнить" R ( 2 ).Caption = IIf ( gНумероватьВопросы , "V" , " " ) & " Нумеровать" R ( 3 ).Caption = IIf ( gКвадратики , "V" , " " ) & " Квадратики" R ( 4 ).Caption = IIf ( gПечатьОтветов , "V" , " " ) & " Ответы" End Sub 2) Измените макросы ПомнитьНумерациюВопросов , НумероватьВопросы , КвадратикиПередОтветами , ПечатьНомеровВерныхОтветов , чтобы они выглядели так : Sub ПомнитьНумерациюВопросов ( ) фNot gПомнитьНумерациюВопросов ГП End Sub Sub НумероватьВопросы ( ) фNot gНумероватьВопросы ГП End Sub Sub КвадратикиПередОтветами ( ) фNot gКвадратики ГП End Sub Sub ПечатьНомеровВерныхОтветов ( ) фNot gПечатьОтветов ГП End Sub 3) Закройте окно Редактора . Установите галочки на все кнопки панели ГлобальныеПеременные . Закройте Word , сохранив История.dot . 4) Вновь откройте История.dot , выведите на экран панель ГлобальныеПеременные - все кнопки на ней будут с галочками . 5) Нажав Космос , выведите на экран одну проверочную - появится три непронумерованных вопроса с пронумерованными ответами и без номеров верных ответов . Таким образом , по крайней мере три галочки не соответствуют значениям глобальных переменных . 6) Нажмите любую из 4-х кнопок - галочка на кнопке , которую Вы нажали , останется , а с остальных исчезнет . 7) Очистите экран . Нажав Космос , выведите на экран одну проверочную - появится тройка вопросов , полностью соответствующая галочкам на кнопках . Если у Вас есть время , проверьте работу макроса яьКосмос при всех возможных сочетаниях галочек и убедитесь , что его работа не изменилась ни при каком сочетании галочек . 8) Из второй строки макроса ГП удалите “Set ” . Закройте окно Редактора , нажмите любую кнопку панели ГлобальныеПеременные - компьютер сообщит об ошибке . 9) Левой кнопкой нажмите Отладка - выделится строка R = CommandBars ( "ГлобальныеПеременные" ).Controls , что говорит о том , что ошибка именно в этой строке . 10) Левой кнопкой мыши нажмите Сброс ( синий квадратик ) на панели ( “ Стандарт ” ) окна Редактора - выделение со строки R = CommandBars ( "ГлобальныеПеременные" ).Controls снимется . 11) Верните выделявшуюся строку к её первоначальному виду Set R = CommandBars ( "ГлобальныеПеременные" ).Controls Закройте окно Редактора , нажмите любую кнопку панели ГлобальныеПеременные - компьютер сработает нормально . Выполнив обязательную часть урока 42 , Вы узнали оператор Set . Оператор Set определяет объектную переменную ( объектные переменные также называют ссылками или переменными типа Object ) . Чтобы понять , чем объектная переменная отличается от “ обычной ” , выполните или хотя бы прочитайте следующие пункты : 12) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 3 V = Z V = V + 2 Б Z , 11 End Sub Закройте окно Редактора . Нажмите Проверка - напечатается число 3 . 13) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Z = 3 Set V = Z V = V + 2 Б Z , 11 End Sub Закройте окно Редактора . Нажмите Проверка - компьютер сообщит об ошибке . Сравним работу макроса Проверка в версии пункта 12 и макроса ГП : Sub Проверка ( ) Z = 3 V = Z V = V + 2 Б Z , 11 End Sub Sub ГП ( ) Set R = CommandBars ( "ГлобальныеПеременные" ).Controls R ( 1 ).Caption = IIf ( gПомнитьНумерациюВопросов , "V" , " ") & " Помнить" R ( 2 ).Caption = IIf ( gНумероватьВопросы , "V" , " " ) & " Нумеровать" R ( 3 ).Caption = IIf ( gКвадратики , "V" , " " ) & " Квадратики" R ( 4 ).Caption = IIf ( gПечатьОтветов , "V" , " " ) & " Ответы" End Sub В первой строке тела макроса Проверка переменная Z принимает значение 3 . Во второй - переменная V принимает значение переменной Z . В третьей - меняется значение переменной V , но значение переменной Z при этом не меняется , что и демонстрирует выполнение четвёртой строки . В первой строке тела макроса ГП переменная R как бы принимает значение “ объекта ” CommandBars ( "ГлобальныеПеременные" ).Controls ( подобно тому , как во второй строке тела макроса Проверка переменная V принимает значение переменной Z ) . Во второй … пятой строках как бы меняется значение переменной R ( подобно тому , как в третьей строке тела макроса Проверка меняется значение переменной V ) , но на самом деле меняется не значение переменной R ( или не только значение переменной R ) , а ( или но и ) значение объекта CommandBars ( "ГлобальныеПеременные" ).Controls , в отличие от макроса Проверка , в котором значение переменной Z не меняется . На самом деле , если “ обычная ” переменная является самим “ объектом ” и содержит всю содержащуюся в нём информацию , то объектная переменная содержит лишь краткую ссылку на объект , или ( иными словами ) краткий “ адрес ” объекта . Никакие действия над объектной переменной ( кроме применения оператора Set , который может переадресовать объектную переменную ) не меняют её значение , измениться при этом может только значение самого объекта , на который ссылается объектная переменная . Роль объектных переменных в VBA подобна роли ярлыков в Windows , с которыми Вы познакомились в начале настоящей книги ( вероятно , Вы часто пользуетесь ярлыком для быстрого открытия папки “ Шаблоны ” ) . Наш макрос ГП демонстрирует , как применение объектной переменной может сократить код , позволяя избежать многократного повторения длинного имени объекта . Пункт 13 настоящего урока демонстрирует , что VBA может сопоставить адрес , или ссылку , не всякому объекту ( в данном случае VBA не смог сопоставить ссылку переменной с числовым значением ) . Следующий итог К оглавлению
Задача 11 Соответствие кнопок глобальным переменным при открытии шаблона
Сделайте так , чтобы сразу после открытия История.dot галочки на кнопках панели ГлобальныеПеременные всегда соответствовали значениям глобальных переменных . Ответ К оглавлению
Урок 43 Модификация фNot
Когда мы составляем большую книгу , нам нужно , чтобы компьютер не только помнил нумерацию вопросов , но и : □ нумеровал вопросы ; □ нумеровал ответы ( т.е. чтобы не было квадратиков ) ; □ печатал номера верных ответов . Хотелось бы , чтобы это можно было установить одним нажатием кнопки Помнить . Однако , если мы просто изменим макрос ПомнитьНумерациюВопросов , чтобы он выглядел так : Sub ПомнитьНумерациюВопросов() фNot gПомнитьНумерациюВопросов , _ gНумероватьВопросы , gКвадратики , gПечатьОтветов ГП End Sub , то не достигнем поставленной цели , так как нумерации вопросов и печати номеров верных ответов соответствуют значения True переменных gНумероватьВопросы и gПечатьОтветов , а нумерации ответов - значение False переменной gКвадратики ; наша процедура-функция фNot же пока может устанавливать только одинаковые значения всем своим аргументам . К оглавлению 1) В модуль А введите новую процедуру Function фП ( Z ) фП = False If IsNumeric ( Z ) Then If Z > 0 Then фП = True End Function 2) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б фП ( 0 ) , 11 End Sub 3) Нажмите Проверка ( в дальнейшем я не буду напоминать , что , перед тем как левой кнопкой мыши нажать какую-нибудь кнопку на панели История , нужно закрыть окно Редактора , если оно открыто ) - на экране напечатается “ Ложь ” . Это значит , что процедура фП приняла значение False . 4) В макросе Проверка ноль замените на единицу . Нажмите Проверка - на экране напечатается “ Истина ” . Это значит , что процедура фП приняла значение True . 5) В макросе Проверка единицу замените на True . Нажмите Проверка - на экране напечатается “ Ложь ” . 6) В макросе Проверка True замените на False . Нажмите Проверка - на экране напечатается “ Ложь ” . Таким образом , фП принимает значение True , если её аргумент - положительное число , и False в любом другом случае ( если её аргумент ноль , отрицательное число или не число вообще ) . 7) Оставив макрос Проверка в виде Sub Проверка ( ) Б фП ( False ) , 11 End Sub , измените саму процедуру фП , чтобы она выглядела так : Function фП ( Z ) фП = False If IsNumeric ( Z ) And Z > 0 Then фП = True End Function Нажмите Проверка - на экране напечатается “ Ложь ” . 8) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Б фП ( "Дом" ) , 11 End Sub Нажмите Проверка - компьютер сообщит об ошибке . 9) Верните процедуру фП к её первоначальному виду . Нажмите Проверка - на экране напечатается “ Ложь ” . Хотя некоторые математики считают , что любое утверждение либо ложно , либо истинно ( утверждение “ “Дом” > 0 ” для них ложно ) , VBA делит утверждения на три типа : ложные , истинные и некорректные . В VBA строка If Утверждение Then ОператорTrue Else ОператорFalse работает следующим образом : □ Если Утверждение истинно , то выполняется оператор или группа операторов ОператорTrue . □ Если Утверждение ложно , то выполняется оператор или группа операторов ОператорFalse . □ Если Утверждение некорректно , то не выполняется ни ОператорTrue , ни ОператорFalse и “ возбуждается ошибка ” . Утверждение IsNumeric ( "Дом" ) And "Дом" > 0 некорректно , потому что некорректно утверждение "Дом" > 0 . Поэтому если Z = “Дом” , то строка If IsNumeric ( Z ) And Z > 0 Then фП = True возбуждает ошибку . В строке же If IsNumeric ( Z ) Then If Z > 0 Then фП = True сначала проверяется , можно ли значению переменной Z сопоставить какое-нибудь число , и только для случая , когда можно , проверяется , больше ли это число ноля . Поэтому вторая строка ни при каком значении Z не возбуждает ошибку . 10) Измените процедуру фNot , чтобы она выглядела так : Function фNot ( ParamArray zЛогическиепеременные ( ) ) Z = zЛогическиепеременные фNot = Not Z ( 0 ) For k = 0 To Ubound ( Z ) If фП ( Z ( k ) ) Then For kk = k + 1 To k + Z ( k ) zЛогическиепеременные ( kk ) = Not фNot Next kk k = kk - 1 Else zЛогическиепеременные ( k ) = фNot End If Next k End Function 11) Измените макрос ПомнитьНумерациюВопросов , чтобы он выглядел так : Sub ПомнитьНумерациюВопросов ( ) фNot gПомнитьНумерациюВопросов, _ gНумероватьВопросы, 2, gКвадратики, gПечатьОтветов ГП End Sub Несколько раз нажмите Помнить на панели ГлобальныеПеременные - будут менять друг друга 2 состояния кнопок : □ Кнопки Помнить , Нумеровать с галочками ; Квадратики , Ответы - без галочек . □ Наоборот : Помнить , Нумеровать - без галочек ; Квадратики , Ответы - с галочками . 12) В макросе ПомнитьНумерациюВопросов замените 2 на единицу . Несколько раз нажмите Помнить на панели ГлобальныеПеременные - будут менять друг друга 2 состояния кнопок : □ Кнопки Помнить , Нумеровать , Ответы с галочками ; Квадратики - без галочки . □ Наоборот : Помнить , Нумеровать , Ответы - без галочек ; Квадратики - с галочкой . Цель , поставленная нами в начале настоящего урока , достигнута . Смысл работы последней версии нашей процедуры фNot состоит в том , чтобы переключать 2 состояния набора логических переменных . Причём эти 2 состояния должны быть противоположны ( т.е. если какая-то переменная , входящая в набор , в первом состоянии набора равна True , то во втором должна быть равна False , и наоборот : если в первом состоянии набора переменная равна False , то во втором должна быть равна True ) , но в остальном произвольны : в наборе могут быть как только одинаковые по значению переменные ( либо все переменные набора одновременно равны True , либо все переменные набора одновременно равны False ) , так и разные по значению переменные . Например , сразу после выполнения строки фNot Z0, Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9 все переменные Z1 … Z9 будут равны Z0 , а сразу после выполнения строки фNot Z0, 3, Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9 переменные Z4 … Z9 будут равны переменной Z0 , а переменные Z1 … Z3 - противоположны ей . Рассмотрим подробно работу процедуры фNot : В первой строке тела процедуры переменной Z присваивается значение массива zЛогическиепеременные , чтобы дальше можно было в некоторых случаях длинное имя массива заменить коротким именем переменной . Эта строка напомнила Вам , что переменной типа Variant можно присвоить значение массива ; обратное неверно : если бы в процедуру фNot мы ввели строку zЛогическиепеременные = Z , то при выполнении процедуры компьютер сообщил бы об ошибке . Во второй строке тела процедуры самой процедуре присваивается значение , противоположное значению нолевого элемента переменной Z , т.е. нолевого элемента массива zЛогическиепеременные . Строки 3 … 12 занимает цикл по переменной k , пробегающей значения с наименьшего номера элемента массива zЛогическиепеременные по наибольший номер элемента этого массива . Условный оператор в этом цикле действует следующим образом : Если zЛогическиепеременные ( k ) не является положительным числом , то zЛогическиепеременные ( k ) принимает значение равное значению процедуры . Если же zЛогическиепеременные ( k ) - натуральное число , то это число следующих элементов массива принимает значение противоположное значению процедуры ; при этом k увеличивается на это натуральное число ( строку k = kk - 1 можно заменить немного более длинной , зато более понятной строкой k = k + Z ( k ) - работа процедуры от этого не изменится ) , таким образом обеспечивается , что перед тем , как компьютер исполнит строку Next k , k равно номеру последнего изменённого элемента массива . Мы ввели строку k = kk - 1 , а не k = kk потому , что при выходе из For kk переменная kk имеет значение не k + Z ( k ) , а k + Z ( k ) + 1 . Сейчас Вы познакомились с удачным примером изменения значения счётчика цикла в теле цикла ( а не только оператором Next ) . Применяя такой приём , процедуру с аргументом ParamArray можно превратить в самый настоящий язык программирования , в котором некоторые числа и константы будут играть роль операторов . Внимательно прочтя и выполнив урок 43 , Вы : 1) Узнали , что такое некорректное утверждение и почему If … Then If … Then не всегда можно заменить на If … And … Then 2) Вспомнили , что значение массива можно присвоить переменной типа Variant . 3) Познакомились с примером , в котором значение счётчика цикла меняется не только оператором next , но и в теле цикла . 4) Вспомнили , что при выходе из цикла For значение счётчика цикла обычно больше верхнего предела цикла ( если шаг цикла равен единице , то на один больше ) . 5) Узнали и протестировали короткую , но эффективную процедуру-функцию фNot , позволяющую одновременно переключать значения неограниченного числа логических переменных . Эта процедура может оказаться очень полезной для других Ваших шаблонов . Следующий итог К оглавлению
Урок 44 Добавление вопросов
Чтобы продемонстрировать второй способ навигации по проверочным , нам нужно добавить новые вопросы . К оглавлению 1) В оператор Select Case zТипВопроса процедуры Г добавьте новые случаи : Case 23 ББ "Древнеегипетское приспособление для подъёма воды :" , _ "Царь древнего Египта :" , _ "Служитель древнеегипетского или некоторых других " & _ "религиозных культов :" М 0 , "шадуф" , "фараон" , "жрец" П 3 , 2 , 4 Case 24 ББ "Усыпальница фараона или другого знатного " & _ "человека в Древнем Египте :" , _ "Древнеегипетский материал для письма :" М 0 , "пирамида" , "папирус" , "иероглиф" , "клинопись" П 3 , 2 Case 25 ББ "Пожалуй , самый известный нашим современникам фараон :" , _ "По легенде , фразу : ""И ты , Брут"", " & Chr ( 150 ) & _ " перед своей смертью произнёс :" , _ "Учитель Александра Македонского :" М 0 , "Тутанхамон" , "Юлий Цезарь" , "Аристотель" П 3 , 4 , 2 Case 26 Б "Главный бог древних " ББ "египтян" , "славян" , "греков" , "римлян" Б " :" М 0 , "Ра" , "Перун" , "Зевс" , "Юпитер" П 3 Case 27 ББ "Отец Александра Македонского :" , _ "Восстановить господство язычества пытался " & _ "древнеримский император :" , _ "Юлианский календарь ввёл :" М 0 , "Филипп Второй" , "Юлиан Отступник" , "Юлий Цезарь" П 3 , 4 , 3 2) Измените макрос Проверка , чтобы он выглядел так : Sub Проверка ( ) Г 23 , , , 1 Б "gПравильный = " & gПравильный , 11 End Sub Нажмите Проверка - появится текст : Древнеегипетское приспособление для подъёма воды : 1 ) шадуф 2 ) фараон 3 ) жрец gПравильный = 1 3) Подобным образом проверьте все подтипы новых вопросов . 4) В процедуре ДД строку Д 3 , 21.22 замените на Д 3 , 21.27 Нажав Д на панели История , введя цифру 3 в качестве первого диалога и при появлении второго диалогового окна ( “ тип второго диалога ” ) нажав Отмена , проверьте работу новой версии третьего диалога . Выполнив урок 44 , Вы вспомнили : как добавлять новые вопросы и проверять их ; как программировать диалог и проверять его работу . Следующий итог К оглавлению
Урок 45 Второй способ навигации по проверочным
К оглавлению 1) В модуль А введите новые макросы : Sub яэДревнийЕгипет ( ) Задать Z , "номер проверочной" If Z = Empty Then Exit Sub Select Case Z Case 1 ГГ 23 , 24 , 25 Case 2 ГГ 23.2 , 24.2 , 26 End Select End Sub Sub яэДревняяГреция ( ) ГГ 25.3 , 26.3 , 27 End Sub Sub яэДревнийРим ( ) ГГ 25.2 , 26.4 , 27.2 , 8 End Sub 2) Создайте новую панель ДревнийМир , а на ней - кнопки Египет , Греция и Рим для новых макросов . Закрепите новую панель под панелью История ( между История и ГлобальныеПеременные ) . Проверьте работу новых макросов . 3) В модуль А введите новый макрос : Sub яьДревнийМир ( ) фNot CommandBars ( "ДревнийМир" ).Visible End Sub На панели История создайте для него кнопку ДревнийМир и несколько раз нажмите её - новая панель будет должна появляться и исчезать , но на самом деле появляться и исчезать не будет . 4) Измените макрос яьДревнийМир , чтобы он выглядел так : Sub яьДревнийМир ( ) CommandBars ( "ДревнийМир" ).Visible = _ Not CommandBars ( "ДревнийМир" ).Visible End Sub Несколько раз нажмите ДревнийМир - новая панель будет появляться и исчезать . Почему же процедура фNot не действовала при выполнении третьего пункта настоящего урока ? Дело в том , что в качестве аргумента процедуры любое выражение ( а не просто переменная ) воспринимается VBA как аргумент ByVal . Z - пример переменной , Z + D - пример выражения . CommandBars ( "ДревнийМир" ).Visible - не переменная , а выражение , в качестве аргумента процедуры фNot воспринимается как аргумент ByVal , который , в отличие от аргумента ByRef , не может быть изменён процедурой . Выполнив урок 45 , Вы : 1) Вспомнили , как программировать проверочную , создать панель и кнопку . 2) Вспомнили , какое свойство панели задаёт её видимость или невидимость на экране . 3) Вспомнили , что в отличие от переменной выражение поставленное на месте аргумента ByRef процедуры ведёт себя как аргумент ByVal , и стали более полно понимать , что такое выражение , ( чтобы освежить в памяти известное Вам о ключах ByVal и ByRef , перечитайте уроки 14 и 38 ) . 4) Узнали второй способ навигации по проверочным , заключающийся в том , что макрос с кнопкой на панели История ( на панели 1-го уровня ) выводит на экран и скрывает другую панель ( панель 2-го уровня ) с кнопками макросов , каждый из которых либо сам пишет проверочную , либо выводит и скрывает панель 3-го уровня . С панели 3-го уровня можно выводить или скрывать панели 4-го уровня и т.д. . Получается система аналогичная системе вложенных меню . Чтобы понять , что такое система вложенных меню : □ Подведите указатель мыши к верхнему краю экрана - появится головное меню . □ Левой кнопкой мыши нажмите Вставка - выпадет меню , в котором будет и пункт Автотекст . □ Наведите указатель мыши на Автотекст , Обычный - появится кнопка ф . Нажмите её левой кнопкой мыши - появится текст Фамилия , имя _______________________________ Класс __________ Автотекст - меню , вложенное непосредственно в меню Вставка , или - короче - меню в меню Вставка . Обычный - меню в меню Автотекст . ф - кнопка в меню Обычный ( в меню может быть несколько кнопок ) . ф непосредственно вложена только в меню Обычный и вложена в меню Обычный , Автотекст , Вставка . Система “ вложенных ” панелей перед системой вложенных меню имеет 2 преимущества . Первое заключается в том , что при нажатии кнопки в меню все меню , в которые она вложена , закрываются и , чтобы нажать другую кнопку в том же меню , приходится заново открывать всю цепочку меню , которая может быть очень длинной . На панели же кнопка макроса не закрывает , т.е. не скрывает , панель , если в макросе нет оператора скрывающего эту панель . Однако гораздо большее значение имеет второе преимущество , с которым Вы познакомитесь на уроке 47 . Немного о префиксах . Имя каждого макроса , который непосредственно сам или опосредственно пишет проверочные , будем начинать префиксом яь , яэ , яю или яя . Имя макроса , кнопка которого находится на панели 1-го уровня ( т.е. на панели История ) , будем начинать префиксом яь ; имя макроса с кнопкой на панели 2-го уровня - префиксом яэ ; имя макроса с кнопкой на панели 3-го уровня - префиксом яю ; имя макроса с кнопкой на панели 4-го уровня - префиксом яя . Так как таких макросов в дальнейшем Вы или специалист-историк можете создать очень много, то такая система префиксов может помочь относительно быстро находить нужный макрос в окне Редактора и избежать совпадения имён макросов . Следующий итог К оглавлению
Урок 46 TypeName
Так как макросов вызывающих и скрывающих панели может быть очень много , то было бы полезно записывать их кратко . К оглавлению 1) В модуль А введите новую процедуру : Function фПанель ( zИмяпанелиИлиПеременная , Optional zЗначение = False ) If TypeName ( zИмяпанелиИлиПеременная ) = "String" Then Set R = CommandBars ( zИмяпанелиИлиПеременная ) фПанель = R.Visible R.Visible = zЗначение Else фПанель = zИмяпанелиИлиПеременная zИмяпанелиИлиПеременная = zЗначение End If End Function Новая для Вас встроенная функция TypeName определяет , к какому типу относится её аргумент . Если TypeName равна “String” ( между String и кавычками ни одного пропуска ) , то это значит , что значение её аргумента может быть совершенно адекватно передано набором символов заключённым в кавычки . 2) Измените процедуру фNot , чтобы она выглядела так : Function фNot ( ParamArray zЛогическиепеременные ( ) ) Z = zЛогическиепеременные фNot = Not фПанель ( Z ( 0 ) ) For k = 0 To Ubound ( Z ) If фП ( Z ( k ) ) Then For kk = k + 1 To k + Z ( k ) фПанель zЛогическиепеременные ( kk ) , Not фNot Next kk k = kk - 1 Else фПанель zЛогическиепеременные ( k ) , фNot End If Next k End Function После выполнения Вами двух пунктов настоящего урока , работа процедуры фNot слегка изменилась . Процедуре фNot в качестве аргументов мы будем теперь передавать не только логические переменные , но и закавыченные имена панелей . Вызываемая строкой фNot = Not фПанель ( Z ( 0 ) ) процедура фПанель определяет , является нолевой аргумент процедуры фNot логической переменной или закавыченным именем панели . В первом случае фПанель примет значение логической переменной , во втором - значение свойства Visible соответствующей панели ( свойство Visible равно True , если панель видна на экране , и False , если панель скрыта , т.е. не видна ) . В строке фПанель zЛогическиепеременные ( kk ) , Not фNot определяется , является аргумент zЛогическиепеременные ( kk ) логической переменной или закавыченным именем панели . В первом случае значение противоположное значению фNot принимается самим аргументом , во втором - свойством Visible соответствующей панели . Аналогично работает строка фПанель zЛогическиепеременные ( k ) , фNot 3) Выведите на экран панель ГлобальныеПеременные . Несколько раз нажав каждую её кнопку , убедитесь , что работа ни одной из этих кнопок не изменилась , ( сейчас , как и в дальнейшем , под работой кнопки я понимаю работу вызываемого ею макроса ) . 4) Измените макрос яьДревнийМир , чтобы он выглядел так : Sub яьДревнийМир ( ) фNot "ДревнийМир" End Sub Несколько раз нажав кнопку ДревнийМир , убедитесь , что работа макроса яьДревнийМир не изменилась . 5) Измените макрос яьДревнийМир , чтобы он выглядел так : Sub яьДревнийМир ( ) фNot "ДревнийМир", "ГлобальныеПеременные" End Sub Несколько раз нажав кнопку ДревнийМир , убедитесь , что теперь она выводит на экран и скрывает две панели одновременно . Выполнив урок 46 , Вы : 1) Познакомились с встроенной в VBA функцией TypeName . 2) Вспомнили оператор Set . 3) Усовершенствовали процедуру фNot так , что теперь она может не только переключать значения логических переменных , но и выводить на экран и скрывать панели . Эта процедура может быть очень полезной другим Вашим шаблонам . Следующий итог К оглавлению
Урок 47 Омоложение шаблона
Мы выполнили все поставленные собой задачи . Но , пожалуй , нам придётся выполнить ещё три урока . На настоящем уроке мы уберём из шаблона “ пустые ” байты ; на двух следующих - защитим шаблон от возможности изменений , которые может пытаться внести ученик , обучаемый шаблоном посредством диалогов . К оглавлению 1) Удалите Normal.dot . 2) Откройте и сразу же закройте История.dot - в папке шаблонов появится новый , стандартный Normal.dot . 3) Двойным нажатием левой кнопки мыши откройте Normal.dot . 4) Установите ( Файл , Параметры страницы ) параметры страницы , которые мы установили в История.dot : Поля : Верхнее 1,6 см Нижнее 1 см Левое 0,5 см Правое 0,5 см Переплёт 0 см От края до колонтитула : верхнего 0,7 см нижнего 0,7 см Размер бумаги : Ширина 16,7 см Высота 28,5 см Ориентация : книжная 5) Нажмите По умолчанию . 6) Нажмите Формат , Стиль , Организатор , Автотекст и удалите все элементы автотекста из Normal.dot . 7) Закройте Word , сохранив Normal.dot ( возможно , он сохранится автоматически ) . 8) Правой кнопкой мыши нажав История.dot , Свойства , запишите точный размер История.dot в байтах . 9) Двойным нажатием левой кнопки мыши откройте История.dot . 10) Откройте диалоговое окно Организатор ( Формат , Стиль , Организатор ) и скопируйте из История.dot в Normal.dot : □ оба стиля ; □ все три элемента автотекста ; □ все три панели □ и модуль А ( Макросы ) . 11) Откройте окно Редактора , в нём - окно проекта , переименуйте проект Normal в А ( А - латинская ) . 12) Откройте ThisDocument проекта А(История) . 13) На клавиатуре нажмите Ctrl Ф - весь текст в папке ThisDocument выделится . 14) На клавиатуре нажмите Ctrl C - весь текст в папке скопируется в буфер , но никаких видимых изменений не произойдёт . 15) На клавиатуре нажмите серую стрелку вверх - выделение с текста снимется . 16) Откройте папку ThisDocument проекта А(Normal) - она будет пуста . 17) На клавиатуре нажмите Ctrl V - появится текст , который был в папке ThisDocument проекта А(История) . 18) Закройте окно Редактора . Закройте Word , сохранив Normal.dot ( возможно , он сохранится автоматически ) . 19) Запишите точный размер Normal.dot в байтах , - скорей всего , он окажется в полтора … три раза меньше размера История.dot , записанного в пункте 8 . 20) Удалите История.dot . Переименуйте Normal.dot в История.dot . Двойным нажатием левой кнопки мыши откройте новый История.dot . Вплоть до закрытия никаким образом не сохраняя История.dot , убедитесь , что его работа совпадает с работой старого История.dot , насколько Вам позволят убедиться в этом Ваши время и терпение . Закройте Word , не сохраняя История.dot . Убедитесь , что размер История.dot равен размеру Normal.dot , записанному в пункте 19 . 21) Двойным нажатием левой кнопки мыши откройте История.dot . Несколько раз измените галочки на кнопках панели ГлобальныеПеременные , сразу после каждого изменения кроме последнего сохраняя История.dot . Закройте Word , сохранив История.dot в процессе закрытия но не перед закрытием . Запишите точный размер История.dot , - скорей всего , он увеличится в полтора … два раза . У меня размер История.dot , записанный в пункте 8 , был равен 153 600 байтам ; размер Normal.dot , записанный в пункте 19 , совпадая с размером История.dot после выполнения пункта 20 , - 68 095 байтам ; размер История.dot , записанный в пункте 21 , - 123 392 байтам . Таким образом , эффект от “ омоложения ” шаблона может быть весьма большим и весьма хрупким . 22) Откройте модуль А . На клавиатуре нажмите Ctrl ф - весь текст в модуле выделится . 23) На клавиатуре нажмите Ctrl Ч - весь выделенный текст исчезнет ( вырежется в буфер ) . 24) Не закрывая ни окно Редактора , ни модуль А , на клавиатуре нажмите Ctrl S - История.dot сохранится . 25) На клавиатуре нажмите Ctrl V - исчезнувший текст появится вновь . 26) Сохраните История.dot . Закройте окно Редактора . Закройте Word . Запишите точный размер История.dot . У меня в результате выполнения пунктов 22 … 26 размер История.dot упал со 123 392 до 100 352 байтов . 27) На рабочий стол или дискету скопируйте История.dot . 28) Двойным нажатием левой кнопки мыши вновь открыв История.dot , находящийся в папке “ шаблоны ” , - убедитесь , что его работа не изменилась , сохраняя его сразу после каждого ( кроме последнего ) изменения галочек на панели ГлобальныеПеременные . 29) Закройте Word , сохранив История.dot в процессе закрытия но не перед закрытием . Запишите точный размер История.dot . У меня в результате выполнения пунктов 28 , 29 размер История.dot вырос со 100 352 до 138 240 байтов . 30) Удалите История.dot из папки “ шаблоны ” . Скопируйте в неё История.dot , сохранённый Вами в пункте 27 . 31) Почти в точности повторите пункт 28 , сохраняя История.dot сразу после каждого без исключений ( включая последнее ) изменения галочек на панели ГлобальныеПеременные . 32) Закройте Word - если предыдущий пункт Вы выполнили правильно , то компьютер не спросит , сохранить ли История.dot ; но если всё-таки спросит , не сохраняйте История.dot . Запишите точный размер История.dot . У меня в результате выполнения пунктов 31 , 32 размер История.dot не изменился , т.е. остался равным 100 352 байтам . Таким образом , малость размера шаблона в байтах можно сохранить , придерживаясь некоторых правил сохранения шаблона . 33) Откройте диалоговое окно Организатор . 34) Удалите все элементы автотекста из Normal.dot . 35) Из История.dot в Normal.dot скопируйте : □ все три элемента автотекста ; □ все три панели ; □ модуль А ( Макросы ) . 36) Из История.dot удалите всё перечисленное в предыдущем пункте ( три элемента автотекста , три панели и модуль А ) . 37) Закройте диалоговое окно Организатор . Сохраните История.dot . 38) Откройте диалоговое окно Организатор . 39) Обратно из Normal.dot в История.dot скопируйте : □ все три элемента автотекста ; □ все три панели ; □ модуль А ( Макросы ) . Следите за тем , чтобы всё это скопировать именно в История.dot , а не в Документ1 . 40) Закройте диалоговое окно Организатор . Сохраните История.dot . 41) Закройте Word . Запишите точный размер История.dot . У меня в результате выполнения пунктов 33 … 41 размер История.dot упал со 100 352 до 69 632 байтов . 42) Поместив Normal.dot в корзину , но не удалив его из корзины , повторите пункты 31 , 32 . Если Вы всё сделали правильно , то работа История.dot не изменилась и его размер в результате выполнения настоящего пункта не изменится . Если работа История.dot не изменилась , то можете очистить корзину ( если в ней помимо Normal.dot нет других файлов , которые могут понадобиться Вам или другим пользователям ) . 43) Если работа История.dot изменилась или он вообще отказывается открываться или работать , то , скорей всего , что-то из Normal.dot Вы скопировали не в История.dot , а в Документ1 . В таком случае : □ Откройте корзину ( для этого правой кнопкой мыши нажмите сначала саму корзину , затем Открыть ) . □ Правой кнопкой мыши нажмите сначала Normal.dot в открывшейся только что папке , затем Восстановить - Normal.dot вернётся из корзины в “ шаблоны ” . Из восстановленного из корзины Normal.dot Вы можете скопировать в История.dot потерянные элементы . Выполнив урок 47 , Вы познакомились с несколькими способами “ омоложения ” шаблона , т.е. удаления из него “ пустых ” байтов , и с одним правилом сохранения его “ молодости ” . В процессе этого знакомства Вы вспомнили и узнали : 1) Как создать стандартный Normal.dot . 2) Как установить параметры страницы и сохранить их в шаблоне . 3) Как сохранить Normal.dot . 4) Как узнать точный размер шаблона в байтах . 5) Как открыть диалоговое окно Организатор и с его помощью удалять из шаблона и копировать из шаблона в шаблон стили , элементы автотекста , панели и стандартные модули . 6) Как переименовать проект . 7) Как в окне кода выделить весь текст модуля , копировать и вырезать его в буфер , вставить в модуль содержимое буфера и как эти операции использовать для копирования ThisDocument из шаблона в шаблон . 8) Как переименовать файл . 9) Как вернуть файл из корзины . Осталось сказать о главном преимуществе системы вложенных панелей перед системой вложенных меню : Меню не копируются из шаблона в шаблон так легко , как копируются панели . Если в Вашем шаблоне будут сложные , разветвлённые меню , то Вам придётся немало потрудиться , чтобы “ омолодить ” его по полной программе ( по полной программе - значит временно удаляя и все меню или копируя и все меню в “ чистый ” Normal.dot ; “ чистый ” Normal.dot - Normal.dot , полученный из стандартного Normal.dot удалением всех элементов автотекста ) . Возможно , Вы обратили внимание , что в окне Организатор мы могли копировать только созданные нами панели , а к встроенным панелям это окно не даёт доступа . Вот почему не следует никак менять встроенные панели : копировать их из шаблона в шаблон очень трудоёмко . Следующий итог К оглавлению
Урок 48 Защита шаблона ( начало )
Самая надёжная защита шаблона от модификации пользователем - записать его на компакт-диск доступный только для чтения . Однако у Вас вряд ли есть возможность записывать свои программные продукты на такие компакт-диски . Защитить шаблон от непроизвольного изменения Вы можете открыв его не с жёсткого диска , а с защищённой от записи дискеты ( чтобы защитить дискету от записи , сдвиньте заглушку на ней ближе к краю дискеты ) . Однако , если Вы , например , дадите на защищённой от записи дискете наш шаблон ребёнку ( например , чтобы он обучался диалогами ) , то не можете быть уверены , что получите назад неизменённый шаблон , так как хоть в малой степени знакомый с компьютерами ребёнок может сдвинуть заглушку от края дискеты и таким образом снять защиту от записи . К счастью , можно защитить шаблон , где бы он ни находился , в том числе и в случае , когда он находится на жёстком диске . К оглавлению 1) Двойным нажатием левой кнопки мыши откройте История.dot . 2) В текстовом файле , т.е. не открывая окно Редактора , русскими буквами наберите МВЗМ . Вырежьте или скопируйте в буфер этот четырёхбуквенный набор . Этот набор будет нашим паролем . Он кажется совершенно случайным , но на самом деле легко запоминается : МВЗМ - Меркурий , Венера , Земля , Марс . 3) Откройте окно Редактора , а в нём - окно проекта . 4) Правой кнопкой мыши нажмите А(История) , Свойства А … - откроется диалоговое окно “ А - свойства проекта ” . 5) В этом диалоговом окне левой кнопкой мыши нажмите Защита , Блокировать просмотр проекта - появится галочка . 6) В этом же диалоговом окне левой кнопкой мыши нажмите окошечко справа от слова Пароль - в этом окошечке появится курсор . 7) На клавиатуре нажмите Ctrl V - в окошечке появится 4 звёздочки . 8) В этом же диалоговом окне левой кнопкой мыши нажмите окошечко справа от слова Подтверждение - в этом окошечке появится курсор . 9) На клавиатуре нажмите Ctrl V - в окошечке появится 4 звёздочки . 10) Левой кнопкой мыши нажмите ОК - диалоговое окно закроется . 11) Сохраните История.dot . Закройте окно Редактора . Закройте Word . Закрыть Word совершенно необходимо . Наличие введённого сейчас пароля может проявиться только после закрытия Word и повторного открытия История.dot . 12) Двойным нажатием левой кнопки мыши откройте История.dot . 13) Откройте окно Редактора , а в нём - окно проекта . 14) Попробуйте открыть любой из модулей проекта А(История) ( А или ThisDocument ) - появится диалоговое окно “ А пароль ” с окошечком , в котором будет курсор . 15) На клавиатуре нажмите Shift и , не отпуская её , последовательно М , В , З , М ( буквы русские ) - в окошечке появится 4 звёздочки . 16) Левой кнопкой мыши нажмите ОК - диалоговое окно исчезнет . Если появится диалоговое окно “ Проект блокирован ” , то это значит , что у Вас была раскладка не на русские , а на латинские буквы . Левой кнопкой мыши нажмите ОК в окне “ Проект блокирован ” - это окно исчезнет , а в окне “ А пароль ” исчезнут все звёздочки . На клавиатуре нажмите Alt Shift - раскладка изменится . Вновь введите пароль и нажмите ОК - окно “ Проект блокирован ” исчезнет . 17) Обычным образом откройте модули А и ThisDocument . 18) Если у Вас есть время , то : □ Закройте Word , откройте История.dot . Попытайтесь автоматически записать макрос в История.dot - Вам опять придётся ввести пароль . □ Закройте Word , откройте История.dot . Попытайтесь открыть окно Редактора не клавишами Alt F11 , а через меню Сервис , Макрос - Вам опять придётся ввести пароль . Таким образом , введение пароля довольно надёжно защищает от изменения программного кода . Выполнив урок 48 , Вы научились устанавливать пароль на изменение программного кода и правильно вводить этот пароль в случае , когда Вы всё-таки хотите код изменить . Однако это далеко не совершенная защита шаблона , как мы убедимся на следующем уроке . Следующий итог К оглавлению
Урок 49 Защита шаблона ( конец )
К оглавлению 1) Скопируйте История.dot из папки “ шаблоны ” на рабочий стол ( скопировать - значит “ раздвоить ” , у Вас должно стать два идентичных История.dot ; “ скопировать ” нужно отличать от “ переместить ” : переместить - значит убрать файл из одной папки и поместить его в другую , скопировать - значит создать идентичную копию файла и эту копию поместить в другую папку , а в старой папке оставить первоначальный файл ) . 2) Двойным нажатием левой кнопки мыши откройте История.dot в папке “ шаблоны ” . 3) Убедитесь , что все три элемента автотекста шаблона История.dot работают нормально . 4) Переставьте кнопки на панели История , с помощью окна Организатор удалите все элементы автотекста шаблона История.dot . 5) Сохраните История.dot . 6) Закройте Word . Двойным нажатием левой кнопки мыши вновь откройте История.dot . 7) Убедитесь , что внесённые в шаблон изменения действительно сохранились ( элементы автотекста перестали работать , кнопки панели История остались на новых местах ) . 8) Закройте Word . Удалите изменённый История.dot . 9) В папку “ шаблоны ” переместите или - лучше - скопируйте История.dot с рабочего стола . 10) Двойным нажатием левой кнопки мыши откройте История.dot . 11) Измените макрос Я , чтобы он выглядел почти так : Sub Я ( ) On Error Resume Next ChangeFileOpenDirectory "D:\MSoffice\Шаблоны\" Documents.Open "История.dot" , , True ActiveWindow.Close ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True gМножительПаузы = 1 ГП End Sub “ Почти так ” значит , что "D:\MSoffice\Шаблоны\" Вы должны заменить на расположение папки “ Шаблоны ” в Вашем компьютере . 12) Сохраните История.dot . Закройте Word . 13) Двойным нажатием левой кнопки мыши откройте История.dot . 14) Внесите изменения в История.dot . Попробуйте сохранить История.dot - у Вас это не получится . 15) Попробуйте закрыть Word , сохранив История.dot в процессе закрытия , - у Вас это не получится . 16) Закройте Word , не сохраняя История.dot . 17) Двойным нажатием левой кнопки мыши откройте История.dot . Убедитесь , что ни одно из внесённых в История.dot изменений действительно не сохранилось . Закройте Word . 18) Откройте История.dot вторым способом ( однократное нажатие История.dot правой кнопкой мыши , Открыть ) . 19) Переставьте кнопки на панели История . Сохраните История.dot . Закройте Word . 20) Двойным нажатием левой кнопки мыши откройте История.dot . Убедитесь , что внесённые в История.dot изменения действительно сохранились . Закройте Word . 21) Откройте История.dot вторым способом ( однократное нажатие История.dot правой кнопкой мыши , Открыть ) . 22) Измените макрос Я , чтобы он выглядел так : Sub Я ( Z ) On Error Resume Next ChangeFileOpenDirectory "D:\MSoffice\Шаблоны\" Documents.Open "История.dot" , , True If Z = 0 Then ActiveWindow.Close False ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True gМножительПаузы = 1 ГП End Sub 23) Измените макрос Document_New модуля ThisDocument , чтобы он выглядел так : Private Sub Document_New ( ) А.Я 0 End Sub 24) В модуль ThisDocument введите новый макрос : Private Sub Document_Open ( ) А.Я 1 End Sub Document_New автоматически выполняется при создании нового файла , Document_Open - при открытии уже созданного файла . Когда мы “ открываем ” шаблон двойным нажатием левой кнопки мыши , то создаётся новый файл - Документ1 . Когда же мы открываем шаблон вторым способом ( однократное нажатие имени шаблона правой кнопкой мыши , Открыть ) , то открывается этот шаблон и никакого нового файла не создаётся . Я не случайно заключил слово “ открываем ” в кавычки в первом случае : в строгом , профессиональном смысле при двойном нажатии левой кнопки мыши шаблон не открывается . В строгом , профессиональном смысле шаблон можно открыть только вторым способом . И в первом , и во втором случае можно сказать , что шаблон активизируется . Во всей книге профессиональные слова “ активизировать ” , “ активизируется ” я заменяю просторечными , более простыми и короткими словами “ открыть ” и “ открывается ” . 25) Сохраните История.dot . Закройте Word . 26) Откройте История.dot вторым способом ( однократное нажатие История.dot правой кнопкой мыши , Открыть ) . 27) Переставьте кнопки на панели История . Попытайтесь сохранить История.dot - у Вас это не получится . Вы , наверно , обратили внимание , что при закрытии Word компьютер спрашивает , сохранить ли изменения в История.dot ( которые сохранить нельзя ) . Вряд ли такой надоедливый , бессмысленный , издевательский вопрос понравится пользователю . 28) В модуль А введите новый макрос : Sub FileExit ( ) ActiveWindow.View.FullScreen = False ActiveWindow.Close False End Sub 29) Оставаясь в окне Редактора , на клавиатуре нажмите Ctrl S - появится сообщение “ Данный файл открыт только для чтения . … ” . 30) В этом сообщении левой кнопкой мыши нажмите ОК - появится диалоговое окно “ Сохранение документа ” . 31) Во втором снизу оконце этого диалогового окна замените История.dot на Истори.dot ( т.е. уберите букву я ) . 32) Левой кнопкой мыши нажмите Сохранить - окно “ Сохранение документа ” закроется , новая версия шаблона ( с макросом FileExit ) сохранится под именем Истори.dot . 33) Закройте окно Редактора . 34) На клавиатуре нажмите Alt F4 - закроются Документ1 и История.dot ( без вопроса о сохранении изменений в История.dot ) , но не Word . Ещё раз нажмите Alt F4 - закроется Word . 35) Удалите История.dot . Истори.dot переименуйте в История.dot . 36) Откройте ( любым способом ) новый История.dot . 37) Откройте окно Редактора и убедитесь , что новый История.dot содержит введённый Вами макрос FileExit . 38) Закройте окно Редактора . Переставьте кнопки на панели История . 39) Повторите пункт 34 . Откройте История.dot и убедитесь , что никакие внесённые изменения ( перестановка кнопок ) не сохранились . FileExit - встроенная команда Word , закрывающая Word . Введя процедуру с тем же именем , мы “ перегрузили ” эту команду . Теперь вместо встроенной команды выполняется наша процедура . Вместо закрытия Word с дурацким вопросом о сохранении изменений в шаблоне , наша процедура : □ Выключает полноэкранный режим . □ Закрывает активное окно ( текстовый файл и шаблон , “ в котором ” этот текстовый файл создан ) без сохранения изменений ни в текстовом файле , ни в шаблоне . Наш макрос FileExit может работать только до тех пор , пока открыт ( точнее - активизирован ) История.dot . Поэтому двойное нажатие Alt F4 действует следующим образом : □ При первом нажатии выполняется наш макрос FileExit - закрываются текстовый файл и История.dot . □ При втором нажатии ( когда История.dot уже закрыт ) выполняется стандартная встроенная в Word команда FileExit , т.е. закрывается Word . В работу макроса FileExit мы включили выключение полноэкранного режима , чтобы пользователь мог закрыть Word не только кнопками Alt F4 или через меню Файл , Выход , но и нажав крестик в правом верхнем углу . Как и макросы модуля ThisDocument , перегрузку команд возможно использовать в компьютерном хулиганстве . Например , можно запрограммировать , чтобы при закрытии Word происходило удаление всего содержимого текстового файла с сохранением этого файла после этого удаления или даже удаление каких-нибудь файлов ( не обязательно открытых на момент закрытия Word ) . Немного сложнее ( но , пожалуй , морально оправданно ) с помощью макросов модуля ThisDocument и перегрузки встроенных элементов наказать пиратов . Для этого нужно запрограммировать , чтобы макросы модуля ThisDocument и процедуры , одноимённые встроенным элементам , начали хулиганить только по достижении определённой даты или в случае невведения пользователем запрограммированного Вами пароля ( или введения неверного пароля ) . 40) Измените макрос FileExit , чтобы он выглядел так : Sub FileExit ( ) With ActiveWindow .View.FullScreen = False .Close False End With End Sub 41) Повторите пункты 29 … 39 ( выполняя пункт 37 , убедитесь , что макрос FileExit не только существует , но и имеет код , указанный в пункте 40 ) . Сейчас Вы познакомились с оператором With , который , как и оператор Set , позволяет избежать многократного повторения имени объекта . 42) Левой кнопкой мыши нажмите Файл , Закрыть - компьютер спросит , сохранить ли изменения в История.dot ( которые сохранить нельзя ) . Левой кнопкой мыши нажмите Отмена . Нажав Файл , Закрыть , Вы вызвали встроенную в Word команду FileClose . Чтобы при выполнении этой команды компьютер не задавал бессмысленный вопрос , 43) В модуль А введите новый макрос Sub FileClose ( ) FileExit End Sub 44) Сохраните История.dot под именем Истори.dot . Закройте Word . Удалите История.dot . Переименуйте Истори.dot в История.dot . Откройте История.dot . 45) Левой кнопкой мыши нажмите Файл , Закрыть - текстовый файл и История.dot закроются ( без вопроса о сохранении изменений в История.dot ) . На клавиатуре нажмите Alt F4 - закроется Word . Если у Вас есть время , то Вы могли бы перед выполнением 45-го пункта изменить История.dot ( например , переставить кнопки на панели История ) . Но особой нужды в этом нет , так как История.dot автоматически изменяется при открытии ( убираются галочки с кнопок панели ДревнийМир ) . 46) Откройте История.dot . 47) Левой кнопкой мыши нажмите Ш на панели История - появится сообщение “ Данный файл открыт только для чтения . … ” . 48) Левой кнопкой мыши нажмите ОК на этом сообщении - появится диалоговое окно “ Сохранение документа ” . 49) В этом диалоговом окне левой кнопкой мыши нажмите Отмена . 50) Не сохраняя История.dot , в модуль А введите новый макрос : Sub SaveTemplate ( ) MsgBox "Шаблон История.dot защищён от изменения ." & Сб2 End Sub 51) Левой кнопкой мыши нажмите Ш на панели История - появится сообщение : Шаблон История.dot защищён от изменения . Чтобы убрать настоящую справку с экрана , нажмите кнопку ОК настоящей справки или кнопку “Пробел” , Esc или Enter клавиатуры . 52) Левой кнопкой мыши нажмите ОК - не произойдёт ничего кроме того , что с экрана уберётся сообщение ; История.dot при этом не сохранится . 53) Удалите Ш с панели История . 54) Откройте окно Редактора . Разверните его во весь экран , если оно не развёрнуто . 55) Откройте модуль А проекта А(История) . На клавиатуре нажмите Ctrl S и сохраните История.dot под именем Истори.dot . 56) Закройте Word . Удалите История.dot . Переименуйте Истори.dot в История.dot . Откройте История.dot и убедитесь , что кнопка Ш действительно исчезла . 57) Насколько позволяют Ваши время и терпение , протестируйте История.dot и убедитесь , что он работает как надо . Выполнив настоящий , последний ( поздравляю ! ) урок , Вы вспомнили и узнали : 1) Чем “ копировать файл ” отличается от “ переместить файл ” . 2) Что стандартная защита шаблона паролем ( которую мы установили на прошлом уроке ) защищает шаблон не от всех изменений . 3) Оператор ChangeFileOpenDirectory , который активизирует указанную папку . При любом виде открытия ( точнее - активизации ) нашего шаблона активизируется папка “ шаблоны ” . Чтобы понять , что это значит : □ Удалите Normal.dot . □ Откройте История.dot . На клавиатуре нажмите Ctrl Щ - откроется диалоговое окно “ Открытие документа ” , в котором будет открыта папка “ Шаблоны ” . Левой кнопкой мыши нажмите Отмена - диалоговое окно закроется . Закройте Word . □ Откройте Normal.dot ( который будет стандартным , так как Вы недавно удалили Normal.dot ) . На клавиатуре нажмите Ctrl Щ - откроется диалоговое окно “ Открытие документа ” , в котором будет открыта папка “ Мои документы ” . Левой кнопкой мыши нажмите Отмена - диалоговое окно закроется . Закройте Word . 4) Как оператором Documents.Open активизировать шаблон только для чтения . 5) Разницу между двумя способами активизации шаблона . 6) Зачем в модуль ThisDocument могут быть введены макросы Document_New и Document_Open . 7) Встроенные в Word команды FileExit , FileClose , SaveTemplate и что такое перегрузка встроенного элемента . 8) Как сохранить изменения в защищённом от изменения шаблоне . 9) Оператор With . Эпилог К оглавлению
ЭПИЛОГ
Кроме настоящего эпилога , вся настоящая книга написана ещё полтора года назад в WORDе. Я почти не менял её : только исправил опечатки и добавил гиперссылки. С тех пор я приобрёл большой опыт в написании очень больших программ на VBA . При написании и модификации таких программ возникают проблемы , о которых даже трудно заподозрить при написании небольших программ , подобных той , которую Вы написали , если выполнили все уроки и задачи настоящей книги . Методами решения таких проблем я кратко и поделюсь сейчас . К оглавлению 1) Вызов процедур других модулей 2) Древовидная структура программы 3) Перегрузка встроенных элементов 4) Глобальные переменные и константы 5) Аргумент COMMENT 6) Имена аргументов процедур 1) Вызов процедур других модулей Любую процедуру того же проекта можно вызвать , набрав имя модуля , поставив точку и набрав имя самой процедуры . Однако VBA позволяет вызвать процедуру короче , набрав только имя самой процедуры и не указывая имя модуля . В таком случае VBA смотрит , есть ли процедура с таким именем в том же модуле , в который она вызывается . Если да , то вызывается эта процедура ( того же модуля , в который она вызывается ) . Если нет , то VBA ищет процедуру с таким именем в других модулях и вызывает её . Если при этом окажется , что процедура с таким именем есть хотя бы в двух разных модулях , то последствия такого вызова непредсказуемы . Поэтому я принял за правило процедуру того же модуля вызывать кратко , а процедуру другого модуля - полно ( ИмяМодуля.ИмяПроцедуры ) . Исключения из этого правила смотрите в пункте 3 . 2) Древовидная структура программы При создании практически каждой программы пишутся , тестируются , долго-долго доводятся до совершенства процедуры , которые можно использовать в других программах . Чтобы облегчить такой перенос , программу разбивают на модули . Однако , если модули будут связаны друг с другом беспорядочными перекрестными вызовами процедур , то " вытянуть " один модуль ( или небольшую группу модулей ) из всей программы будет невозможно . Чтобы модуль или небольшую группу модулей можно было использовать независимо от остальной ( возможно , очень большой ) части программы , можно придерживаться следующей стратегии : " В основании " программы лежит модуль А . " На " модуле А лежат модули А2 , А4 , А5 , А7 , А8 , А9 . " На " модуле А2 лежат модули А22 , А24 , А25 , А27 , А28 , А29 . " На " модуле А4 лежат модули А42 , А44 , А45 , А47 , А48 , А49 . " На " модуле А5 лежат модули А52 , А54 , А55 , А57 , А58 , А59 . " На " модуле А7 лежат модули А72 , А74 , А75 , А77 , А78 , А79 . " На " модуле А8 лежат модули А82 , А84 , А85 , А87 , А88 , А89 . " На " модуле А9 лежат модули А92 , А94 , А95 , А97 , А98 , А99 . " На " модуле А22 лежат модули А222 , А224 , А225 , А227 , А228 , А229 . " На " модуле А24 лежат модули А242 , А244 , А245 , А247 , А248 , А249 . И т.д. . Процедурами модуля А вызываются ( т.е. используются ) только процедуры самого модуля А . Процедурами модуля А2 вызываются только процедуры модулей А и А2 . Процедурами модуля А4 вызываются только процедуры модулей А и А4 . Процедурами модуля А5 вызываются только процедуры модулей А и А5 . Процедурами модуля А7 вызываются только процедуры модулей А и А7 . Процедурами модуля А8 вызываются только процедуры модулей А и А8 . Процедурами модуля А9 вызываются только процедуры модулей А и А9 . Процедурами модуля А22 вызываются только процедуры модулей А , А2 и А22 . Процедурами модуля А24 вызываются только процедуры модулей А , А2 и А24 . И т.д. . Благодаря такой системе , модуль А не использует никаких элементов других модулей и может быть использован независимо от остальной части программы , т.е. может быть введён в новую программу без введения какого-либо другого модуля старой программы . Точно так же любая из следующих пар модулей : А-А2 , А-А4 , А-А5 , А-А7 , А-А8 , А-А9 - может быть использована независимо от остальной части программы . Точно так же может быть использована независимо от остальной части программы " ветвь " А-А2-А22 , " ветвь " А-А2-А29 , " ветвь " А-А8-А85-А857 и т.д. Точно так же может быть использован независимо от остальной части программы " куст " А-А3-А4 , " куст " А-А3-А39-А4 , " куст " А-А3-А39-А4-А42 , " куст " А-А3-А4-А42 и т.д. . 3) Перегрузка встроенных элементов В VBA есть встроенная функция IIF ( Expression , TruePart , FalsePart ) с тремя обязательными аргументами . Если Expression = True , то IIF принимает значение TruePart . Если Expression = False , то IIF принимает значение FalsePart . Таким образом , встроенная IIF проверяет только одно условие и возможных её значений всего 2 . Хотелось бы , чтобы IIF могла проводить более сложный разбор случаев и была подобна оператору If , в который можно вводить строки ElseIf ... Then Рассмотрим перегрузку встроенной функции Function Iif ( ParamArray vУсловиеЗначение_BDJenV ( ) ) Z = vУсловиеЗначение_BDJenV For k = 0 To UBound ( Z ) - 1 Step 2 If IsObject ( Z ( k ) ) Then t = Z ( k ).Value Else t = Z ( k ) If t <> 0 Then Iif = Z ( k + 1 ) : Exit Function Next If k = UBound ( Z ) Then Iif = Z ( k ) Else Iif = "" End Function ( в имени функции вторая I заменена на i , F на f , чтобы при написании процедуры , в которую вызывается эта функция , напомнить , что мы имеем дело не со встроенной функцией , а с перегрузкой ) . Iif ( Z > 0 , 2 , 4 ) ведёт себя как встроенная функция : если Z положительна , то Iif принимает значение 2 ; если нет , то Iif принимает значение 4 . Таким образом , перегрузка Iif поддерживает обычное употребление встроенной функции IIF : во всех случаях , когда может быть употреблена IIF , может быть употреблена и Iif , которая во всех этих случаях будет вести себя точно так же как IIF . Поэтому , если в программу только ввести рассмотренную процедуру Iif , то работа программы не изменится , сколько бы раз ни вызывалась в неё функция IIF . Однако перегрузка Iif предоставляет гораздо больше возможностей чем встроенная в VBA функция IIF . Главное преимущество в том , что Iif может иметь неограниченно много аргументов . Например , в строке ZZ = Z & " стол" & Iif ( Z > 4 , "ов" , Z > 1 , "а" ) Iif сначала проверяет , выполняется ли условие Z > 4 , если да , то Iif принимает значение "ов" ; если нет , то Iif проверяет , выполняется ли условие Z > 1 , если да , то Iif принимает значение "а" , если нет , то Iif принимает значение "" . Кроме того , в качестве условия Iif понимает не только утверждение , но и число . Например , в строке ZZ = Z & Iif ( Z mod 2 , " не" ) & " делится на 2 ." Iif принимает значение " не" , если Z mod 2 не равно нолю , и значение "" , если Z mod 2 = 0 . Более того , в качестве условия Iif понимает не только утверждение или число , но и флажок ( CheckBox ) и кнопку-переключатель ( OptionButton ) формы , принимая за True состояние флажка или переключателя , при котором тот отмечен ( т.е. выбран ) , за False состояние флажка или переключателя , при котором тот не отмечен ( т.е. не выбран ) . vУсловиеЗначение_BDJenV - " говорящее " имя массива аргументов . " Корень " УсловиеЗначение этого имени показывает , что чётные ( нолевой , второй , четвёртый и т.д. ) элементы массива аргументов воспринимаются процедурой как условия , нечётные ( первый , третий , пятый и т.д. ) - задают возможные значения процедуры . Префикс v ( напоминающий о ключе ByVal ) показывает , что никакой элемент массива аргументов не может быть изменён процедурой . Окончание BDJenV показывает , что чётный элемент массива аргументов может быть утверждением , числом или объектом , нечётный - любым . ( en - сокращение английского then ( потом ) , B - первая буква Boolean ( логический тип переменных ) , D - первая буква Decimal ( тип " обычных " - без порядка - десятичных дробей ) , J - третья буква Object ( объектный тип переменных ) , V - первая буква Variant ( универсальный тип переменных ) ) Разумно : □ все перегрузки встроенных элементов собрать в " корневом " модуле А ; □ при вызове их не указывать имя модуля , т.е. вызывать их кратко ; □ давать перегрузкам имена , отличающиеся от имён встроенных элементов тем , что некоторые большие буквы заменены на малые , а некоторые малые - на большие ( при выполнении программы большая и малая буквы в имени процедуры не различаются , если же при написании программного кода ввести имя перегрузки без соблюдения регистра , то VBA автоматически сделает его идентичным имени перегрузки по регистру , что подскажет Вам - или другому программисту , - что вызывается перегрузка , а не встроенный элемент ) ; □ добиваться , чтобы перегрузка встроенной функции поддерживала обычное употребление этой функции . Впрочем , Вы можете вызвать встроенный элемент даже при наличии его перегрузки , набрав VBA.ИмяВстроенногоЭлемента . Это необходимо , когда Вы перегрузку встроенного элемента определяете через этот же встроенный элемент . Например : Function isNumeric ( ParamArray vV ( ) ) As Boolean isNumeric = True For k = 0 To UBound ( vV ) If Not VBA.isNumeric ( vV ( k ) ) Then isNumeric = False: Exit Function Next End Function ( эта перегрузка хороша тем , может иметь неограниченно много аргументов ( равна True , если каждый аргумент может быть воспринят VBA как число , и False , если хотя бы один аргумент не может быть воспринят VBA как число ) , встроенная же функция всегда имеет только один аргумент ) . Рассмотрим ещё один , простой , но важный , пример перегрузки : Function CHr ( Optional vСимволLDS = 160 , Optional vЧислоСимволовDm05 = 1 ) CHr = String ( vЧислоСимволовDm05 , vСимволLDS ) End Function Встроенная функция Chr имеет один , обязательный аргумент - число не меньше -0,5 , задающее строку из одного символа , которой равна Chr . Перегрузка CHr может равняться строке из произвольного числа символов . Причём повторяющийся символ может быть задан не только числом , но и самим этим символом . Ни один из аргументов CHr не является обязательным . CHr без аргументов равна Chr ( 160 ) , т.е. неразрывному пробелу . CHr поддерживает обычное употребление Chr . 4) Глобальные переменные и константы В VBA глобальные переменные и константы делятся на закрытые ( вводимые оператором Private или Dim ) и открытые ( вводимые оператором Public ) . Закрытые переменные и константы " видимы " только в том модуле , в котором они объявлены . Открытые - во всех модулях проекта . Иначе говоря , изменить и " узнать " значение закрытой переменной может любая процедура того модуля , в котором эта переменная объявлена , но никакая процедура никакого другого модуля не может это сделать , изменить и " узнать " значение открытой переменной может любая процедура любого модуля проекта ; аналогично , " узнать " значение закрытой константы может любая процедура того модуля , в котором эта константа объявлена , но никакая процедура никакого другого модуля не может это сделать , " узнать " значение открытой константы может любая процедура любого модуля проекта . Таким образом , открытые переменные и константы " более глобальны " чем закрытые . Глобальные переменные позволяют сократить число аргументов процедур , давая процедурам ещё один способ обмена информацией . Глобальные константы позволяют сократить программный код , позволяя многократное повторение длинного выражения заменить повторением относительно короткого имени константы . Например , константа gsДа1нет0 объявленная следующим образом : Public Const gsДа1нет0 = " ?" & vbCr & _ "Да -- 1" & vbCr & _ "Нет -- 0" позволяет выражение " ?" & vbCr & "Да -- 1" & vbCr & "Нет -- 0" заменять на gsДа1нет0 Чем шире область " видимости " глобальной переменной или константы , тем больший эффект она может дать . Поэтому разумно вообще не вводить закрытые переменные и константы , используя только открытые . Однако в очень большой программе , состоящей из большого числа модулей , при плохо продуманной системе наименования имена открытых переменных или констант из разных модулей могут случайно совпасть . Это совершенно неприемлемо (возможно , VBA и не позволит это сделать ) , так как каждая открытая переменная и каждая открытая константа должна выполнять важную и уникальную функцию . Избежать случайного совпадения имён открытых переменных или констант из разных модулей позволяют префиксы . Разумно выполнять правила : □ Префикс состоит только из цифр и латинских букв g , s и n , а следующий за ним " корень " начинается с буквы , отличной от этих трёх букв . □ Каждая открытая переменная , объявленная в модуле А , имеет префикс g ; каждая открытая переменная , объявленная в модуле А2 , имеет префикс g2 ; каждая открытая переменная , объявленная в модуле А549 , имеет префикс g549 и т.д. . Наиболее употребительные переменные могут состоять только из префикса . □ Каждая открытая константа , объявленная в модуле А , имеет префикс gs или gn ( префикс gs имеет константа , равная строке , например "натуральное ( целое положительное )" , префикс gn имеет константа , равная числу , например 3,141593 ) ; каждая открытая константа , объявленная в модуле А8 , имеет префикс gs8 или gn8 ; каждая открытая переменная , объявленная в модуле А7749 , имеет префикс gs7749 или gn7749 и т.д. . При соблюдении этих правил достаточно следить , чтобы в одном модуле не совпали имена двух открытых переменных или двух открытых констант ( при соблюдении вышеуказанных правил имя открытой переменной не может совпасть с именем открытой константы , так как они имеют разные префиксы ) . 5) Аргумент COMMENT При введении в программный код вызова процедуры , VBA выводит имя каждого аргумента этой процедуры и его значение по умолчанию , если оно имеется . Поэтому в конец списка аргументов процедуры бывает разумно ввести аргумент COMMENT с комментарием , который процедура " возьмёт с собой " во всякое место , куда бы её ни вызвали . Например , процедура Function ББ ( vD , _ Optional Comment = " Показываю отрицательное число с большим минусом ; практически " & _ " необходима при выведении отрицательного числа в InputBox или MsgBox , позволяя " & _ " пользователю без напряжения зрения различать отрицательное и положительное числа " ) ББ = Iif ( vD < 0 , CHr ( 151 ) & CHr & -vD , vD ) End Function имеет аргумент vD , который однозначно задаёт её значение , и аргумент Comment , который никак не влияет на её работу . Если в программный код введён вызов процедуры ББ , то в том месте всегда можно посмотреть пояснение об её назначении . Для этого нужно установить курсор перед первым аргументом и нажать кнопку пробела ( длинную без надписи ) - появится прямоугольник с текстом : ББ ( vD , [Comment = " Показываю отрицательное число с большим минусом ; практически необходима при выведении отрицательного числа в InputBox или MsgBox , позволяя пользователю без напряжения зрения различать отрицательное и положительное числа "] ) 6) Имена аргументов процедур При введении в программный код вызова процедуры , VBA выводит имена аргументов этой процедуры . Поэтому разумно , чтобы имена аргументов были " говорящими " , имя аргумента должно пояснять : □ какова функция аргумента в вызываемой процедуре ; □ может ли процедура изменить значение аргумента ; □ каким должно быть входное значение аргумента , т.е. значение аргумента перед работой процедуры ; □ каким может быть выходное значение аргумента , т.е. значение аргумента сразу после завершения работы процедуры . Разумно информацию о возможности изменения значения аргумента заключить в префикс , информацию о допустимых входных и возможных выходных значениях аргумента - в окончание ( если о значениях аргумента легко догадаться , окончание может быть выпущено ; префикс же выпускать никогда не следует , так как префиксы нужны и для того , чтобы имена аргументов отличать от имён процедур , меток , констант и других переменных ) , информацию о функции , смысле аргумента - в корень между префиксом и окончанием ( если кратко пояснить функцию аргумента невозможно , корень может быть выпущен ) . Если процедура не может изменить значение аргумента , разумно его имени дать префикс v . Чтобы процедура не могла изменить значение аргумента , совсем не обязательно вводить ключ ByVal . Во-первых , часто бывает , что в теле процедуры нет ни одной строки , изменяющей значение аргумента . Во-вторых , если есть хотя бы одна такая строка , то в начало процедуры можно ввести строку Z = аргумент и в дальнейшем работать с переменной Z , а не с аргументом . Разумно совсем не использовать ключ ByVal , так как он увеличивает всплывающую подсказку об аргументах процедуры , автоматически даваемую редактором программного кода , и мешает восприять её . Если процедура может изменить значение аргумента , разумно его имени дать префикс R , Rav , Rm , или R0_ , R1_ , ... , R9_ , R01_ , R39_ и т.д. . Префикс Rm значит , что значение аргумента может быть изменёно процедурой только в том случае , если необязательный аргумент не инициализирован ( т.е. выпущен при вызове процедуры ) или если в качестве аргумента ( необязательно необязательного ) использована неинициализированная переменная . Например , если в стандартный Normal.dot ввести процедуры Function Б ( V , Optional Rm ) If IsMissing ( Rm ) Then Rm = V Б = Rm End Function Function Г ( Optional V ) Г = V End Function Sub Проверка() Selection.TypeText Б ( 2 , 4 ) End Sub , для макроса Проверка создать кнопку и нажать эту кнопку , то на экран выведется число 4 . Если в макросе Проверка Б ( 2 , 4 ) заменить на Б ( 2 ) , то на экран выведется число 2 . Если в макросе Проверка Б ( 2 ) заменить на Б ( 2 , Г ) , то на экран опять выведется число 2 . Если в макросе Проверка Б ( 2 , Г ) заменить на Б ( 2 , Г ( 5 ) ) , то на экран выведется число 5 . Если макрос Проверка привести к виду Sub Проверка ( ) m = Г Selection.TypeText Б ( 2 , m ) End Sub , то на экран выведется число 2 . Если макрос Проверка привести к виду Sub Проверка() m = Г Б 2 , m Selection.TypeText m End Sub , то на экран опять выведется число 2 . При этом мы убедимся , что процедура Б действительно может изменить значение последнего аргумента , если тот не инициализирован . Если процедуру Б привести к виду Function Б ( V , Rm ) If IsMissing ( Rm ) Then Rm = V Б = Rm End Function ( т.е. если просто сделать аргумент Rm обязательным ), то на экран опять выведется число 2 . Префикс R0_ значит , что аргумент - массив ( частный случай - ParamArray ) и что процедура может изменить только нолевой ( крайне левый ) элемент этого массива . Префикс R1_ значит , что аргумент - массив ( частный случай - ParamArray ) и что процедура может изменить только первый ( следующий за крайне левым ) элемент этого массива . Префикс R09_ значит , что аргумент - массив ( частный случай - ParamArray ) и что процедура может изменить только нолевой ( крайне левый ) и девятый элементы этого массива . Префикс R139_ значит , что аргумент - массив ( частный случай - ParamArray ) и что процедура может изменить только первый , третий и девятый элементы этого массива . Префикс R или Rav разумно дать имени аргумента , если процедура может изменить его значение , но применение префикса Rm или R0_ ( R1_ , R7_ , R9_ , R10_ , R11_ , R02_ и т.д. ) неуместно . В таком случае разумно употребить префикс Rav , если входное значение аргумента не может повлиять на работу процедуры ( в том числе и на выходное значение этого же аргумента ) ; если же входное значение аргумента может повлиять на работу процедуры , то разумно употребить префикс R . ( a - первая буква английского слова any - любой ; av - сокращение от any входное) В моих программах R иногда употребляется вместо Rav , так как система наименования формировалась постепенно . В окончании имени аргумента разумно использовать латинские буквы B , N , L , D , S , J , R , M , V . Буква B значит , что аргумент может иметь логическое значение ( True или False ) . Буква N значит , что аргумент может иметь натуральное значение ( 1 ; 2 ; 3 ; 4 и т.д. ) . Буква L значит , что аргумент может иметь целое значение ( 0 ; 1 ; -1 ; 2 ; -2 и т.д. ) . Буква D значит , что значением аргумента может быть любое вещественное число . Буква S значит , что аргумент может иметь значение типа String ( например , "Дом" ) . Буква J значит , что значением аргумента может быть ссылка на объект . Буква R значит , что значением аргумента может быть массив . Буква M значит , что аргумент может быть неинициализирован . Буква V значит , что аргумент может иметь любое значение . В качестве примера рассмотрим процедуру Function Обмен ( R , R1 , Optional vУсловиеВыполненияBD = True , Optional Comment = "Я = s1 - s" ) On Error Resume Next If vУсловиеВыполненияBD <> 0 Then Z = R : R = R1 : R1 = Z Обмен = R1 - R End Function Окончание BD значит , что значение аргумента vУсловиеВыполненияBD может быть только логическим или числом . Причём , логическое значение - " нормальное " , т.е. предпочтительное ; число же - только допустимо , или терпимо . Comment Я = s1 - s значит , что процедура-функция принимает значение разности выходных значений первого ( R1 ) и нолевого ( R ) аргументов ( если , конечно , такую разность можно вычислить ) . Если процедура не может изменить значение аргумента , то входное и выходное значения аргумента совпадают , то можно просто характеризовать допустимые значения аргумента . Если же процедура может изменить значение аргумента , то выходное значение аргумента ( сразу после окончания работы процедуры ) может отличаться от его входного значения ( перед началом работы процедуры ) , то можно характеризовать допустимые входные или возможные выходные значения аргумента . Если характеризуются только выходные значения аргумента , то разумно в конце окончания ставить букву s ( обязательно малую ) . Если характеризуются только входные значения аргумента , то разумно в конце окончания ставить букву v ( обязательно малую ) . Если характеризуются как входные , так и выходные значения аргумента и множества этих значений различаются , то разумно сначала охарактеризовать входные значения , затем поставить малую v и наконец охарактеризовать выходные значения ( для русскоязычного программиста получается очень понятная подсказка что-то во что-то ) . Например , окончание DvL значит , что исходные вещественные значения аргумента переходят в целые . Если характеризуются как входные , так и выходные значения аргумента и множество входных значений совпадает с множеством выходных значений , то разумно не использовать ни s , ни v . Рассмотрим несколько примеров процедур . Function ДробьвДваЦелых_ND1M ( vДробьDR1J , _ RavЦелаяЧастьLVs , RavИзДробнойЧастиLVs , Optional vИзНолевойДробнойLV , _ Optional Comment = "Я = |s1 - s2| + 1" ) Z3v = vИзНолевойДробнойLV If IsArray ( vДробьDR1J ) Then RavЦелаяЧастьLVs = vДробьDR1J ( 0 ) RavИзДробнойЧастиLVs = vДробьDR1J ( 1 ) Else If IsObject ( vДробьDR1J ) Then Z = CDec ( vДробьDR1J.Text ) Else Z = CDec ( vДробьDR1J ) RavЦелаяЧастьLVs = Fix ( Z ) RavИзДробнойЧастиLVs = Abs ( Z - RavЦелаяЧастьLVs ) If RavИзДробнойЧастиLVs = 0 Then RavИзДробнойЧастиLVs = Iif ( IsMissing ( Z3v ) , RavЦелаяЧастьLVs , Z3v ) Else If RavИзДробнойЧастиLVs < 0.1 Then _ RavИзДробнойЧастиLVs = -RavИзДробнойЧастиLVs While Not П ( RavИзДробнойЧастиLVs - Fix ( RavИзДробнойЧастиLVs ) , 0 , 0.1 , -0.1 ) RavИзДробнойЧастиLVs = 10 * RavИзДробнойЧастиLVs Wend RavИзДробнойЧастиLVs = Fix ( RavИзДробнойЧастиLVs ) End If End If If isNumeric ( RavЦелаяЧастьLVs , RavИзДробнойЧастиLVs ) Then _ ДробьвДваЦелых_ND1M = Abs ( RavЦелаяЧастьLVs - RavИзДробнойЧастиLVs ) + 1 End Function Префикс v аргумента vДробьDR1J значит , что его значение не может быть изменено процедурой . Окончание DR1J характеризует множество допустимых значений этого аргумента . " Наиболее нормальное " значение аргумента - вещественное число , десятичная дробь , ( поэтому первая буква окончания - D ) , так как рассматриваемая процедура создавалась , чтобы пару целых чисел можно было задавать десятичной дробью , это и осталось её главной функцией : обычное , наиболее частое , применение рассматриваемой процедуры состоит в том , чтобы десятичную дробь , передаваемую рассматриваемой процедуре через значение аргумента vДробьDR1J , разложить на два целых числа , передаваемых вызывающей процедуре через значения аргументов RavЦелаяЧастьLVs и RavИзДробнойЧастиLVs . Однако два целых числа могут быть заданы не только десятичной дробью , но и массивом из двух элементов , каждый из которых равен целому числу . Что рассматриваемая процедура может провести такой разбор , и говорит часть R1 окончания аргумента ( R говорит , что аргумент может быть массивом ; цифра 1 говорит , что этот массив должен состоять из двух элементов : с нолевого по первый ) . Задать два целых числа может также пользователь , введя десятичную дробь в окошечко какой-нибудь формы . Что рассматриваемая процедура рассчитана и на такой случай ( при котором значением аргумента vДробьDR1J будет объект ) , говорит часть J окончания аргумента . Префикс Rav аргумента RavЦелаяЧастьLVs значит , что его значение может быть изменено процедурой и что входное его значение никак не влияет на работу процедуры ( в частности , выходное значение этого аргумента не зависит от его входного значения ) . Автоматическое переименование процедур и переменных
Ответ к 1-й задаче
Условие задачи 1) В начале модуля А строку Public gПравильный, gПауза, gВерных, gНеверных замените на Public gПравильный, gПауза, gВерных, gНеверных, gПропущенных 2) В процедуре Г Select Case InputBox(zСб, zЗг, 0) Case Empty Case gПравильный gВерных = gВерных + 1 MsgBox "Ответ верен . Поздравляем Вас !" & Сб2, , _ "Верных ответов " & gВерных & " Неверных " & gНеверных Case Else gНеверных = gНеверных + 1 MsgBox "Ответ неверен . Повторите попытку ." & Сб2, , _ "Верных ответов " & gВерных & " Неверных " & gНеверных Г zТипВопроса, True End Select замените на Select Case InputBox(zСб, zЗг, 0) Case Empty gПропущенных = gПропущенных + 1 Case gПравильный gВерных = gВерных + 1 MsgBox "Ответ верен . Поздравляем Вас !" & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных Case Else gНеверных = gНеверных + 1 MsgBox "Ответ неверен . Повторите попытку ." & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных Г zТипВопроса, True End Select 3) В макросе Проверка строку gВерных = 0: gНеверных = 0 замените на gВерных = 0: gНеверных = 0: gПропущенных = 0 4) В макросе Проверка MsgBox " Конец" & Аб & "Верных ответов " & _ gВерных & Аб & "Неверных ответов " & gНеверных & Сб2 End Sub замените на MsgBox " Конец" & Аб & "Верных ответов " & _ gВерных & Аб & "Неверных ответов " & gНеверных & _ Аб & "Пропущенных вопросов " & gПропущенных & Сб2 End Sub 5) Нажмите Проверка и посмотрите , что получится , ( хотя бы один раз нажмите Отмена ) . 6) Вы убедились , что макрос работает нормально . Однако в процедуре Г MsgBox "Ответ верен . Поздравляем Вас !" & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных и MsgBox "Ответ неверен . Повторите попытку ." & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных почти совпадают . Чтобы упростить код : □ В модуль А введите новую процедуру : Sub Справка2(zСб) MsgBox zСб & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных End Sub □ В процедуре Г MsgBox "Ответ верен . Поздравляем Вас !" & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных замените на Справка2 "Ответ верен . Поздравляем Вас !" □ В той же процедуре Г MsgBox "Ответ неверен . Повторите попытку ." & Сб2, , _ "Верных ответов " & gВерных & _ " Неверных " & gНеверных & _ " Пропущенных вопросов " & gПропущенных замените на Справка2 "Ответ неверен . Повторите попытку ." □ В процедуре Проверка MsgBox " Конец" & Аб & "Верных ответов " & _ gВерных & Аб & "Неверных ответов " & gНеверных & _ Аб & "Пропущенных вопросов " & gПропущенных & Сб2 замените на Справка2 " Конец" 7) Нажмите Проверка и посмотрите , что получится . Условие задачи К оглавлению
Ответ ко 2-й задаче
Условие задачи 1) В модуль А введите новую процедуру : Sub Д(ParamArray zТипыВопросов()) End Sub 2) В эту процедуру из процедуры Проверка2 переместите MsgBox " Выполнение вызванного Вами макроса может занять " & _ "слишком много времени ." & Аб & _ "Вы можете в любой момент прервать его работу . Для этого" & _ " достаточно нажать кнопку" & _ " ""Ctrl"" и , не отпуская её , кнопку ""Pause Break"" ." & Сб2 3) Между перемещённым куском и End Sub введите : For k = 0 To UBound(zТипыВопросов) Dc = CDec(zТипыВопросов(k)) k2 = Int(Dc) k4 = Dc - k2 If k4 = 0 Then Г k2, True, Timer Else While k4 - Int(k4) > 0 And k4 - Int(k4) <> 0.1 k4 = 10 * k4 Wend k4 = Int(k4) For kk = k2 To k4 Step IIf(k2 > k4, -1, 1) Г kk, True, Timer Next kk End If Next k Обратите внимание , что для внешнего и внутреннего циклов For мы используем разные имена счётчиков ( k и kk ) . Если бы имена совпадали , то работа внутреннего цикла делала бы работу внешнего , как правило , совершенно неправильной . 4) В макросе Проверка2 Г 12, True, Timer Г 0, True, Timer Г 7, True, Timer For k = 16 To 20 Г k, True, Timer Next k замените на Д 12, 0, 7, 16.201 5) Удалите макрос Проверка . 6) Макрос Проверка2 переименуйте в Проверка . 7) Нажмите Проверка и посмотрите , что получится . Условие задачи К оглавлению

Ответ к 3-й задаче Условие задачи 1) Существующую на настоящий момент процедуру ББ4 замените на Sub ББ4(ParamArray zВопросНомерответа()) Z = zВопросНомерответа gПодТипВопроса = gПодТипВопроса Mod (UBound(Z) + 1) \ 2 ZZ = gПодТипВопроса * 2 Б Z(ZZ) gПравильный = Z(ZZ + 1) End Sub Sub ББ5(ParamArray zВопросНомерответа()) Z = zВопросНомерответа ZZ = (gПодТипВопроса Mod (UBound(Z) + 1) \ 2) * 2 Б Z(ZZ) gПравильный = Z(ZZ + 1) End Sub 2) Протестируйте подтипы 1 , 2 , 7 и 8 третьего вопроса и убедитесь , что в подтипах 7 и 8 вновь появился текст " была в составе" , ( можете протестировать и другие подтипы ) . Работа новой процедуры ББ4 отличается от работы её старой версии тем , что меняется значение переменной gПодТипВопроса . Благодаря этому , процедура Б4 стала работать должным образом . Однако , как будет показано на следующем уроке , может понадобиться и неизменённое значение переменной gПодТипВопроса . Поэтому мы сохранили старую версию этой процедуры ( под именем ББ5 ) . Условие задачи К оглавлению

Ответ к 5-й задаче
Условие задачи 1) В модуль А введите новую процедуру Sub Б5(zВариантовВопроса, zПоКакой, ParamArray zТекстЧисло()) GG = zТекстЧисло БА gПодТипВопроса Mod zВариантовВопроса + 1 <= zПоКакой End Sub 2) В третьем случае оператора Select Case zТипВопроса процедуры Г строку Б2 6, 1, 2, " была в составе" замените на Б5 6, 2, " была в составе" 3) Проверьте третий вопрос и убедитесь , что его работа не изменилась . Условие задачи К оглавлению
Ответ к 6-й задаче
Условие задачи Сейчас число разных подтипов 22-го вопроса равно 3 • 7 • 5 • 5 • 11 = 5775 . Однако минимальный период повторения подтипов равен 3 • 7 • 8 • 5 • 11 = 9240 ( для любого натурального N подтип N совпадает с подтипом N + 9240 ) . Так как минимальный период больше числа разных подтипов и не кратен ему , то некоторые подтипы будут встречаться чаще других . В нашем случае среди первых 9240 подтипов ( а также среди любых 9420 натуральных подтипов , следующих подряд друг за другом ) - каждый подтип с фамилией Леннон , Маккартни или Харрисон встретится два раза , а каждый подтип с фамилией Стар или Бест - только один раз . Условие задачи К оглавлению
Ответ к 8-й задаче
Условие задачи С помощью ключа ParamArray процедуре может быть передано сколь угодно много массивов , точнее - число и размер передаваемых массивов ограничиваются только возможностями “ железа ” компьютера . С помощью ключа ParamArray процедуре может быть передано сколько угодно аргументов . Так как любой из этих аргументов может быть массивом , то процедуре может быть передано сколько угодно массивов . В частности , любой аргумент , передаваемый с помощью ключа ParamArray , может быть задан функцией Array . Условие задачи К оглавлению
Ответ к 9-й задаче
Условие задачи 1) Измените процедуру ДаНет , чтобы она выглядела так : Sub ДаНет ( ParamArray zРезультатВопрос ( ) ) For k = 0 To Ubound ( zРезультатВопрос ) Step 2 zРезультатВопрос ( k ) = MsgBox ( zРезультатВопрос(k + 1) , 292) = 6 Next k End Sub 2) В макросе яьКосмос строки ДаНет Z2, "Нумеровать вопросы ?" ДаНет Z4, "Перед вариантами ответа вставлять квадратики ?" замените на ДаНет Z2, "Нумеровать вопросы ?", _ Z4, "Перед вариантами ответа вставлять квадратики ?" 3) Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . Естественно , теперь процедурой ДаНет Вы можете задать значения любого числа логических переменных ( точнее - это число ограничено только “ железом ” компьютера ) . Условие задачи К оглавлению
Ответ к 10-й задаче
Условие задачи 1) Измените процедуру-функцию фДаНет , чтобы она выглядела так : Function фДаНет ( ParamArray zВопросРезультат ( ) ) фДаНет = MsgBox ( zВопросРезультат ( 0 ) , 292 ) = 6 Z = Ubound ( zВопросРезультат ) If Z Mod 2 = 1 Then zВопросРезультат ( 1 ) = фДаНет For k = 1 + Z Mod 2 To Z Step 2 zВопросРезультат ( k + 1 ) = фДаНет ( zВопросРезультат ( k ) ) Next k End Function 2) Убедитесь , что макрос яьКосмос по-прежнему выглядит так : Sub яьКосмос ( ) Задать Z , "номер проверочной", , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГG 16, 20.2, 18 Case 2 ГГG 16.2, 20, 19 Case 3 ГГG 16.3, 20.3, 17 End Select ГГА фДаНет( "Нумеровать вопросы ?" ) , _ фДаНет ( "Перед вариантами ответа вставлять квадратики ?" ) End Sub Если это не так , приведите его именно к такому виду . Обратите внимание , что фДаНет используется именно как процедура-функция ( а не процедура Sub ) с одним аргументом . 3) Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . 4) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной", , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГG 16, 20.2, 18 Case 2 ГГG 16.2, 20, 19 Case 3 ГГG 16.3, 20.3, 17 End Select фДаНет "Нумеровать вопросы ?", Z2, _ "Перед вариантами ответа вставлять квадратики ?", Z4 ГГА Z2, Z4 End Sub Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . Обратите внимание , что фДаНет используется как процедура Sub . 5) Измените макрос яьКосмос , чтобы он выглядел так : Sub яьКосмос ( ) Задать Z , "номер проверочной", , , 3 If Z = Empty Then Exit Sub Select Case Z Case 1 ГГG 16, 20.2, 18 Case 2 ГГG 16.2 , 20 , 19 Case 3 ГГG 16.3 , 20.3 , 17 End Select ГГА фДаНет("Нумеровать вопросы ?" , _ "Перед вариантами ответа вставлять квадратики ?" , Z4) , Z4 End Sub Закройте окно Редактора . Несколько раз нажав Космос , убедитесь , что работа макроса яьКосмос не изменилась . Обратите внимание , что ответом на первый вопрос определяется значение самой процедуры-функции фДаНет , ответом на второй - значение переменной Z4 . Разберём подробно работу фДаНет ( прежде чем читать следующий абзац , откройте окно Редактора и найдите в нём код этой процедуры-функции ) . Благодаря ParamArray , фДаНет может иметь неограниченное число аргументов . Эти аргументы нумеруются с ноля : аргумент , стоящий первым в списке , компьютер считает нолевым элементом массива zВопросРезультат ; аргумент , стоящий вторым , - первым и т.д. . Последний аргумент , с точки зрения компьютера , имеет номер на единицу меньший общего числа аргументов . Вслед за компьютером , аргумент , стоящий в списке первым , я буду называть нолевым ; стоящий вторым - первым и т.д. . Число аргументов фДаНет может быть чётно или нечётно . Если чётно - число логических переменных среди аргументов равно числу вопросов ( нолевой , 2-й , 4-й , … аргументы - вопросы ; 1-й , 3-й , 5-й , … аргументы - логические переменные ) , если нечётно - логических переменных на одну меньше чем вопросов ( нолевой , 1-й , 3-й , 5-й , … аргументы - вопросы ; 2-й , 4-й , 6-й , … - логические переменные ) . Первая строка тела процедуры присваивает фДаНет значение ответа на первый вопрос ( нолевой аргумент ) . Вторая строка присваивает локальной переменной Z номер последнего аргумента , который на один меньше числа аргументов ( поэтому если число аргументов чётно , то значение Z нечётно , и наоборот ) . В третьей строке определяется чётность числа аргументов : если число аргументов чётно ( и тогда первый аргумент - логическая переменная ) , то значение Z нечётно , то условие Z Mod 2 = 1 истинно , то первому аргументу присваивается значение фДаНет , т.е. значение ответа пользователя на первый вопрос . В цикле For переменная k пробегает все номера аргументов-вопросов , кроме ноля - компьютерного номера первого вопроса : □ Если число аргументов чётно , то Z нечётно , то 1 + Z Mod 2 = 2 ( в этом случае это и есть компьютерный номер второго вопроса , так как первый аргумент - не вопрос , а логическая переменная ) . □ Если число аргументов нечётно ( в этом случае первый аргумент - второй вопрос ) , то Z чётно , то 1 + Z Mod 2 = 1 . Цикл выполняется , пока k не превысит Z . Последнее значение k , при котором ещё выполняется тело нашего цикла , т.е. строка zВопросРезультат ( k + 1 ) = фДаНет ( zВопросРезультат ( k ) ) , равно Z - 1 . После этого оператор Next k увеличивает k на 2 , компьютер возвращается в заголовок цикла , обнаруживает , что k больше Z , и выходит из цикла . Обратите внимание , что в теле цикла мы использовали рекурсию , которая немного сократила код . Условие задачи К оглавлению

Ответ к 11-й задаче Условие задачи Измените макрос Я , чтобы он выглядел так : Sub Я ( ) On Error Resume Next ActiveWindow.View.FullScreen = False ActiveWindow.View.FullScreen = True For Each k In CommandBars k.Visible = False Next k CommandBars("История").Visible = True gМножительПаузы = 1 ГП End Sub Условие задачи К оглавлению

Хостинг от uCoz