Текст
                    СЕРГЕИ КАШАЕВ
ПРОГРАММИРОВАНИЕ в Microsoft®Excel + ВИДЕОКУРС
НА ПРИМЕРАХ
ИСПДЛЬаОВАНИЕ VBA
ПРИ СОЗДАНИИ АОТОМАТИЗИРаПАНН! >ос книг MICPQbOIT EXCEL
овьекты. коллекции овыктов, МЕТОПЫ. СЛГЫТ1ЛЯ И СВОИСТЛА
ОВРМГ^ТКА ВАННЫХ иэ отчетов ПРОГРАММЫ 1С'П1 'ЕППРИНТМЬ В КНИГЕ MICROSOFT EXCEL
РВАПИПАЦИН ЭЛЕКТРОННОГО лак УМГНТСНЭЕОРОТА
ПРОГ! IAMMA
Сергей Кашаев
ПРОГРАММИРОВАНИЕ в Microsoft Excel НА ПРИМЕРАХ
Санкт-Петербург «БХВ-Петербург» 2007
УДК ББК
681.3.068
32.973.26-018.1
К31
Кашаев С. М.
К31 Программирование в Microsoft Excel на примерах. — СПб.: БХВ-Петербург, 2007. — 320 с.: ил. + Видеокурс (на CD-ROM)
ISBN 978-5-9775-0049-4
Обучение программированию в Microsoft Excel построено на практических примерах различной сложности. Рассмотрены простые примеры автоматизации рутинных операций и более сложные примеры, такие как создание автоматизированных бланков для заказа продукции или программирование логических игр на листе Microsoft Excel. Основной упор сделан на подробный разбор бизнес-приложений: обработка отчетов, полученных а программе 1С:Прсдприятие, организация электронного документооборота, программа составления расписания занятий в учебном заведении.
CD содержит видеокурс по основам программирования в среде Excel и все рассмотренные в книге примеры.
Дм пользователей Microsoft Excel и начинающих программистов
УДК 681.3.068
ББК 32.973.26-018.1
Группа подготовки издания:
Главный редактор
Зам. главного редактора Зав редакцией Редактор Компьютерная верстка Корректор Дизайн серии Оформление обложки Зав. производством
Екатерина Кондукова Евгений Рыбаков Григорий Добин Татьяна Темкина Натальи Караваевой Зинаида Дмитриева Игоря Цырульникова Елены Беляевой Никочай Тверских
Лицензия ИД Nt 0242S от 24.07.00. Подписано  печать 25.12 06 Формат 70x100'/,». Печать офсетная Усл. печ. л 25.8.
Тираж 3000 экз. Заказ Nt 925
“БХВ-Петербург", 194354, Санкт-Петербург, ул. Есенина. 56
Санитарно-эпидемиологическое заключение на продукцию
Nt 77.99.02.9534.006421.11.04 от 11.11.2004 г. выдано Федеральной службой по надзору в сфере защиты прав потребителей и благополучия человека.
Отпечатано с готовых диапозитивов в ГУП "Типография "Наука"
199034, Санкт-Петербург, 9 линия, 12
ISBN 978-5-9775-0049-4
О Kuueei С. М . 2007
С Оформление, издательство "БХВ-Петербург". 2007
Оглавление
Введение.........................................................1
Краткое содержание книги.........................................1
Достоинства VBA..................................................3
Компакт-диск...................................................  6
От автора......................................................  6
Глава 1. Среда для написания программ на VBA.....................7
Свойства элементов...............................................9
События.........................................................12
Поле со списком.................................................17
Список..........................................................20
Рисунок.........................................................24
Динамическое изменение цвета кнопки.............................27
Вывод информации о текущем времени..............................28
Полоса прокрутки................................................33
Динамическое перемещение кнопки.................................35
Разработка игры.................................................36
Основные сведения по VBA........................................39
Выводы..........................................................43
Самостоятельная работа..........................................44
Задание 1.1.....................................................44
Задание 1.2.....................................................44
Задание 1.3.....................................................44
Глава 2. Объекты Microsoft Excel................................45
Автоматизированный бланк........................................47
Бланк заказа на офисные товары..................................56
Электронная анкета............................................  63
Самостоятельная работа..........................................69
Задание 2.1.....................................................69
Задание 2.2.....................................................70
IV
Оглавление
Глава 3. Реализация алгоритмов.................................71
Имитация передвижения шахматной фигуры.........................71
Пример разработки игровой программы............................79
Игра на матрице................................................85
Самостоятельная работа.........................................88
Задание 3.1....................................................88
Задание 3.2....................................................89
Задание 3.3....................................................89
Глава 4. Пример обработки отчетов из программы 1С:Предприятие в книге Excel.................................  91
Представление об организации программного комплекса 1 С: Предприятие...............................................91
Основной лист книги............................................98
Лист Индексация...............................................109
Процедура WorkbookjOpen.......................................116
Выводы........................................................117
Глава 5. Организация электронного документооборота............119
Описание элементов управления.................................120
Процедура установки защиты....................................127
Пример создания электронного документа........................  130
Процедура WorkbookjOpen.......................................131
Механизм защиты документа.....................................135
Процедура установки защиты для резолюции......................136
Сервисные возможности книги...................................138
Дополнительные листы..........................................145
Шаблон книги..................................................146
Глава 6. Задача управления ресурсами..........................147
Ввод начальной информации.....................................148
Форма для ввода заявок........................................152
Форма для подбора аудитории...................................164
Форма для снятия заявки с обслуживания........................183
Лист Расписание...............................................187
Сводный отчет по загрузке.....................................196
Отчет по ресурсам фонда аудиторий.............................  201
Отчет по предмету.............................................203
Лист Расчет...................................................204
Отчет Нагрузка................................................205
Оглавление
V
Лист Передача...........................................208
Отчет по конкретному дню................................209
Заключение..............................................210
ПРИЛОЖЕНИЯ----------------------------------------------213
Приложение 1. Процедуры формы ввода заявок..............215
Приложение 2. Процедуры формы для подбора аудитории.....229
Приложение 3. Процедуры листа Отчет 1...................242
Приложение 4. Процедуры листа Расписание----------------247
Приложение 5. Процедуры листа Отчет 2...................266
Приложение 6. Процедуры листа Отчет 3...................270
Приложение 7. Процедуры, связанные с листом Расчет......276
Приложение 8. Процедуры листа Нагрузка..................280
Приложение 9. Процедура, связанная с открытием книги....285
Приложение 10. Тесты по VBA.............................288
Приложение 11. Ответы на тесты по VBA (приложения 10)...293
Приложение 12. Описание компакт-диска...................294
Литература..............................................297
Предметный указатель....................................299
Введение
Если попытаться выбрать среди многочисленных программных продуктов для офиса самый популярный, то с большой вероятностью это окажется Microsoft Excel. С этой программой успешно работают и начинающие пользователи персональных компьютеров, и квалифицированные программисты.
Умение обращаться с формулами на листах Excel создает у начинающего пользователя иллюзию, что он уже овладел секретами работы с этим приложением. Однако для сложной автоматизации требуется знакомство с более глубокими ресурсами. И основной практический ресурс — это язык Visual Basic for Applications (VBA). Буквально первые шаги с использованием VBA показывают, какие возможности есть у пользователей Microsoft Excel для совершенствования своих рабочих книг.
Первые вопросы, которые возникают у читателя, открывшего новую книгу, — для него ли она написана, и что он уже должен знать, чтобы усвоить информацию, приведенную в книге? Практические занятия со студентами вузов показали, что освоение приведенных в книге разработок вполне по силам пользователям, до этого вообще не имевшим о программировании никакого представления. Использование приведенного в этой книге практического курса позволило сделать вывод о том, что приобрести серьезные навыки для самостоятельной разработки автоматизированных рабочих книг с использованием VBA можно за короткий срок.
Краткое содержание книги
В книге приводятся практические примеры, которые отличаются увеличением сложности разработок от главы к главе.
В главе 1 читатель познакомится с объектами, их методами и свойствами. Он увидит, как легко с помощью программного кода можно обрабатывать такие события, как перемещение курсора мыши на рисунке или двойной щелчок
2
Введение
на списке. Основная цель первой главы — заложить базовые сведения по программированию с использованием VBA для решения серьезных задач в последующих главах.
В главе 2 описывается работа с объектами Microsoft Excel, при этом подробно рассматривается создание разнообразных автоматизированных бланков, которые могут встретиться при работе в офисе. Вы увидите, как легко с помощью программного кода получить доступ к ячейкам на листах Microsoft Excel. Используя подобные примеры, читатель может создать свою разработку по автоматизации офисной работы в фирме. Как показала практика, руководство гораздо больше ценит подобного специалиста и очень часто воспринимает его как достаточно квалифицированного программиста. Один бывший студент (замечу, гуманитарной специальности) удивленно сказал: "Они считают меня программистом."
Глава 3 отличается большей алгоритмизацией рассматриваемых примеров. Здесь рассматривается создание нескольких игровых программ на рабочем листе Microsoft Excel. Разобравшись в программном коде, большинство читателей придет к выводу: ничего сложного в подобных разработках нет!
В главе 4 подробно рассматривается реальная задача, которая была решена для деканата высшего учебного заведения. Она связана с учетом внесения оплаты за обучение по внебюджетным программам. Особенностью этой задачи является то, что разработанная автоматизированная книга позволяет извлекать информацию из отчетов, сформированных в программе 1С:Предприятие. Рассматриваемая здесь разработка содержит несколько управляющих листов и несколько листов данных. При этом читатели, связанные с анализом оплат в большом временном интервале, смогут использовать данную разработку как в исходном варианте, так и после внесения необходимых изменений. Для большинства читателей рассмотрение организации автоматизированной рабочей книги позволит познакомиться с техническими приемами программирования, что в результате поможет им выполнить собственную разработку.
Глава 5 связана с разработкой схемы электронного документооборота внутри одной организации. Здесь рассматривается книга Microsoft Excel с разнообразными элементами управления, позволяющими защитить от изменений авторскую часть документа электронной подписью. Также в разработке предоставляется возможность внесения в документ резолюций и их защиты от посторонних изменений. Оригинальным аспектом решения можно считать использование книги Microsoft Excel в качестве контейнера, вмещающего всю информацию, в том числе, необходимую для авторизации доступа.
Глава 6 — самая сложная. Здесь рассматривается задача эффективного управления ресурсами. Более конкретно данная разработка позволяет эффективно
Введение
автоматизировать процесс загрузки имеющихся аудиторий при проведении занятий в учебном заведении (школа, колледж, вуз). Автоматизация рассмотренной задачи сводится к сложному управлению информационной базой, включающей учебные группы, преподавательский состав, имеющиеся аудитории с известной вместимостью, набор дисциплин. В созданную книгу Excel входит более 10 листов и несколько экранных форм, направленных на удобство пользователя при составлении расписания. Даже если читатель далек от решения задачи по составлению расписания, в этой главе он познакомится с разнообразными сложными программными приемами управления данными на листах.
Достоинства VBA
Таким образом, в данном издании на практических примерах рассматривается возможность автоматизации работы в Microsoft Excel с помощью популярного языка современного офисного программирования VBA. Известно, что офисные приложения (конкретно Word и Excel) позволяют создавать достаточно сложные автоматизированные документы. В этих приложениях есть масса пользовательских возможностей, обеспечивающих разнообразную автоматизацию. И от версии к версии этих программных продуктов они становятся все более эффективными и полезными. Поэтому пользователь, поработав в последней версии, как правило, уже не возвращается к предыдущей. Однако часто, когда требуется сложная автоматизация расчетов, только пользовательских ресурсов этих приложений оказывается недостаточно. В свое время компанией Microsoft была выбрана очень эффективная стратегическая линия, связанная с внедрением языка VBA в приложения пакета Microsoft Office. Фактически для программирования в этих приложениях используется один и тот же язык программирования с определенными особенностями для каждого приложения.
Язык VBA относится к категории объектно-ориентированных, и каждое приложение Microsoft Office характеризуется своими объектами. Что же такое — объект? Попробуем дать представление об этом.
Объект это программный компонент, который содержит связанные между собой данные и программный код. При этом в объекте часть данных может быть открыта для других программных конструкций, а другой частью могут оперировать только программные компоненты, относящиеся к данному объекту. То же самое относится и к процедурам (небольшим программам), принадлежащим объекту, — некоторые из них могут быть вызваны извне, а другие, наоборот, используются только внутри объекта.
Введение
Мы все знаем, что реальные объекты характеризуются некими свойствами. Например, у яблока есть такие свойства, как вкус, цвет, сорт. При этом каждое свойство может принимать одно из нескольких возможных значений. Например, для свойства "вкус" возможны следующие значения — "кислое", "сладкое", "кисло-сладкое" и т. д. Понятно, что свойство "цвет" яблока тоже может иметь разные значения — "красный", "зеленый" и т. д. В этом плане у программного объекта наблюдается аналогия с реальными объектами. А именно: у объекта есть набор свойств, которые могут принимать определенные значения. И таким образом, свойство объекта — одно из ключевых понятий, с которым мы познакомимся далее при рассмотрении примеров.
Кроме свойства объекта есть еще одно, даже более значительное понятие — метод. Вернемся к аналогии. С реальными объектами можно выполнять разнообразные действия. Например, яблоко можно съесть, разрезать и, допустим, переместить (например, передвинуть на столе). В программировании методы представляют собой программные процедуры, относящиеся к определенному объекту. Действия над программным объектом и определяются в содержании его методов.
В целом, объектно-ориентированное программирование — это технология разработки приложений (программ) с помощью объектов. При этом не так важен сам объект, как его свойства и методы, т. е. действия, которые можно совершать над объектом.
Несколько слов о том, каким образом организуется работа с объектами. В обычной жизни мы используем выражения вроде "красное яблоко" или, например, "разрезать яблоко на 4 части". В программном языке (практически в любом современном алгоритмическом языке) это "говорится" немного иначе. У каждого объекта есть имя (имя — это обязательный атрибут любого объекта). Имя объекта уникально, и именно по имени программа отличает один объект от других. Если мы хотим программно задать значение определенного свойства объекта, то следует использовать следующую конструкцию:
Имя_объекта. Имя_своЙства = Значение-свойства
Примечание
Здесь вместо пробела используется символ подчеркивания — для исключения пробелов в частях этой конструкции. Это связано с тем, что в именах объектов, именах их свойств и значениях пробелы недопустимы.
Аналогично используются методы:
Имя—объекта. Имя_метода
Введение
5
Если у метода есть параметры, то значения параметров указываются в скобках после имени метода. Попробуем составить программную аналогию разрезания яблока на 4 части. В этом случае надо написать:
МоеЯблоко.Разрезать(4)
Сразу после имени объекта записывается имя метода с указанным в скобках значением параметра.
Далее в книге мы рассмотрим работу с объектами, типичными для операционной системы Windows. Это кнопки, текстовые окна, окна рисунков и др. Для подобных объектов наиболее часто используемыми свойствами являются цвет, размер, положение на экране, состояние объекта (например, видимость). Их методы связаны с такими событиями, как щелчок и двойной щелчок мышью, наведение курсора мыши. Мы также рассмотрим объекты, характеризующие именно Microsoft Excel, то есть то, с чем работает пользователь, — рабочие книги, листы, ячейки (главы 2—6). События для этих объектов достаточно специфичны. Большинство программных примеров использует такие события, как открытие книги, активизация листов, двойной щелчок на ячейке.
Поясню вкратце, в чем заключается программирование на VBA.
Событие, связанное с тем или иным методом, приводит к выполнению предопределенной процедуры. Эта процедура объективно существует в приложении Microsoft Excel, и, как мы увидим далее, эту процедуру можно легко открыть для изменения (внесения в нее нашего программного кода). Фактически, задача программиста заключается в том, чтобы выбрать интересующий объект и событие, реакцию на которое требуется запрограммировать. Например, если мы при открытии книги Excel намереваемся автоматически заполнить информацию рабочего листа, то для этого следует выбрать объект workbook, который характеризует всю книгу в целом. Для данного объекта есть событие open — открытие книги (оно происходит в момент открытия пользователем этой книги). И в среде VBA для этого уже имеется процедура work-bookjDpen, фактически пустая — все, что в ней записано, это заголовок и завершение процедуры. Программист должен написать только (хотя часто это "только" для программиста означает довольно много работы) содержимое этой процедуры. В дальнейшем этот код будет автоматически выполняться при открытии книги. Здесь можно вполне разумно возразить — в Excel применяются макросы, и несложно записать макрос, автоматически выполняемый при открытии книги, причем практически без программирования. Это действительно так — но только для несложных вычислений. Если по определенному событию требуется выполнить сложные вычисления, для этого следует написать программу на VBA.
Фактически все основные программные разработки на VBA укладываются в следующую схему. Если пользователь производит какое-либо воздействие
6
Введение
(например, нажимает кнопку мыши), то в качестве отклика автоматически выполняется программный код, содержащийся в предопределенной для этого события процедуре.
Некоторые считают программирование с использованием VBA непрофессиональным. На мой взгляд, это мнение ошибочно и для эффективной автоматизации работы в офисе рассматриваемый язык является наилучшим. Большим плюсом при этом можно считать возможность быстрой разработки достаточно сложных конструкций и легкость освоения. Последовательно выполняя рассмотренные в книге примеры на своем компьютере, вы сами в этом убедитесь.
Компакт-диск
Сопроводительный компакт-диск книги содержит файлы приведенных в ней примеров. Файлы скомпонованы в папки, номера которых соответствуют главам книги. Приведенные файлы являются рабочими книгами Microsoft Excel 2003.
От автора
Мне бы хотелось поблагодарить всех читателей, познакомившихся с моей книгой. Эта книга не первая, предыдущие (их больше десяти) были выпущены небольшими вузовскими тиражами. Большинство изданий получило положительные отзывы как от студентов, так от преподавателей. Для меня это явилось поводом попробовать обратиться в одно из центральных издательств. И я очень благодарен издательству "БХВ-Петербург", которое выпустило мою книгу.
Что касается содержания книги, то мне бы хотелось выразить большую благодарность Ю. В. Воронкову, декану вечернего факультета НГЛУ им. Н. А. Добролюбова. Фактически, материал глав 4—6 появился как результат эффективной организации им управления учебным процессом. Поставленные им задачи и его участие в разработке удобного пользовательского интерфейса практически предопределило появление этого издания. Другими словами, без его энергии и идей не было бы этой книги.
В заключение замечу, что наибольший эффект от чтения будет достигнут, если одновременно с чтением выполнять рассмотренные примеры прямо в Microsoft Excel. Думаю, книга не лишена неточностей, и заранее приношу читателям за них свои извинения.
Связаться с автором книги можно через электронную почту издательства mail@bhv.ru, отзывы на книги принимаются на сайте www.bhv.ru.
Глава 1
Среда для написания программ на VBA
Наша задача в этой главе — получить первые навыки работы с VBA в приложении Microsoft Excel. При этом предполагается, что читатель должен быть знаком с пользовательскими возможностями этого приложения, хотя бы в незначительной степени. И, как уже говорилось, параллельно с чтением книги желательно запустить приложение Microsoft Excel и выполнять все описанные действия на компьютере.
Итак, будем считать, что вы запустили рассматриваемое приложение. Теперь следует вывести на экран необходимый набор инструментов.
В качестве первого шага выведем на экран панель инструментов Элементы управления (для этого следует выбрать в меню Вид пункт Панели инструментов и поставить флажок в строке Элементы управления). В результате на экране появится новая панель инструментов — Элементы управления (рис. 1.1). На этом рисунке не показаны традиционные при работе в Microsoft Excel панели инструментов (Стандартная, Форматирование и др.) и в строке, расположенной под главным меню, присутствуют только кнопки панели Элементы управления.
Большинство пиктограмм этой панели соответствует графическим элементам, типичным для операционной системы Windows. Здесь вы видите полосу (линейку) прокрутки, текстовое окно, список и т. д. С этими элементами мы будем работать в последующих разработках.
Перед тем как приступить к каким-либо действиям с тем или иным элементом, его необходимо создать на рабочем листе. Для того чтобы разместить на листе приложения Microsoft Excel какой-нибудь элемент (например, кнопку или текстовое окно) из имеющихся на указанной панели, сначала нужно перейти в режим конструктора. Это можно сделать, нажав самую левую кнопку панели Элементы управления (на рис. 1.2 эта кнопка выглядит "утопленной").
8
Глава 1
Рис. 1.1. Рабочий лист и панель инструментов Элементы управления
Рис. 1.2. Рабочий лист в режиме конструктора
В этом режиме можно конструировать элементы на рабочем листе — размещать и удалять их, а также изменять свойства расположенных элементов.
Другой режим можно назвать режимом выполнения или режимом работы (однозначно принятого названия нет). Чтобы перейти в режим выполнения (для выхода из режима конструктора), нужно отжать ту же самую кнопку (рис. 1.2).
Немного поэкспериментировав, вернемся в режим конструктора. Как уже говорилось, на рабочем листе можно размещать различные элементы управления.
Среда для написания программ на VBA 9
Для того чтобы перенести элемент на рабочий лист, щелкните в панели инструментов на пиктограмме этого элемента левой кнопкой мыши, а затем переместите курсор мыши на рабочий лист (он примет вид знака "плюс"). Теперь нажмите левую кнопку мыши и, не отпуская ее, переместите мышь немного вправо и вниз и затем отпустите кнопку. В результате на рабочем листе появится командная кнопка (в дальнейшем будем ее называть — просто кнопка). Результат данных действий показан на рис. 1.2.
Теперь можно с помощью маркеров, окружающих кнопку, изменять ее размеры, а также перетаскивать созданную кнопку по рабочему листу.
Примечание
После размещения элемента управления на рабочем листе в книге (точнее, на данном листе книги) появился новый объект.
Свойства элементов
Как было сказано, у объектов есть свойства. Первое очевидное желание заключается в том, чтобы посмотреть (а затем и изменить) значения свойств созданного объекта.
Для просмотра свойств объекта его сначала нужно выделить (щелкнуть на нем мышью), а затем с помощью второй слева кнопки панели Элементы управления открыть окно свойств (рис. 1.3). В данном случае объектом является созданная нами ранее кнопка.
В левой части рис. 1.3 показано окно свойств, в котором видна таблица — набор строк в две колонки. Левая колонка содержит имена свойств, а правая — значения этих свойств. Понятно, что содержание левой колонки изменить нельзя — свойства объекта уже определены его разработчиком (компанией Microsoft). А изменить значения свойств мы можем, для этого достаточно щелкнуть в ячейке правой колонки и просто изменить ее содержимое.
Если посмотреть на окно свойств, то мы увидим, что для ряда свойств возможны только два варианта значений. Например, для свойства visible (оно определяет, виден или нет объект на экране в данный момент) возможны только значения False и True. Такая ситуация наблюдается и для ряда других свойств.
Для некоторых других свойств можно устанавливать числовое значение. Например, свойство width соответствует ширине элемента (в данном случае кнопки). Аналогичные свойства — Height (высота элемента), тор (координата верхней границы элемента, начиная от верхней границы листа) и Left (координата левой границы элемента, начиная от левой границы листа).
w
Глава 1
Рис. 1.3. Окно свойств объекта
Если теперь вы переместите созданную на листе кнопку по экрану и измените ее размеры (с помощью окружающих ее маркеров), то соответствующие значения в окне свойств тоже изменятся.
Ранее уже упоминалось, что самое основное свойство объекта — это имя (в окне свойств это свойство называется Name). Как мы видим в данном примере, при создании объекта Excel автоматически присваивает ему имя. В нашем Примере созданной кнопке присвоено имя CommandButtonl (см. рис. 1.3). Однако это первоначальное имя вы можете изменить. Явной необходимости изменять имя, присвоенное по умолчанию, нет, однако очень часто программисты сами назначают объектам имена. Это связано с тем, что мы можем получить доступ к любому объекту листа (т. е. к свойствам и методам этого объекта) из программы, указав имя конкретного объекта. Поэтому с точки зрения организации программы часто удобнее использовать свою систему именования объектов.
Возвратимся к рассматриваемому примеру. В данном случае мы создали один объект — кнопку. Система именования по умолчанию заключается в комбинации типа объекта (command button — командная кнопка) и числа (номера объекта данного типа). Так, следующая кнопка будет иметь номер 2, затем 3 и т. д.
Чтобы изменить ИМЯ КНОПКИ, В окне СВОЙСТВ нужно вместо CommandButtonl ввести то имя, которое вас устраивает, но без внутренних пробелов (частая ошибка у начинающих программистов). Например, введем новое имя кнопка!. Заметим, что при смене имени надпись на кнопке не изменилась. Это связано
Среда для написания программ на VBA 1J
с тем, что за надпись на кнопке отвечает свойство caption (фактически это бирка или ярлык на кнопке). С помощью этого свойства установим надпись на кнопке — кнопка на листе (в значении этого свойства могут присутствовать пробелы), а затем поменяем цвет кнопки (сделаем кнопку не серой, а, скажем, зеленой). Для этого нужно щелкнуть мышью в строке значения свойства Backcoior и изменить серый цвет на зеленый (откроется окно, где можно выбрать необходимый цвет щелчком).
Чтобы сделать надпись на кнопке более крупной, поменяем шрифт — с помощью свойства Font. С помощью этого свойства можно подобрать тип шрифта и установить размер букв. Технически это несложно — все делается с помощью щелчков. После выполненных действий кнопка должна принять вид, аналогичный показанному на рис. 1.4.
Примечание
Иногда на первых шагах работы с VBA в сознании пользователя возникает “подмена" свойств Name и Caption. Поэтому еще раз подчеркнем, что свойство caption отвечает просто за надпись на кнопке (значение свойства проявляется только визуально на экране), а свойство Name — внутреннее имя объекта, и значение этого свойства используется на программном уровне (во введении об этом уже говорилось).
Поясним еще несколько часто используемых свойств.
Свойство Picture позволяет разместить на кнопке изображение из графического файла. Для этого в качестве значения свойства следует указать имя файла (с помощью диалогового окна для выбора графического файла из имеющихся на компьютере и в сети).
Цвет текста на кнопке задается с помощью свойства Forecolor, а свойство AutoSize позволяет установить автоматическое изменение размера кнопки в зависимости от размера надписи на ней (как мы уже знаем, за надпись на кнопке отвечает свойство caption).
Для свойства Autosize, как и для свойства visible, может быть установлено только одно из двух возможных значений — False и True. Попробуйте установить значение True для этого свойства и после этого измените надпись на кнопке — размер кнопки автоматически изменится.
Достаточно часто используется свойство Enabled, которое позволяет установить возможность доступа к объекту. Так, при значении этого свойства False текст на кнопке становится серым — это говорит о том, что кнопка недоступна (не реагирует на воздействия мыши). И, наоборот, при значении True с объектом можно работать. Эффект свойства Enabled можно наблюдать в любом приложении — как правило, часть названий меню выводится бледным цветом (эти меню неактивны и доступ к ним заблокирован).
12
Глава 1
Рис. 1.4. Кнопка с измененными значениями свойств
У любого объекта достаточно много свойств и методов, однако на практике их все редко используют в программах. Необходимые пояснения по ним будут даны далее в процессе рассмотрения примеров. А для получения полной справочной информации по VBA читатель может обратиться к ряду очень неплохих изданий [1—5].
Кратким итогом выполненных действий является создание нового объекта и установка значений для некоторых его свойств.
Теперь наступает следующий этап — выход из режима конструктора и работа с уже созданным объектом. Как уже было сказано, для выхода из режима конструктора следует просто отжать кнопку на панели Элементы управления (см. рис. 1.2). Теперь мы можем просто понажимать созданную на листе кнопку, без какого-либо эффекта.
Вообще, в режиме конструктора мы размещаем на рабочем листе элементы и устанавливаем значения их свойств, а работаем с созданными элементами (нажимаем кнопки, вводим текст в текстовые окна и т. д.) в режиме выполнения.
События
Теперь расположим на листе другой элемент управления — текстовое окно (рис. 1.5). На панели Элементы управления на его пиктограмме видны буквы "ab". Текстовое окно предназначено для ввода текста с клавиатуры.
Среда для написания программ на VBA
13
Рис. 1.5. Добавлен объект — текстовое окно
Есть еще один элемент — надпись, предназначенный для отображения на экране поясняющего текста. На пиктограмме этого элемента изображена большая буква А. В функциональном плане текстовое окно и надпись несколько схожи, однако, в отличие от текстового окна, ввести информацию в надпись с клавиатуры невозможно.
Примечание
При работе с русифицированной версией Microsoft Excel при наведении курсора мыши на пиктограмму элемента "текстовое окно" в качестве подсказки выводится слово "Поле". В оригинале название этого элемента TextBox, и поэтому далее по тексту мы будем использовать более соответствующее смыслу название — текстовое окно.
Продолжим работу. Рядом с кнопкой расположим на листе Microsoft Excel текстовое окно. Установим значение Т1 для свойства Name этого элемента, а также выберем для него внутреннюю серую заливку (с помощью свойства BackColor).
Для автоматического переноса длинного текста в текстовом окне со строки на строку свойство MultiLine установим в значение True. Альтернативный вариант значения этого свойства — False (в этом случае текст размещается в окне в одну строку, длинный фрагмент обрезается). Чтобы не забыть про свойство Font, подберите также шрифт текста в окне.
14
Глава 1
I kxvie создания на листе двух объектов можно перейти к обработке связанных с ними событий. Будем считать, что перед нами стоит следующая задача — при щелчке на кнопке в текстовом окне должен выводиться текст Пример вывода текста". Первый шаг для этого, как мы уже знаем, заключается в переходе в режим конструктора.
Теперь наступает новый момент — нам необходимо перейти в среду для написания кода (текста) программы, т. е. перейти в текстовый редактор. Для этого сделайте двойной щелчок на созданной кнопке. Возможен и другой способ перехода — в меню Сервис выбрать пункт Макрос и затем пункт Редактор Visual Basic. Так или иначе, перед вами должно открыться окно, показанное на рис. 1.6.
Рис. 1.6. Окно редактора Visual Basic
В правой части окна редактора Visual Basic расположено окно, позволяющее быстро перейти к разработке необходимой процедуры. В этом окне есть два раскрывающихся списка (чтобы раскрыть такой список, нужно щелкнуть на кнопке с треугольной стрелкой). Сначала следует выбрать в левом списке имя объекта (по значению свойства Name), с которым мы собираемся работать, а затем для указанного объекта в правом списке нужно выбрать событие, которое нас интересует, — щелчок на кнопке. Для этого события мы потом и напишем программный код.
Таким образом, в левом раскрывающемся списке (см. рис. 1.6) выбираем вариант Кнопка!, а затем в правом — Click (щелчок на кнопке). В результате в окне редактора кода перед нами откроется область процедуры, которая
Среда для написания программ на VBA 15 будет автоматически выполняться при щелчке на кнопке. Эта область начинается СО строки Private Sub Кнопка1_С1ick(), а Заканчивается СТРОКОЙ End sub. Здесь Кнопка1_с11ск() — имя процедуры, которое по умолчанию формируется из двух составляющих — Кнопка! (имя объекта, которое мы присвоили объекту сами) и click (событие — щелчок на кнопке).
Подобные процедуры называются предопределенными — они объективно существуют и всегда выполняются при наступлении определенного события. В данном случае процедура Кнопка1_с11ск() автоматически выполняется при щелчке на кнопке Кнопка!.
Если вы теперь напишете программный код между начальной строкой процедуры и ее последней строкой, то он автоматически выполнится при щелчке на кнопке. Фактически программирование с использованием VBA и заключается в разработке содержания подобных предопределенных процедур.
В нашем случае необходимо написать программный код, приведенный на рис. 1.7, который заключается в единственной строке, которая прокомментирована далее.
Рис. 1.7. В процедуру добавлен программный код
Конструкция Т1 .Text говорит о том, что для объекта с именем Т1 рассматривается его свойство Text (значение этого свойства определяет текст, который располагается в этом текстовом окне). Знак равенства и последующая фраза говорят о том, что рассматриваемому свойству присваивается значение "Пример вывода текста".
16
Гпава 1
Таким образом, в конструкторе мы создали нужные объекты (кнопку и текстовое окно) и написали текст процедуры, выполняемой по щелчку на кнопке.
Далее следует вернуться в окно Microsoft Excel (например, с помощью самой левой пиктограммы в панели инструментов — пиктограммы этого приложения, см. рис. 1.7). Если выйти из режима конструктора и щелкнуть по созданной кнопке, то мы увидим ожидаемую фразу в текстовом окне (рис. 1.8).
Таким образом, мы рассмотрели основные шаги, которые следует выполнять при программировании в Microsoft Excel. Сформулируем эти шаги:
1.	Расположить на листе элементы управления.
2.	Присвоить созданным элементам управления имена и установить значения других свойств.
3.	Разработать процедуры, связанные с событиями данных элементов.
Рис. 1.8. При щелчке на кнопке в текстовом поле появляется заданный текст
Несколько слов о том, что мы еще не рассматривали. В левой части окна редактора (см. рис. 1.6) показано окно проекта. Если это окно не отображается на экране, то, чтобы его отрыть, нужно в окне редактора выбрать пункт Project Explorer меню View. На рис. 1.6 последние четыре строки в этом окне — пиктограммы таких "глобальных" объектов, как листы, входящие в книгу, и сама книга. Это тоже объекты со свойствами и методами, которые нам доступны при программировании. На рис. 1.6 в окне проекта выделена
Среда для написания программ на VBA 17 пиктограмма первого листа, соответственно, в правом окне выводятся процедуры, относящиеся только к первому листу и объектам, находящимся на нем. В нашем примере созданные кнопка и текстовое окно находятся на первом листе. Если мы выполним двойной щелчок на пиктограмме ЭтаКнига, то в правом окне получим доступ к методам книги. В дальнейшем нас будет в основном интересовать метод open, связанный с открытием книги.
Поле со списком
Познакомимся еще с одним элементом управления, который называется "поле со списком" (рис. 1.9).
На панели инструментов Элементы управления пиктограмма этого элемента девятая слева. Поле со списком предназначено для работы со списком (набором) значений, и особенность его в том, что в этом элементе до его активизации (щелчком на кнопке со стрелкой) всегда отображается только одна строка. После его активизации список значений раскрывается, и в нем можно выбрать нужный элемент с помощью мыши и автоматически появляющейся полосы прокрутки.
Рис. 1.9. На рабочий лист добавлен элемент "поле со списком"
Примечание
Далее по тексту вместо длинной конструкции "поле со списком" будем в тех ситуациях, где смысл высказывания не изменяется, говорить просто "список". Данное сокращение не совсем точно, т. к. элемент управления "список" также
Глава 1
представлен на панели Элементы управления (его пиктограмма находится левее пиктограммы Поле со списком), далее мы рассмотрим программные примеры и с ним.
Кроме свойства Name у элемента "поле со списком" есть несколько характерных свойств.
Свойство Listindex содержит номер текущего элемента списка (того, который подсвечен, — на нем пользователь сделал щелчок). Нумерация элементов списка начинается с нуля. При этом если никакой элемент в списке не выделен, то значение свойства Listindex равно -1, если выделен самый верхний элемент, то значение свойства равно нулю и т. д.
Свойство Listcount содержит число элементов, внесенных в список, а свойство Text соответствует содержанию выделенного (выбранного) элемента.
Доступ к произвольному элементу списка может быть осуществлен с помощью свойства List(HOMep элемента).
Сами по себе названия перечисленных свойств ничего не говорят, поэтому дадим небольшое пояснение.
Будем считать, что список содержит три строки, или три элемента (как занести элементы в список, мы рассмотрим далее). Если принять, что значение свойства Name рассматриваемого списка spisoki, то доступ к самому верхнему элементу осуществляется так: spisoki.List(O). А если вы в процедуре хотите получить следующий элемент (второй сверху), то следует написать: Spisoki. List (1). Аналогично, получение доступа к последнему элементу списка: Spisoki .List (Listcount - 1). Если же вам в программе нужно получить содержание выделенного элемента, можно написать: spisoki.Text.
Теперь рассмотрим наиболее часто используемые методы работы с полем со списком.
Метод clear удаляет все элементы из списка, вызывают его так: Spisoki.Clear.
Метод Additem добавляет элемент в список. Применять его следует так: spisoki.Additem элемент списка. Противоположный ему по действию метод Removeitem удаляет элемент ИЗ списка: Spisoki .Removeitem номер элемента списка.
После такой вводной информации перейдем к практической задаче. Начнем с того, что на рабочем листе создадим следующий фрагмент (рис. 1.10).
Выберем следующие значения свойства Name для элементов, показанных на этом рисунке:
□	для кнопки Заполнение — зап;
□	для кнопки Очистка — оч;
Среда для написания программ на VBA
19
Рис. 1.10. Создадим на рабочем листе несколько элементов управления
□	для текстового окна (расположено рядом с кнопкой Заполнение) выберем — выбЭл;
□	для поля со списком (расположено рядом с кнопкой Очистка) — Сп. Сформулируем то, что нам требуется программно реализовать после размещения элементов:
□	по щелчку на кнопке Заполнение список заполняется строками — Яблоко, Груша, Слива, Дыня, Арбуз;
□	по щелчку в списке выбранный элемент помещается в текстовое окно;
□	по щелчку на кнопке Очистка текстовое окно и поле со списком очищаются — становятся пустыми.
Перейдем к реализации этих позиций.
Для заполнения поля со списком необходимо процедуру обработки щелчка на кнопке Заполнение оформить следующим образом (листинг 1.1).
| Листинг 1.1. Обработка щелчка на кнопке Заполнение
Private Sub 3an_Click()
Сп.Clear
Сп.Additem "Яблоко"
Сп.Additem "Toviiia"
20
Глава 1
Сп.Additem "Слива"
Сп.Additem "Дыня"
Сп.Additem "Арбуз" End Sub
Теперь оформим процедуру Cn_ciick () для внесения информации в текстовое окно по щелчку на элементе из поля со списком (листинг 1.2). Здесь и для текстового окна, и для поля со списком используется свойство Text. При этом для текстового окна это свойство определяет текст в окне, а для поля со списком — содержание выбранного элемента списка.
Листинг 1.2. Обработка щелчка на элементе поля со списком
Private Sub CnjClickO ВыбЭл-Text = Cn.Text End Sub
Следующее действие, которое нам следует реализовать, — очистка списка и текстового окна. В этом случае необходимо написать обработку события click для кнопки Очистка (листинг 1.3).
Листинг 1.3. Обработка щелчка на кнопке Очистка
Private Sub O4_Click()
ВыбЭл-Text = "" Сп.Clear End Sub
Итак, разрабатываемый программный фрагмент готов — мы разместили нужные элементы и написали программный код. Теперь можно вернуться в Excel, выйти из режима конструктора и поработать с созданными элементами.
Список
Похожим на только что рассмотренный элемент является другой, который называется просто "список". Пиктограмма этого элемента на рис. 1.9 расположена левее пиктограммы Поле со списком. В отличие от поля со списком, на экране список имеет фиксированный размер.
Среда для написания программ на VBA 21
В качестве практического примера разберем следующую задачу. На рабочем листе (рис. 1.11) расположим три элемента типа "список" (дадим этим спискам следующие имена (слева направо) — Lisi, Lis2, Lis3). Левые два списка отводятся для перечней, соответственно, наборов продуктов и напитков. Правый список — это список заказов, и он будет отображать выбранные пользователем в первых двух списках продукты и напитки. На листе над всеми тремя списками располагаются поясняющие подписи (элемент управления "надпись"). Понятно, что списки продуктов и напитков нужно как-то заполнить. Для этого создадим кнопку с надписью Заполнить списки продуктов и напитков (в этом и будет заключаться ее назначение).
Рис. 1.11. Созданы элементы управления
Уточним требования к программной разработке. Для включения в список заказов нужно сделать двойной щелчок на любом из продуктов или напитков в одном из первых двух списков. Это должно привести к переносу выбранного элемента в список заказов, а из списка продуктов (или напитков) выбранный элемент должен исчезнуть.
Сделаем только одно ограничение для программы — количество элементов в списке заказа не должно превышать трех. В этом случае, если мы добавляем новый элемент к трем уже присутствующим, то из списка заказов удаляется самый верхний элемент, а новый элемент добавляется в нижнюю часть списка.
Теперь все требования к программной реализации сформулированы, поэтому перейдем к рассмотрению процедур. Учитывая описанные выше методы
Глава 1
работы со списком, процедуру, выполняемую по щелчку на кнопке, следует оформить следующим образом (листинг 1.4).
Листинг 1.4 Процедура заполнения списков
Private Sub Coml_Click()
Lisi.Clear
Lis2.Clear
Lisi.Additem "Сыр"
Lisi.Additem "Ветчина"
Lisi.Additem "Колбаса"
Lisi.Additem "Творог"
Lisi.Additem "Сосиски"
Lis2.Additem "Минеральная вода"
Lis2.Additem "Ряженка"
Lis2.Additem "Пепси-кола"
Lis2 .Additem "Лимонад"
Lis2.Additem "Пиво"
End Sub
В листинге 1.4 списки сначала очищаются, а затем заполняются элементами. Если начальной очистки списков не делать, то при последующих щелчках на кнопке заполнения они будут пополняться копиями уже присутствующих элементов. По условию задачи требуется с помощью двойного щелчка в списке продуктов переносить выбранный элемент в список заказов, поэтому в окне редактора кода в списке объектов выбираем Lisi, а в соседнем списке Dbiciick. В результате мы открыли процедуру, которая автоматически выполняется при двойном щелчке на элементе списка. Теперь оформим ее следующим образом (листинг 1.5).
Листинг 1.5. Обработка двойного щелчка в списке продуктов
Private Sub Lisl_DblClick(ByVal Cancel As MSForms.RetumBoolean)
If Lis3.ListCount < 3 Then
Lis3.Additem Lisi.Text
Lisi.Removeitem Lisi.ListIndex
Else
Lis3.Removeitem 0
Среда для написания программ на VBA 23
Lis3.Additem Lisi.Text
Lisi.Removeitem Lisi.Listlndex
End If
End Sub
В этом тексте присутствует ряд новых моментов. Так, здесь мы в первый раз встретились с оператором условия. Само условие записывается после ключевого слова if, а после условия располагается ключевое слово Then. Если указанное уСЛОВИе ВЫПОЛНЯеТСЯ, ТО ВЫПОЛНЯЮТСЯ Все СТРОКИ Между If И Else, а затем управление передается на первую строку процедуры после End if. Если же условие не выполняется, то выполняются строки процедуры между Else И End If.
Прокомментируем использование данного оператора. При условии, что количество элементов в списке заказов меньше трех, добавление следующего элемента в заказ достаточно очевидно. А именно, в третий список добавляется элемент, на котором производится двойной щелчок в списке продуктов. Технически это реализуется с помощью следующей строки программы:
Lis3.Additem Lisi.Text
По условию задания переносимый элемент должен удаляться из списка продуктов, что реализуется так:
Lisi.Removeitem Lisl.Listlndex
Здесь учитывается, что свойство Listindex как раз и определяет номер выделенного элемента списка Lisi. В случае, если количество элементов равняется трем, выполняется блок, начинающийся с ключевого слова Else (т. к. условие в операторе if в этом случае не выполняется). В этом фрагменте сначала удаляется начальный элемент из третьего списка (с индексом ноль), а затем уже производится перенос выбранного элемента из первого списка в третий список. Аналогичная процедура выполняется при двойном щелчке во втором списке (листинг 1.6).
: Листинг 1.6. Обработка двойного щелчка в списке напитков
Private Sub Lis2_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
If Lis3.ListCount < 3 Then
Lis3 .Additem Lis2.Text
Lis2.Removeitem Lis2.Listindex
Else
Lis3.Removeitem 0
Lis3.Additem Lis2.Text
24
Глава 1
Lis2.Removeltem Lis2.ListIndex
End If
End Sub
Таким образом, программная разработка готова, и вы можете попробовать с ней поработать. На рис. 1.12 показан один из вариантов работы с данным листом.
Рис. 1.12. Результат разработки в действии
Рисунок
Рассмотрим еще один пример, который будет связан с новым для нас элементом управления, позволяющим отображать содержание графических файлов. На рис. 1.13 показано, где на панели Элементы управления располагается пиктограмма этого элемента. Видно, что в качестве подсказки к пиктограмме появляется слово Рисунок, поэтому далее в тексте мы так и будем его называть. Кроме обычных свойств у элемента "рисунок" есть свойство picture. В качестве значения свойства picture следует в диалоговом окне выбрать имя файла графического изображения (например, одного из файлов с расширением bmp или jpg). На рис. 1.13 показан объект подобного типа, размещенный на рабочем листе.
Перейдем к практической задаче, связанной с рассматриваемым элементом.
Среда для написания программ на VBA
25
Требуется сделать так, чтобы при перемещении курсора мыши менялось изображение элемента "рисунок", а именно: при нахождении курсора мыши в левой части элемента должна отображаться одна картинка, а при перемещении мыши в правую половину элемента — другая.
Подобная задача решается с помощью процедуры, обрабатывающей перемещение курсора мыши (MouseMove).
Рис. 1.13. Элемент "рисунок11, размещенный на рабочем листе
Рис. 1.14. "Пустая" процедура MouseMove в окне редактора программного кода
26
Глава 1
Перейдем в редактор программного кода, и в списке объектов выберем imagei (это имя по умолчанию и здесь мы не будем его менять), а в правом списке выберем действие, которое нас сейчас интересует, — MouseMove (рис. 1.14).
В листинге 1.7 приведена процедура, выполняемая при наведении курсора мыши на область рисунка.
| Листинг 1.7. Обработка перемещения мыши в области рисунка	I
Private Sub Imagel_MouseMove(ByVai Button As Integer,
ByVai Shift As Integer, ByVai X As Single, ByVai Y As Single)
If X < Imagei .Width / 2 Then
Imagei.Picture = LoadPicture("с:\рисунки\рис1.jpg")
Else
Imagei.Picture = LoadPicture("c:\pHcyHKn\pnc2.gif")
End If
End Sub
Здесь появились новые конструкции, которые требуют комментария.
Переменные х и y — это координаты курсора мыши, которые автоматически передаются системой в процедуру imageijwouseMove. Эти переменные располагаются в списке входных параметров процедуры, далее мы будем использовать значения этих переменных.
У объекта “рисунок" есть стандартное свойство width, которое определяет его ширину. В тексте листинга используется условие:
If X < Imagei.Width / 2 Then
Здесь проверяется, находится курсор мыши левее середины окна рисунка или нет. Если да, то в элемент imagei выводится изображение из файла pHcl.jpg, а если нет, то из файла pHc2.gif. При этом используется функция VBA Loadpicture, параметром которой является имя графического файла с указанием полного пути его расположения. В нашем случае графические файлы с указанными именами располагаются на диске С: (если на вашем компьютере другие имена каталога и файлов, то следует изменить входные параметры при вызовах функции LoadPicture).
Таким образом, сформулированное задание требует написания только одной процедуры.
Теперь, если выйти из режима конструктора и перейти в Excel, то вы увидите, что картинка в окне меняется в зависимости от того, где располагается курсор мыши.
Среда для написания программ на VBA 27
Динамическое изменение цвета кнопки
Разберем еще один пример, также связанный с реакцией на перемещение мыши.
Расположим на листе кнопку и сделаем так, чтобы при перемещении курсора мыши в области кнопки ее цвет менялся. А именно: если курсор мыши расположен в левом верхнем углу кнопки, то ее цвет должен быть красным, в правом верхнем — зеленым, в левом нижнем — синим, а в правом нижнем — серым.
Чтобы реализовать требуемый эффект, оформим процедуру реакции на перемещение мыши следующим образом (листинг 1.8).
i Листинг 1.8. Процедура, реализующая изменение цвета кнопки
Private Sub Cl_MouseMove(ByVai Button As Integer,
ByVai Shift As Integer, ByVai X As Single, ByVai Y As Single)
If X < Cl.Width / 2 And Y < Cl.Height / 2 Then
Cl.BackColor = RGB(255, 0, 0)
Elself X > Cl.Width / 2 And Y < Cl.Height / 2 Then
Cl.BackColor = RGB(0, 255, 0)
Elself X < Cl.Width / 2 And Y > Cl.Height / 2 Then
Cl.BackColor = RGB(0, 0, 255)
Else
Cl.BackColor = RGB(190, 190, 190)
End If
End Sub
Прокомментируем новые моменты. А именно: значение переменной y, которое передается в программу, представляет координату курсора мыши в области кнопки по вертикали. Полный размер кнопки по вертикали отражается в значении ее свойства Height. Заметим, что значение координаты y увеличивается от верхнего угла кнопки к нижнему, а координаты х — от левого угла кнопки к правому. В первом условии процедуры
If X < Cl.Width / 2 And Y < Cl.Height / 2 Then
проверяется — находится ли курсор в левом верхнем углу кнопки. Если условие выполняется, то цвет кнопки устанавливается красным. Для установки цвета используется свойство кнопки BackCoior и внутренняя функция rgb:
Cl.BackColor = RGB(255, 0, 0)
Глава 1
28
Примечание
rgb — это функция Visual Basic, которая позволяет установить цвет объекта в виде сочетания трех основных цветов — красного, зеленого и синего. Интенсивности каждого из этих основных цветов задаются в качестве трех входных параметров. При этом минимальное значение интенсивности цвета равняется О (в этом случае в составном цвете данная цветовая составляющая просто отсутствует), а максимальное 255. В рассматриваемой строке задаются максимальная интенсивность для красного цвета и отсутствие зеленого и синего цветов. При подобном сочетании этих трех базовых цветов кнопка будет красной.
Если первое условие не выполняется, то программа переходит к проверке второго условия:
Elself X > Cl.Width / 2 And Y < Cl.Height / 2 Then
Если оно выполняется, то устанавливается зеленый цвет кнопки:
Cl.BackColor = RGB(0, 255, 0)
А если второе условие не выполняется, то проверяется третье условие:
Elself X < Cl.Width / 2 And Y > Cl.Height / 2 Then
Если оно выполняется, то цвет кнопки становится синим, а если нет, то получается, что курсор мыши не находится ни в одной из трех просмотренных областей. Из этого однозначно следует, что курсор мыши располагается в правом нижнем квадранте, и кнопка закрашивается серым цветом.
Программа готова. Теперь выйдите из режима конструктора и, перемещая мышь в пределах кнопки, посмотрите на изменение ее цвета.
Вывод информации о текущем времени
Перейдем к следующей, более сложной разработке — создадим на рабочем листе интерфейс, показанный на рис. 1.15.
Здесь обозначения Часы, Минуты и Секунды представлены элементами типа "надпись" и поясняют назначение соответствующих текстовых окон, в которые выводится информация о времени. По щелчку на кнопке Старт в этих окнах отображается текущее время (происходит обновление значений часов, минут и секунд). Соответственно щелчком на кнопке Стоп обновление останавливается.
Кроме того, при обновлении значений времени в надписи, расположенной под кнопками, выводится сообщение о начале очередной минуты. В табл. 1.1 указаны имена и типы элементов управления, показанных на рис. 1.15.
Среда для написания программ на VBA
29
В качестве первого шага введем переменную flag, которая понадобится нам для остановки обновления времени. Эта переменная должна быть известна как процедуре обработки щелчка на кнопке Старт, так и процедуре обработки щелчка на кнопке Стоп.
В редакторе VBA есть общая область, где можно описывать переменные (рис. 1.16), которые должны быть известны внутри нескольких процедур.
Рис. 1.15. Интерфейс для вывода информации о текущем времени
Таблица 1.1. Имена элементов управления, представленных на рис. 1.15
Свойство Nene	Тип объекта	Назначение
Th	Текстовое окно	Вывод текущего значения часов
Tm	Текстовое окно	Вывод текущего значения минут
Ts	Текстовое окно	Вывод текущего значения секунд
Coml	Кнопка	Инициализация вывода значений текущего времени
Com2	Кнопка	Прекращение вывода значений текущего времени
Labi	Надпись	Вывод информации о начале следующей минуты
Строка программы в окне на рис. 1.16 означает следующее:
□	Dim — "определить" (это ключевое слово языка Visual Basic);
□	flag — имя переменной;
30
Глава 1
□ As integer — определить данную переменную как целое число (т. е. значениями этой переменной могут быть только целые числа).
Рис. 1.16. Раздел General (Declarations) — общая область
Таким образом, мы определили переменную, которая должна быть известна всем процедурам на данном рабочем листе Excel. И если одна из процедур изменит значение переменной flag, то это изменение можно увидеть из другой процедуры. В дальнейшем мы это используем для остановки обновления времени по щелчку на кнопке Стоп.
После такого вступительного комментария можно записать процедуру обработки щелчка на кнопке Старт (листинг 1.9).
| Листинг 1.9. Процедура выполняемая по щелчку на кнопке Старт
Private Sub Coml_Click()
flag = 0 ' Начальная установка переменной flag в О
While flag = 0 ' Организация цикла до оператора Wend
. Th = Format (Now(), "hh")
Tm = Format (Now (), "n")
Ts = Format(Now(), "ss")
DoEvents
If Ts = "00“ Then
Labi.Caption = "Началась новая минута"
Else
Labi.Caption = ""
End If
Wend
End Sub
Среда для написания программ на VBA 31
Рассмотрим строки этой процедуры.
Здесь используется оператор цикла, который начинается со строки while flag = о и заканчивается строкой wend. После ключевого слова while располагается условие, и если оно выполняется, то выполняются все строки процедуры вплоть до wend. Затем выполнение программы продолжается со строки while, и если условие опять выполняется, то все повторяется. Если же условие не выполняется, то выполнение программы продолжается с первой строки после Wend.
В строке
Th = Format(Now(), "hh")
используются несколько внутренних функций Visual Basic. Функция Now () не требует входных параметров и просто определяет текущие дату и время. Другая внутренняя функция Format позволяет задать определенный формат для выводимой информации. Если нам нужно выделить только часы, то в качестве второго аргумента функции Format мы должны задать "hh". Соответственно в следующих двух строках процедуры из текущего времени выделяются минуты и секунды.
Далее по тексту располагается внутренняя процедура Visual Basic — DoEvents, которая позволяет переключаться из выполняемого программного кода на обработку других событий. В данном случае нам требуется по щелчку на кнопке Стоп установить значение переменной flag в 1.
В условии
If Ts = "00" Then
проверяется начало отсчета новой минуты, и, если это так, выводится соответствующее сообщение. Далее, при смене информации в окне секунд это сообщение исчезает до начала отсчета следующей минуты.
Теперь осталось привести процедуру, выполняемую при щелчке на кнопке Стоп, — ее текст показан в листинге 1.10.
Листинг 1.10. Процедура, выполняемая при щелчке на кнопке Стол	j
Private Sub Com2_ClickQ
flag = 1
End Sub
Программа для обновления времени и остановки обновления готова, результат ее работы показан на рис. 1.17.
32
Глава 1
Рис. 1.17. Интерфейс в действии
Познакомимся в рамках данного примера со свойством, которое определяет разрешение доступа к элементам управления. Как мы уже знаем, у элементов управления есть свойство Enabled. Если это свойство принимает значение True, то доступ к данному элементу управления разрешен, в противном случае (если свойство принимает значение False) доступ элементу запрещен.
Изменим предыдущую разработку следующим образом.
В окне свойств установим свойство Enabled кнопки Старт в значение True, а для кнопки Стоп такое же свойство установим в значение False. Теперь при щелчке на кнопке Старт она должна стать недоступной, а доступ к кнопке Стоп, наоборот, должен разрешаться. И обратно: щелчок на кнопке Стоп делает ее недоступной, а доступ к кнопке Старт разрешается. В листинге 1.11 показана измененная процедура обработки щелчка на кнопке Стоп. (Изменение процедуры обработки щелчка на кнопке Старт в этом случае выполняется аналогично.)
Private Sub Com2_Click() flag = 1 Com2.Enabled = False Coml.Enabled = True
End Sub
Среда для написания программ на VBA
33
После выполненных изменений доступ к кнопкам в программе реализуется попеременно.
Примечание
По мере рассмотрения разработок в книге примеры усложняются, поэтому рекомендуется проработать каждый рассматриваемый пример.
Примечание
В разд. "Основные сведения по VBA" этой главы приведена справочная информация. Необходимые сведения по используемому языку программирования будут приводиться и в последующих главах в процессе рассмотрения разработок, поэтому явной потребности в дополнительной справочной информации пока нет. С другой стороны, читателю было бы полезно ознакомиться с известными книгами по рассматриваемой теме [1—5].
Полоса прокрутки
Продолжим изучение элементов управления. Следующий элемент, который мы рассмотрим, — полоса прокрутки.
Сразу же перейдем к очередному примеру разработки интерфейса. Откроем новый лист (либо просто новую книгу) и расположим на нем полосу прокрутки и текстовое окно (рис. 1.18).
Рис. 1.18. Полоса прокрутки и текстовое окно
34
Глава 1
Для текстового окна в качестве значения свойства Name выберем т-1, а аналогичное свойство полосы прокрутки установим в значение Seri.
У полосы прокрутки часто используются следующие свойства:
□	value — значение, соответствующее положению ползунка (движка) на полосе прокрутки;
□	мах — значение, соответствующее нижнему (или правому при горизонтальной полосе прокрутки) положению ползунка;
□	Min — значение, соответствующее верхнему (или левому при горизонтальной полосе прокрутки) положению ползунка;
□	Smallchange — значение, соответствующее изменению значения Value при щелчке на стрелке полосы прокрутки;
□	Largechange — значение, соответствующее изменению значения value при щелчке на полосе элемента.
У текстового окна (как у любого другого элемента) есть, свойство тор, которое определяет положение элемента по вертикали, начиная от верхнего края листа. А при изменении положения движка полосы прокрутки автоматически ВЫПОЛНЯетСЯ Процедура Scrl_Change ().
Теперь сформулируем задачу для программной разработки — при перемещении движка полосы прокрутки текстовое окно должно синхронно перемещаться на листе по вертикали. При этом, когда движок в верхнем положении, текстовое окно должно располагаться на уровне верхней границы полосы прокрутки. Соответственно, при нижнем положении движка текстовое окно должно располагаться на уровне нижней границы полосы прокрутки. В окне свойств для полосы прокрутки установим значение Min равным численному значению свойства тор, значение мах должно быть равно сумме значений свойств тор и Height (для этого требуется просто арифметически сложить числа). Установим также SmallChange = 1 И LargeChange = 5.
Теперь можно написать процедуру, которая выполняется при перемещении движка линейки прокрутки (листинг 1.12).
' Листинг 1.12. Процедура, выполняемая при перемещении движка полосы i прокрутки
Private Sub Scrl_Change()
Tl.Top = Scrl.Value
Tl.Text = "Положение по вертикали " + Str(Scrl.Value)
delta = 255 / (Scrl.Max - Scrl.Min)
Tl.BackColor = RGB(0, delta * (Scrl.Value - Scrl.Min), 0)
Среда для написания программ на VBA 35
inten = 255 - delta .* (Scrl.Value - Scrl.Min)
Tl.ForeColor = RGB(inten, inten, inten)
End Sub
Перед тем как прокомментировать работу программы, полезно посмотреть на результат ее работы (см. рис. 1.18). Кроме синхронного с движком полосы прокрутки перемещения текстового окна по вертикали изменяется сообщение в окне и меняются цвета фона и основного текста. Так, при верхнем положении движка цвет букв белый, а фона — черный. Далее, при перемещении движка вниз в цвете фона увеличивается интенсивность зеленой составляющей (до максимального значения), а цвет букв наоборот становится сначала серым, а при нижнем положении движка — черным.
Поясню некоторые конструкции этой процедуры.
В строке Ti.Top = si.value задается изменение положения верхнего угла текстового окна в соответствии с положением движка. Фактически это приводит к перемещению текстового окна по вертикали.
В следующей строке с помощью функции str данные числового типа преобразуются в строковый тип (о типах данных и об этой функции мы еще поговорим в конце главы). В результате в текстовое окно выводится сообщение о текущем положении движка на полосе.
В следующих двух строках задается изменение фонового цвета текстового окна. Как уже отмечалось, интенсивность цвета меняется от 0 до 255. В результате выполнения этих строк максимальная интенсивность зеленого обеспечивается при одном крайнем положении движка, а минимальная интенсивность — при другом его крайнем положении.
В конце процедуры задается изменение цвета текста в окне. Строки
inten = 255 - delta * (Scrl.Value - Scrl.Min)
Tl.ForeColor = RGB(inten, inten, inten)
обеспечивают различную интенсивность серого цвета текста (от черного до белого) в зависимости от положения движка.
Динамическое перемещение кнопки
Рассмотрим еще один простой, но эффектный пример.
Задача заключается в том, чтобы разместить на рабочем листе кнопку, положение которой должно автоматически меняться при наведении на нее курсора мыши. Фактически, в этом случае при выходе из режима конструктора навести на кнопку курсор мыши невозможно.
36
Глава 1
Рассмотрим, что потребуется сделать для подобного эффекта.
Сначала создадим на новом листе кнопку и ее свойство Name установим в значение coml. Затем перейдем в режим конструктора и напишем содержание процедуры comi_MouseMove () (ее примерный текст представлен на рис. 1.19). Как вы уже знаете, эта процедура автоматически выполняется при наведении курсора мыши на кнопку. В приведенном тексте используется внутренняя функция Visual Basic — Rnd, которая возвращает случайное число в интервале от 0 до 1. Координаты кнопки на листе определяются значениями свойств тор и Left. Поскольку функция Rnd выдает произвольное действительное число от 0 до 1, после умножения этого значения на 200 координаты кнопки могут принимать любые значения в интервале от 0 до 200.
Теперь, после перехода в окно Excel и выхода из режима конструктора, можно убедиться, что положение кнопки меняется.
Рис. 1.19. Процедура Coml_MouseMove ()
Разработка игры
Перейдем к следующему примеру — разработаем несложную игру.
На рабочем листе разместим два окна для рисунков (объекты "рисунок"), а также две кнопки и две надписи (рис. 1.20). При щелчке на кнопке Бросок в каждое окно рисунка случайным образом "попадает" одна из трех возможных картинок. Если картинки в обоих окнах совпадают, то в надпись для результата добавляется 3 балла, а если нет, то вычитается 1 балл. При щелчке на кнопке Начать игру заново значение результата обнуляется.
Таким образом, вступительная часть перед программированием завершена, поэтому перейдем к описанию программного кода.
Среда для написания программ на VBA
37
Рис. 1.20. Интерфейс несложной игры
Для размещения изображения в окне рисунка следует воспользоваться уже знакомой функцией Loadpicture. Нам также потребуется датчик случайных чисел — функция Rnd. На первом этапе мы должны дать объектам имена (табл. 1.2). Назначение элементов управления достаточно очевидно. Нескольких слов заслуживает надпись — объект для отображения результата. В ней вычисляется суммарный результат по итогам серии произведенных бросков.
В разделе General (Declarations) (см. рис. 1.16) следует задать переменную, которая будет использоваться для подсчета суммы баллов:
Dim symma As Integer
В листинге 1.13 приведена основная процедура, выполняемая по щелчку на кнопке Бросок.
Таблица 1.2. Объекты для разрабатываемой игры
Свойство Name	Тип объекта	Назначение
Imgl	Рисунок	Левый рисунок
Img2	Рисунок	Правый рисунок
Labi	Надпись	Слово "Результат11
Lab2	Надпись	Отображение числового значения результата
Coml	Кнопка	Бросок
Com2	Кнопка	Переход к началу игры
38
Глава 1
 Листинг 1,13. Обработка щелчка на кнопке Бросок
Private Sub Coml_Click()
а = CIntfRnd * 3) + 1
b = CIntfRnd * 3) + 1
If a = 1 Then
Imgl.Picture = LoadPicture("с:\рисунки\рис1.jpg")
Elself a = 2 Then
Imgl.Picture = LoadPicture("с:\рисунки\рис2.gif")
Else
Imgl.Picture = LoadPicture ("с:\рисунки\рис3.1япр")
End If
If b = 1 Then
Img2.Picture = LoadPicture("с:\рисунки\рис1.jpg")
Elself b = 2 Then
Img2.Picture = LoadPicture("с:\рисунки\рис2.gif")
Else
Img2.Picture = LoadPicture("с:\рисунки\рисЗ.fcrnp")
End If
If a = b Then
symma = symma + 3
Else
synrna = symma - 1
End If
Lab2.Caption - symma
End Sub
В тексте процедуры используется внутренняя функция Rnd, которая нам уже встречалась. Преобразование cintfRnd * 3) + 1 позволяет сформировать случайное целое число, которое может принимать три возможных значения: 1, 2 или 3. Таким образом, можно сопоставить значения переменных а и ь номерам картинок. При совпадении картинок мы увеличиваем значение переменной symma на 3, а при несовпадении соответственно уменьшаем на один. Другая кнопка (сот2) позволяет сбросить значение переменной symma в ноль для начала новой игры (листинг 1.14).
| Листинг 1.14. Процедура сброса суммы баллов в ноль	ИЙК
Private Sub Com2_Click()
symma = О
Lab2.Caption = symma
End Sub
Среда для написания программ на VBA 39
Разработка готова, однако в ней есть небольшой недостаток, а именно: функция Rnd при каждом повторном открытии книги формирует случайные числа в одной и той же последовательности. Чтобы этого избежать, следует воспользоваться функцией Randomize, которая выполняет перемешивание случайных чисел, и при повторных открытиях книги по нажатию кнопки Бросок картинки каждый раз будут выводиться в другой последовательности (листинг 1.15).
I-	•	•	......—....... .............................. ...........
Листинг 1.15. Включение в процедуру Coml_Click() функции Randomize
Private Sub Coml_Click()
Randomize
1 Здесь располагается прежний программный код процедуры
End Sub
Основные сведения по VBA
В этом разделе мы рассмотрим основные элементы языка, который используется во всех главах книги. При этом мы уделим внимание только тем конструкциям, которые нам понадобятся в последующих главах. Полную информацию по VBA можно получить из очень хороших книг, изданных недавно [1-5].
При написании процедур мы уже встречались с переменными. Переменная — это фрагмент компьютерной памяти, которому мы присвоили имя. Для обращения (записи или считывания информации) к этому фрагменту в программе следует использовать выбранное имя. Для того чтобы в зависимости от нужд программы переменным отводились разные фрагменты памяти, применяется понятие типов данных. Создавая переменную, мы сразу указываем (явно или неявно), к какому типу данных она относится. Основные типы данных языка VBA приведены в табл. 1.3. В этой таблице присутствуют как простые типы (например, integer и string), так и достаточно сложные (object и variant). Переменные типа object занимают в памяти компьютера мало места — всего 4 байта, однако при этом позволяют обращаться из процедур Microsoft Excel к таким сложным объектам, как приложение Microsoft Word. Далее, в главе 5, мы рассмотрим это на примере.
В VBA есть два варианта отведения памяти для переменных.
Первый способ — явный, в этом случае вы определяете тип создаваемой переменной с помощью инструкции. Синтаксис:
Dim Имя_Переменной As Тип_Даиных
40
Глава 1
Здесь Dim и as — ключевые слова языка программирования. В качестве имени переменной можно задавать любое слово (без внутренних пробелов), а возможные типы данных уже упоминались.
Можно несколько ускорить работу при написании программ — не объявлять переменные. В этом случае при появлении в тексте переменной, которая не была описана с помощью инструкции Dim, она автоматически становится переменной типа variant и для нее отводится соответствующая память.
Таблица 1.3. Основные типы данных
Тил данных	Значение	Комментарий
Boolean	True (истина) или False (ложь)	Логическое значение
Byte	От 0 до 255	Целое число без знака
Date	От 01.01.0100 до 31.12.9999	Дата и время
Object	Ссылка на объект	—
Integer	От-32 768 до 32 767	Короткое целое
Variant	Любое значение	Значение переменной любого типа
Long	От-2 147 483 648 до 2 147 483 647	Длинное целое
String	Символьная строка длиной от 0 до 64 Кбайт	Текст
Более сложный вид данных по сравнению с переменной — это массив, который представляет собой набор однотипных данных (набор данных определенного типа). Массив, как и переменная, задается именем. При этом каждый элемент массива определяется его индексом, например: mass(3) — третий элемент массива с именем mass. Объявление массива производится аналогично объявлению переменных:
Dim Имя_Массива (Граница_р!ассива) As Тиц_Ланных_Элемента_Массива
По умолчанию индексация массивов начинается с 0. Например, в следующей строке отводится память под массив mass:
Dim mass(10) As Integer
При этом в памяти выделяется 11 ячеек — каждая ячейка для хранения данных типа Integer.
Среда для написания программ на VBA 41
Примечание
Для одной переменной типа integer отводится 2 байта в памяти компьютера.
Поговорим теперь о встроенных функциях и процедурах, которые существенно облегчают программирование в среде VBA. Фактически они позволяют программисту быстро оформить стандартные действия. Рассмотрим ряд стандартных функций и процедур, которые нам понадобятся далее.
Для вывода сообщений на экран предназначена функция
MsgBox(сообщение[, кнопки], [заголовок])
Параметры: сообщение — текст, который будет отображен в диалоговом окне (параметр является обязательным, т. к. для вывода текста этого сообщения данная функция и существует; кнопки — числовое значение, т. е. сумма чисел, определяющих, какие кнопки будут отображены в диалоговом окне (для каждого варианта кнопок можно использовать либо числа, либо константы VBA, табл. 1.4); заголовок — текст, который будет помещен в заголовок диалогового окна (если этот параметр не указан, то выводится заголовок с информацией о приложении, из которого данная функция вызвана).
Таблица 1.4. Константы для функции MsgBox
Группа	Константа	Значение	Комментарий
	vbOKOnly	0	Только кнопка OK
	vbOKCancel	1	Кнопки ОК и Cancel
	vbYesNoCancel	3	Кнопки Yes, No и Cancel
	vbYesNo	4	Кнопки Yes и No
	vbDefaultButonl	0	По умолчанию выделяется первая • кнопка
II	vbDefaultButon2	256	По умолчанию выделяется вторая кнопка
	vbDefaultButon3	512	По умолчанию выделяется третья кнопка
	vbApp1i ca t i onModa1	0	Модальность приложения — работа с приложением блокируется, пока пользователь не закроет окно, открытое функцией MsgBox
	vbSys t emModa1	4096	Модальность системы — работа с системой блокируется, пока пользователь не закроет окно, открытое функцией MsgBox
42
Гпава 1
Нужное значение параметра кнопки можно получить сложением констант, приведенных в табл. 1.4. При этом можно указать только одну константу из каждой группы. Если параметр кнопки не указан, то по умолчанию предполагается, что его значение равно нулю:
MsgBox(сообщение, 0)
Это означает, что выбраны три константы с нулевыми значениями (vbOKOniy, vbDefaultButonl И vbApplicationModal).
Например, мы можем сформировать окно диалога с тремя кнопками (Yes, No, Cancel) и установкой фокуса (выделения) на третью кнопку. Для этого вызов функции можно оформить следующим образом:
MsgBox(сообщение, vbYesNoCancel+vbDefaultButon3)
Мы рассмотрели входные параметры для функции MsgBox, теперь поговорим о возвращаемых значениях.
Значение, возвращаемое данной функцией, говорит о том, какую именно кнопку нажал пользователь в диалоговом окне, что позволяет организовать в программе разную обработку в зависимости от разных действий пользователя. Для проверки возвращаемого значения можно воспользоваться константами VBA из табл. 1.5.
Таблица 1.5. Константы, возвращаемые функцией MsgBox
Константа	Значение	Нажатая клавиша
vbOK	1	ОК
vbCancel	2	Cancel
vbYes	6	Yes
vbNo	7	No
Рассмотрим функцию, позволяющую вводить информацию:
InputBox(сообщение[, заголовок][, значение_по_умолчанию])
Первые два параметра знакомы вам по функции MsgBox. Параметр значение-по_умолчанию определяет то значение, которое по умолчанию присутствует в поле ввода. Фактически это способ задать наиболее ожидаемое при вводе значение. Если этот параметр опущен, то в поле ввода будет пустая строка. Пример:
z = InputBox("Введите число маршрутов", "Начальная информация", 1)
При выполнении этой команды перед нами откроется окно ввода с заголовком Начальная информация.
Среда для написания программ на VBA
43
Как было сказано, в VBA есть несколько типов данных, и часто приходится выполнять действия с переменными разных типов. В большинстве случаев VBA самостоятельно корректно выполняет преобразование типов в операциях со смешанными типами данных. Однако в ряде ситуаций требуется указать, какое именно преобразование типов данных необходимо выполнить перед вычислением. Далее в рассматриваемых примерах часто будет использоваться преобразование строки в число и наоборот. Для этого можно воспользоваться стандартными функциями, приведенными в табл. 1.6.
Примечание
Некоторым недостатком приведенной в табл. 1.6 функции val является неопределенность типа числовых данных. Поэтому наряду с ней можно, например, использовать стандартную функцию преобразования типов сint (выражение), позволяющую выполнить преобразование выражения в число типа integer. Также есть аналогичные функции, выполняющие преобразование в другие числовые типы данных.
Таблица 1.6. Функции преобразования типов
Функция	Аргумент	Возвращаемое значение
Val	Строка	Число
Str	Число (любое)	Строка
Это были справочные сведения по VBA, необходимые для наших разработок. В следующих главах нам придется воспользоваться рядом стандартных процедур и функций, пояснения по которым будут приведены по ходу изложения.
Выводы
Таким образом, в этой главе мы познакомились с основами программирования в Microsoft Excel на примерах несложных разработок, связанных с наиболее популярными элементами управления и связанными с ними событиями. При этом приложение Microsoft Excel никак в разработках не проявлялось (создаваемые элементы управления и сам рабочий лист, на котором они располагались, не взаимодействовали друг с другом). В определенной степени такой подход правилен — новые технические моменты для лучшего восприятия следует рассматривать поэтапно. В следующей главе мы рассмотрим, каким образом процедуры VBA могут обмениваться информацией с листами Microsoft Excel. Однако перед этим для закрепления полученных сведений рекомендуется выполнить несколько самостоятельных заданий.
Гпава 1
Самостоятельная работа
Задание 1.1
Предлагаемое задание связано с некоторой модификацией разработки, соответствующей рис. 1.11. Требуется создать еще один список — для удаленных элементов. В этом случае при двойном щелчке на элементе списка Заказ он перемещается в список удаленных элементов. Также при заполнении списка Заказ выбранный элемент из списков продуктов и напитков не удаляется.
Задание 1.2
Это задание связано с модификацией программы, соответствующей рис. 1.15. Требуется обеспечить изменение цвета надписи, расположенной под кнопками Старт и Стоп через каждые 15 секунд. Надпись должна становиться синей на 5 с, а затем возвращаться к первоначальному цвету.
Задание 1.3
Требуется изменить задание, соответствующее рис. 1.18, а именно: создать еще одну полосу прокрутки — горизонтальную. При перемещении движков полос прокрутки текстовое окно должно перемещаться по горизонтали и вертикали.
Глава 2
Объекты Microsoft Excel
До настоящего времени мы рассматривали возможности VBA без особой связи с информацией на рабочем листе. В этой главе мы познакомимся с объектами, которые позволяют работать с данными, расположенными в ячейках листов рабочих книг Microsoft Excel. В дальнейшем (главы 4—6) будут рассмотрены сложные разработки, базирующие на основных конструкциях, которые мы здесь разберем.
Весь файл рабочей книги Excel представлен в объекте workbook, у которого есть много свойств и методов. Справочная информация по ним присутствует как в электронной справке по VBA, так и во многих изданиях по данной теме. Мы не будем углубляться в чисто справочную информацию, рассмотрев во вводной части только те сведения, которые понадобятся для разработки наших практических примеров.
Так, свойство worksheets объекта workbook представляет семейство всех рабочих листов книги. Для обращения к конкретному листу книги с помощью этого свойства следует просто указать в качестве параметра номер листа: Worksheets(номер_листа).
Примечание
Объект workbook представляет рабочую книгу Excel, однако синтаксис работы с ним требует использования коллекции подобных объектов (в качестве параметра коллекции указывается имя файла рабочей книги):
Workbooks("МояРабочаяКнига.xls").Worksheets(номер_листа)
Если книга, с которой мы работаем в конкретной ситуации, — единственная (активная в данный момент, хотя открытых может быть много), то указывать книгу не требуется. Если написать Worksheets (номер_листа), то этот лист относится к текущей книге.
Одним из наиболее часто используемых в программировании событий, связанных с книгой в целом, является событие open, которое происходит при
46
Гпава 2
открытии рабочей книги. Если мы хотим, чтобы при открытии книги выполнялись определенные действия, то следует расположить необходимый программный код внутри процедуры workbook_0pen. В большинстве рассматриваемых далее примеров будет задействовано программирование этого события.
Следующим объектом в иерархии после workbook является объект worksheet, представляющий рабочий лист. Из множества разнообразных методов этого объекта чаще других используется метод Activate, который существует и для семейства листов worksheets, о котором уже говорилось. Например, если при работе на первом листе книги требуется активизировать третий лист, то синтаксис программной строки в процедуре (скажем, выполняемой по щелчку на кнопке) должен быть таким:
Worksheets(3).Activate
Известно, что Microsoft Excel предлагает сервис, связанный с защитой рабочих книг и составляющих ее листов. В примерах мы будем использовать метод Protect семейства worksheets, который защищает рабочий лист от внесения в него изменений. Установить программную защиту с паролем (пароль указывается в параметре Password этого метода) третьего листа можно так:
Worksheets(3).Protect Password: =" 12 3 4 5", DrawingObjects:=True,_
Contents:=True, Scenarios:=True
Есть и соответствующий метод unprotect, позволяющий снять защиту с листа. Снять защиту, установленную в примере из предыдущего абзаца, можно так: Worksheets(3).Unprotect Password:="12345"
Любая практическая работа в Excel так или иначе касается информации в ячейках. Для работы с ячейками в VBA есть объект Range (в переводе — диапазон ячеек). Использование этого объекта требует задания в качестве параметра диапазона ячеек, которые нас интересуют (одна ячейка или группа ячеек). Например:
Worksheets(3).Range ("Al").Value = 5
Это означает, что в ячейку ai третьего листа мы программно записываем число 5. Здесь используется основное свойство объекта Range — value. Буквально оно означает значение или содержимое ячейки (или нескольких ячеек).
В следующей конструкции все ячейки диапазона программно заполняются буквой А:
Worksheets(1).Range ("Al:СЗ").Value = "А"
Другой способ работы с ячейками реализуется с помощью объекта cells. Синтаксис его использования:	,
Cells (номер_строки, номер_столбца)
Объекты Microsoft Excel 47_
Фактически, с точки зрения использования рассматриваемые объекты похожи. Например, получить в переменной z значение ячейки D5 можно двумя разными способами:
Z = Range("D5").Value
ИЛИ
Z = Cells(5, 4).Value
Пример программной конструкции на тему обоих этих объектов:
Worksheets(2).Range("C5").Value = Worksheets(3).Cells(5, 1) .Value
Автоматизированный бланк
Теперь, после того как мы познакомились с простыми конструкциями доступа из процедур VBA к ячейкам рабочего листа Excel, пора перейти к более сложной задаче.
Будем считать, что нам требуется разработать удобный бланк заказа при обслуживании покупателей в компьютерном салоне — обеспечить удобный подбор необходимой конфигурации компьютера из возможных вариантов по информации, присутствующей в прайс-листе.
Будем считать, что в конфигурацию компьютера входит максимум 3 компонента: системный блок, монитор и принтер. Широкая номенклатура различных системных блоков, мониторов и принтеров отражается на втором листе книги (такой лист с названием "Наш прайс" представлен на рис. 2.1). Понятно, что строк в прайс-листе может быть достаточно много, и постоянно прокручивать его при подборе заказа не очень удобно.
Рис. 2.1. Прайс-лист
*3 Гпава 2
Итак, приступим к разработке удобного электронного бланка заказа. Заметим только: в данной книге предполагается, что прайс-лист должен находиться на втором рабочем листе семейства листов (в программном коде номер листа используется в качестве параметра семейства worksheets).
На рис. 2.1 видно, что первая строка прайс-листа представляет собой совокупность заголовков, а сами данные располагаются, начиная со второй строки. Столбцы А и В отображают соответственно описание системного блока и его цену. Следующие две пары столбцов — название и цена для принтера и монитора.
Мы попробуем на первом рабочем листе создать удобный для пользователя электронный бланк заказа, который будет использовать информацию из прайс-листа.
Интерфейс первого листа, который нам требуется разработать, показан на рис. 2.2. Сделаем это так.
Сначала расширим столбцы А, В и С, а затем в ячейку В2 введем текст "Бланк заказа" и отформатируем его соответствующим образом. После этого разместим на рабочем листе элемент "надпись" с текстом "Заказ №’’. Для этого свойство caption установим в соответствующее значение, а с помощью свойства BackColor обеспечим серый фон. Значение свойства Name для этого объекта особой роли не играет.
Рядом с надписью на листе разместим элемент "текстовое окно" для ввода номера заказа с клавиатуры. Для свойства Name этого элемента выберем значение Zkz, добавим серый фон окна (с помощью свойства BackColor), а свойство Autosize установим в значение True (в этом случае ширина текстового окна будет автоматически увеличиваться при вводе символов).
Теперь следует заполнить текстом (рис. 2.2) содержимое ячеек А5, В5, С5, А7, А8, А9, А12 и выполнить соответствующее форматирование.
После этого уберем с экрана сетку (снимем флажок Сетка на вкладке Вид диалогового окна Параметры, открываемого одноименной командой меню Сервис), а для прямоугольного диапазона ячеек А5—С14 установим внешние и внутренние границы. Кроме этого можно установить заливку для диапазона А5—С14 и выбрать подложку для листа (все это выполняется с помощью несложных технических действий в Microsoft Excel).
Теперь следует разместить три элемента управления типа "поле со списком" (с ними мы уже работали в главе Z). Чтобы не было противоречий с программным кодом, выберем для этих элементов имена (сверху вниз): spWi, Spk2 И Spk3.
Объекты Microsoft Excel
49
Рис. 2.2. Интерфейс первого листа
Итак, мы создали интерфейс для нашей разработки. Далее наступает этап программирования созданных элементов, поэтому перейдем в редактор для написания программного кода.
Первая наша задача заключается в том, чтобы при открытии книги созданные три списка на первом листе автоматически заполнялись информацией из прайс-листа. В начале главы мы уже говорили о том, что при открытии книги автоматически выполняется предопределенная процедура workbook_0pen (). Для того чтобы перейти к написанию этой процедуры, следует в редакторе кода в меню View выбрать пункт Project Explorer и в появившемся окне сделать двойной щелчок на пиктограмме ЭтаКнига. Таким образом, мы получили доступ к методам объекта workbook.
Теперь наша задача — правильно оформить процедуру workbook_0pen о, которая обеспечивает заполнение списков моделями системных блоков, принтеров и мониторов (листинг 2.1).
Листинг 2.1. Процедура, выполняемая при открытии книги
Private Sub Workbook_Open( )
' Очистка первого списка на первом листе книги
Worksheets(1).Spkl.Clear
50
Гпаев 2
' Подсчет в переменной N количества вариантов системных блоков по прайсу N = О
While Worksheets(2).Cells(N + 2, 1).Value о ""
N = N + 1
Wend
* Заполнение первого списка
For i = 2 To N + 2
Worksheets(1).Spkl.Additem Worksheets(2) .Cells(i, 1).Value
Next
' Очистка второго списка на первом листе книги.
' Подсчет в переменной N количества моделей принтеров
Worksheets(1).Spk2.Clear
N = О
While Worksheets(2).Cells(N + 2, 3).Value <> ""
N = N + 1
Wend
' Заполнение второго списка
For i = 2 To N + 2
Worksheets(l).Spk2.Additem Worksheets(2).Cells(i, 3).Value
Next
' Очистка третьего списка на первом листе нашей книги.
' Подсчет в переменной N количества моделей мониторов
Worksheets(1).Spk3.Clear
N = О
While Worksheets(2).Cells(N + 2, 5).Value <> ""
N = N + 1
Wend
1 Заполнение третьего списка
For i = 2 To N + 2
Worksheets(1).Spk3.Additem Worksheets(2).Cells(i, 5).Value
Next
'Установка начальных параметров
Worksheets(1).Spkl.Listindex = -1
Worksheets(1).Spk2.Listindex = -1
Worksheets(1).Spk3.Listindex = -1
Worksheets (1) . Zkz. Text = ''"
Worksheets(1).Range("C7:C9").Value = ""
End Sub
Объекты Microsoft Excel 51
Прокомментируем еще несколько программных конструкций этой процедуры. Команда
While Worksheets(2).Cells(N + 2, 1).Value о ""
извлекает содержимое ячейки из первого столбца с информацией об очередной модели системного блока со второго листа. Конструкция <> обозначает "не равно", а " - — это две двойные кавычки, между которыми ничего нет. В совокупности эта запись обозначает выполнение цикла, пока значение в очередной ячейке списка системных блоков на втором листе не окажется пустым. Пустая ячейка — это индикатор того, что данных в этом столбце больше нет. Таким образом, чтобы избежать потери информации при заполнении списков, следует не допускать разрывов в данных на втором листе.
В процедуре, приведенной в листинге 2.1, после подсчета количества системных блоков используется метод Additem, который добавляет в объект "поле со списком" новый элемент (новую строку). Так, в команде
Worksheets(1).Spkl.Additem Worksheets(2).Cells(i, 1).Value
через пробел записывается содержимое ячейки, которое добавляется в список spkl. В данном случае это ячейка Cells(i, 1) второго листа. Другие списки заполняются аналогично и отличаются только номерами столбцов.
Таким образом, мы создали процедуру workbook_Open(), которая обеспечивает заполнение списков данными со второго листа (из прайс-листа) при открытии книги. Теперь, для того чтобы все то, что мы создали, работало, необходимо книгу закрыть и заново открыть ее.
Однако пока выбор в списках той или иной модели не приводит к заполнению информации о ее цене. Нашу разработку следует продолжить, поэтому мы заново вернемся в окно написания программного кода.
Для автоматической подстановки цены модели необходимо написать процедуры, выполняемые по щелчкам на списках. В листинге 2.2 приведена процедура, выполняемая при щелчке на первом списке (включающем системные блоки).
| Листинг 2.2. Обработка щелчка на списке системных блоков
Private Sub Spkl_Click()
Range("с7").Value = Worksheets(2). Cells(Spkl.Listindex +2, 2). Value
End Sub
В этой процедуре ячейка С7 заполняется ценой системного блока из прайса. Если посмотреть на бланк заказа, то именно ячейка С7 на этом листе
5г
Глава 2
отводится для цены системного блока. Здесь же в этой конструкции spkl.Listindex — индекс выделенного элемента в первом списке. Двойка добавляется к этому значению потому, что индексация элементов списка начинается с нуля, а данные о системных блоках на втором листе располагаются со второй строки. Здесь также учитывается, что цены системных блоков указаны во втором столбце. Таким образом, в этой строке мы извлекаем информацию о цене системного блока. Может возникнуть вопрос — почему в правой части команды мы указали номер листа (2), а в левой нет? Это связано с тем, что объект с именем spkl, событие которого мы обрабатываем, находится на первом листе, который и предполагается листом по умолчанию. Щелчки по двум другим спискам приводят к аналогичным действиям (к заполнению цен принтера и монитора), и в листинге 2.3 приведены процедуры, реализующие этот эффект.
Листинг 2.3. Процедуры выбора цен принтера и монитора
Private Sub Spk2_Click()
Range("cB").Value = Worksheets(2).CelIs(Spk2.ListIndex + 2, 4).Value
End Sub
Private Sub Spk3_Click()
Range("c9").Value = Worksheets(2).Cells(Spk3.Listindex + 2, 6).Value End Sub
В результате мы получили автоматизированное заполнение бланка заказа (выбор в списках названий позиций товаров и автоматическая подстановка цены). Для калькуляции суммы заказа осталось только поставить в ячейку С12 формулу для вычисления суммы: =СУММ(С7:С9)
Заметим, что это обыкновенная формула в ячейке первого листа Microsoft Excel.
Следующий этап автоматизации заключается в создании печатной формы этого бланка.
Сначала создадим на первом листе кнопку Печать (рис. 2.3), а затем напишем для нее необходимую процедуру.
Таким образом, теперь мы должны на третьем листе книги создать печатную (автоматически заполняемую по щелчку на кнопке) форму.	/
Объекты Microsoft Excel
53
Рис. 2.3. Кнопка Печать
Рис. 2.4. Форматирование третьего листа книги
54
Гпава 2
Первая задача на этом пути, как и прежде, чисто техническая — обеспечить форматирование третьего листа книги подобно тому, как показано на рис. 2.4 (никаких элементов управления здесь нет). Форматирование листа: добавлен фон ячеек, созданы внешние и внутренние границы, подобран размер шрифта, содержимое ячейки выровнено по горизонтали. Также здесь мы убрали отображение сетки. В дальнейшем в ячейку С2 будет подставляться номер заказа с первого листа (точнее, из соответствующего текстового поля), а содержимое таблицы также будет автоматически заполняться информацией о заказанных позициях и их ценах. При желании можно добавить логотип организации и внести дополнительную текстовую информацию. В этом случае третий лист нашей книги будет больше похож на печатную форму документа.
Фактически мы разработали заготовку, в которую по щелчку на кнопке Печать будет заноситься информация о текущем заказе с первого листа.
Перейдем в режим конструктора и затем в редактор написания программного кода. Это выполняется, как мы знаем, двойным щелчком на кнопке Печать. В этом случае автоматически выполняется процедура, которая обрабатывает щелчок на рассматриваемой кнопке (листинг 2.4).
| Листинг 2.4. Обработка щелчка на кнопке Печать
Private Sub Pm_Click()
' Очистка печатного бланка
Worksheets(3).Range(" А10;С17").Value = ••
’ Ячейка на пересечении 10-й строки и 2-го столбца
’ отводится для модели системного блока
Worksheets(3).Cells(10, 1).Value = "I"
Worksheets(3).Cells(10, 2).Value = _
Worksheets(1).Cells(7, 1).Value + " " + Spkl.Text
’ Ячейка на пересечении 10-й строки и 3-го столбца
' отводится для цены системного блока
If Spkl.Listlndex > -1 Then
Worksheets(3).Cells(10, 3).Value = _
Worksheets(2).Cells(Spkl.Listindex + 2, 2).Value
End If
' Ячейка на пересечении 11-й строки и 2-го столбца
1 отводится для модели принтера
Worksheets(3).Cells(11, 1).Value = "2"
Worksheets(3).Cells(11, 2).Value = _
Worksheets(1).Cells(8, 1).Value + " " + Spk2.Text
' Ячейка на пересечении 11-й строки и 3-го столбца	t
Объекты Microsoft Excel
' отводится для цены принтера
If Spk2.ListIndex > -1 Then
Worksheets(3).Cells(11, 3).Value = _
Worksheets(2).Cells(Spk2.Listindex + 2, 4).Value End If 1 Информация о мониторе и его цене Worksheets(3).Cells(12, 1).Value = "3" Worksheets(3)-Cells(12, 2).Value = _
Worksheets(1).Cells(9, 1).Value + " " + Spk3.Text If Spk3.Listindex > -1 Then Worksheets(3).Cells(12, 3).Value = _
Worksheets(2).Cells(Spk3.Listindex + 2, 6).Value End If ' Автоматическая установка номера заказа Worksheets(3).Range("c2") .Value = Zkz.Text Worksheets (3) .Range ("Ы6") .Value = "Итого" Worksheets(3).Range("cl6").Value = Range("cl2").Value Worksheets(3).Activate End Sub
Рис. 2.5. Пример заполнения бланка
56
Гпаев 2
Теперь автоматизированная книга готова, и вы можете попробовать оформить с помощью созданной разработки несколько гипотетических заказов. На рис. 2.5 приведен один из вариантов заполнения бланка.
Бланк заказа на офисные товары
Рассмотрим еще одну подобную задачу.
Наша цель — разработать удобное приложение для составления заявки на канцелярские товары для офиса. Начнем с того, что создадим новую рабочую книгу Excel и на втором листе сформируем список товаров с указанием их цен (рис. 2.6). Этот список организован достаточно просто — название товара и рядом его цена.
Рис. 2.6. Список товаров с ценами
После этого создадим на первом рабочем листе удобную форму для ввода информации о заказе (рис. 2.7).
Сначала рассмотрим технические действия по оформлению первого листа.
Начнем с того, что уберем сетку с экрана (команда Параметры меню Сервис). После этого оформим столбцы А, В, С и D следующим образом: установим внешние и внутренние границы, введем подписи столбцов в ячейки А2, В2, С2 и D2.
Теперь перейдем к размещению элементов управления на листе.
Объекты Microsoft Excel
57
Рис. 2.7. Форма для ввода информации о заказе
Верхний правый элемент на этом рисунке — "поле со списком". Имя этого объекта нам далее потребуется, поэтому для его Свойства Name установим "наше" значение: spk.
Затем расположим на листе две надписи, в одну из которых просто записывается слово "Итог" (сделать это можно в окне свойств с помощью свойства caption), а другая далее будет использоваться для подсчета суммы. Имя второй надписи будет использоваться в других процедурах, поэтому установим ее свойство Name в значение ьы.
В верхней части экрана располагаются еще три кнопки — Очистить, Пересчет и Печать. Для них выберем имена cir, calc и Prn соответственно.
На этом дизайн интерфейса завершен, и мы можем перейти к программированию.
Необходимо сделать так, чтобы список spk автоматически заполнялся при открытии книги. Поэтому оформим процедуру, выполняемую при открытии книги, следующим образом (листинг 2.5).
Private Sub Workbook_Qpen'()
' Очистка списка
Worksheets(1).Spk.Clear
' Подсчет количества записей в прайс-листе (второй лист) N = О
While Worksheets(2) .Cells(N + 1, 1) .Value о ""
58 Глава 2
N х N + 1
Wend ' Заполнение списка For i = 1 To N
a = Worksheets(2).Cells(i, 1).Value & "	" & _
Worksheets(2).Cells(i, 2).Value & " руб."
Worksheets(1).Spk.Additem a Next
' Установка нуля в поле суммы Worksheets(1).Lbl.Caption = "0" ' Начальная установка списка Worksheets(1).Spk.ListIndex = -1 End Sub
Следующая задача в рамках данной разработки заключается в том, чтобы при щелчке на списке информация фиксировалась в очередной строке первого рабочего листа. Таким способом мы включаем в заявку очередную строку с помощью следующей процедуры (листинг 2.6).
| Листинг 2.6. Процедура, выполняемая по щелчку на списке
Private Sub Spk_Click()
1 Подсчет в переменной N количества уже заполненных строк бланка заказа N = О
While Cells(N + 3, 1).Value <> "" N = N + 1
Wend
1 Запись названия очередной позиции в заявку
Cells (N + 3, 1) = Worksheets(2).Cells(Spk.Listindex + 1, 1).Value
' Запись цены очередной позиции из прайс-листа
Cells(N + 3, 2) = Worksheets(2).Cells(Spk.Listindex + 1, 2).Value
* Использование стандартной функции InputBox ' для .ввода количества товаров с клавиатуры qw = InputBox("Введите количество", "Ввод числа единиц товара", 1) Cells(N + 3, 3).Value = qw
' Вычисление суммы по позиции товара
Cells(N + 3, 4).Value = qw * Cells(N + 3, 2).Value ' Подсчет итоговой суммы
Lbl.Caption = Str(Vai(Lbl.Caption) + Cells(N +3, 4))
End Sub	«
Объекты Microsoft Excel
59
Здесь используются стандартные функции Visual Basic: val (для перевода информации из текстового вида в числовой) и str (для перевода информации из числового вида в текстовый).
Обработку щелчков на кнопках Пересчет и Очистить мы рассмотрим чуть позже, а пока оформим третий лист, как показано на рис. 2.8. Здесь никаких элементов управления нет — только текст и форматирование ячеек.
Теперь, после того как создана заготовка печатной формы, можно перейти к разработке процедуры, выполняемой при щелчке на кнопке Печать (листинг 2.7).
Рис. 2.8. Оформление третьего листа книги
Листинг 2.7. Обработка щелчка на кнопке Печать
Private Sub Pm_Click()
' Очистка листа печати
Worksheets(3).Range("А14:F3 4").value = “"
' Подсчет заполненных строк в бланке заказа N = О
While Worksheets(1).Cells(N + 3, 1).Value < > "" N = N + 1
Wend
' Цикл по строкам бланка заказа
For i = 1 To N
’ заполнение поля номера позиции
Worksheets(3).Cells(13 + i, 1) = i
' Заполнение поля названия позиции заказа
Worksheets(3).Cells(13 + i, 2) = Worksheets(1).Cells(2 + i, 1)
' Заполнение поля цены единицы товара
Worksheets(3).Cells(13 + i, 3) = Worksheets(1).Cells(2 + i, 2)
' Заполнение поля количества единиц товара
Worksheets(3).Cells(13 + i, 4) = Worksheets(1).Cells(2 + i, 3)
' Заполнение поля цены с учетом количества
Worksheets(3).Cells(13 + i, 5) = Worksheets(1).Cells(2 + i, 4)
Next
' Активизация третьего листа
Worksheets(3) .Activate
End Sub
На рис. 2.9 и 2.10 соответственно приведены один из вариантов заполнения бланка и его печатная форма.
Ранее было сказано, что две процедуры (первая выполняется при щелчке на кнопке Очистить, а вторая при щелчке на кнопке Пересчет) мы оформим позднее. Напишем процедуру для кнопки Очистить (листинг 2.8).
Рис. 2.9. Пример заполнения бланка
Объекты Microsoft Excel
61
Рис. 2.10. Пример печатной формы
Листинг 2.8. Процедура, выполняемая при щелчке на кнопке Очистить
Private Sub Clr_Click() ' Подсчет заполненных строк в бланке заказа N = 0
While Cells(N + 3, 1).Value о ""
N = N + 1 Wend
For i = 3 - To N + 2
Cells(i, 1).Value = ""
Cells(i, 2).Value = ""*
Cells(i, 3) .Value « '", Cells(i, 4).Value = "" Next ' Установка нулевой суммы Lbl.Caption = "0" End Sub
62
Гпава 2
Осталось рассмотреть процедуру, связанную с кнопкой пересчет (листинг 2.9). Смысл ее в том, что если в бланк заказа внесено изменение (удалена строка или изменено количество единиц товара), то необходимо пересчитать и итоги.
Листинг 2.9. Процедура, выполняемая при щелчке на кнопке Пересчет
Private Sub Пересчет_СИск()
• Подсчет заполненных строк в бланке заказа
N = О
While Worksheets(1).Cells(N + 3, 1).Value о ""
N = N + 1
Wend
' Пересчет суммы
syrtma = 0
For i = 3 To N + 2
a = Worksheets(1).Cells(i, 3).Value
Worksheets(1)-Cells(i,4).Value = Worksheets(1).Cells(i, 2).Value * a
syrtma = symma + Worksheets(1).Cells(i, 4).Value
Next
' Занесение подсчитанной суммы в надпись
Lbl.Caption = Str(symma)
End Sub
Рабочая книга фактически готова, но мы попробуем немного "улучшить" ее. Ранее мы создали необходимую обработку, выполняющуюся при открытии книги — в процедуре workbook_open (). Однако здесь есть некоторые неудобства, связанные с тем, что изменения, внесенные в номенклатуру товаров, отражаются в элементах "поле со списком" на первом листе только после закрытия и последующего открытия книги. Чтобы эти изменения сразу же отражались в уже открытой книге, необходимо оформить соответствующим образом процедуру worksheet_Activate (), которая выполняется при активизации листа (листинг 2.10).
Листинг 2.10 Процедура, выполняемая при активизации первого листа
Private Sub Worksheet_Activate()
' Очистка первого списка
Worksheets(1).Spk.Clear
' Подсчет количества записей в прайсе на втором листе
63
Объекты Microsoft Excel 
N = О
While Worksheets(2).Cells (N + 1, 1).Value <> ""
N = N + 1
Wend
' Заполнение списка
For i = 1 To N
a = Worksheets(2).Cells(i, 1).Value & • " & _ Worksheets(2).Cells(i, 2).Value & " руб."
Worksheets(1).Spk.Additem a
Next
' Установка нуля в поле для суммы
Worksheets(1).Lbl.Caption = "0"
End Sub
Электронная анкета
Решим еще одну практическую задачу — заполнение электронного бланка анкеты. В разрабатываемом листе будет достаточно много элементов управления, поэтому здесь мы рассмотрим оформление листа последовательно.
Начнем разработку с небольших деталей (рис. 2.11). Заполним три ячейки в столбце В поясняющей информацией, а для трех ячеек столбца С просто подберем соответствующее форматирование — заливку и размер шрифта (работая в дальнейшем с этим бланком, пользователь будет вносить в ячейки С2, С4 и С6 соответственно фамилию, имя и отчество). Как обычно, отключим сетку рабочего листа.
Рис. 2.11. Интерфейс для электронной анкеты, этап 1
64
Гпава 2
В правой части рис. 2.11 кроме элементов управления видна чисто оформительская деталь — рамка (кнопка, позволяющая добавить ее на лист, располагается на панели инструментов Рисование). Также здесь появился новый элемент управления — переключатель, позволяющий обеспечить пользователю, заполняющему бланк, выбор одного из двух вариантов:
□	НЛовгород;
□	Другой город.
В случае выбора варианта Другой город следует указать, какой именно. Понятно, что рассматривается ситуация, когда большинство людей, заполняющих бланк, проживает в Нижнем Новгороде.
Зададим значения свойства Name для этих элементов управления:
□	opti (переключатель Н.Новгород);
□	opt2 (переключатель Другой город);
О city (текстовое окно для ввода названия города).
В начальном варианте (при открытии книги для заполнения анкеты) по умолчанию установлен вариант—Н.Новгород, далее мы реализуем это, программно устанавливая свойство value этого переключателя в значение True). При этом текстовое окно для ввода названия другого города скрыто — для этого свойство видимости visible объекта city необходимо установить в значение False (далее мы также сделаем это программным способом).
При щелчке на переключателе Другой город текстовое окно city становится видимым, а при щелчке на переключателе НЛовгород опять скрывается. Тексты процедур обработки щелчков на переключателях приведены в листинге 2.11.
| Листинг 2.11. Проце, уры обработки щелчков на переключателях (выбор города)
Private Sub Qptl_Click()
City.Visible = False
End Sub
Private Sub Qpt2_Click() City.Visible = True
End Sub
Подчеркнем один важный технический момент. Мы расположили на листе два переключателя, взаимосвязанных друг с другом. При щелчке на одном из них значение свойства value другого автоматически устанавливается в False.
Объекты Microsoft Excel 65
Далее мы расположим на нашем рабочем листе еще несколько переключателей для выбора категории анкетируемого (учащийся или специалист). Для того чтобы все переключатели работали правильно, необходимо указать, какие из них к какой группе относятся. Для этого следует установить значения свойств GroupName всех переключателей, связанных с городами, сделать одинаковыми (например, задать их равными op_city). Для других переключателей значение данного свойства должно отличаться.
Теперь можно выйти из режима конструктора, проверить работу написанных процедур, а затем продолжить создание рассматриваемой разработки. На рис. 2.12 показана следующая группа элементов управления, которые нам нужно добавить на тот же рабочий лист.
Рис. 2.12. Интерфейс для электронной анкеты, этап 2
В верхней левой части рис. 2.12 сосредоточены элементы, которые заполняются при условии, если анкетируемый является студентом. Соответственно правая часть — для тех, у кого уже есть диплом. При этом фрагменты Место учебы, Курс, Место раб.оты и Примечание являются просто надписями. Они поясняют содержимое текстовых окон, расположенных правее.
Два переключателя Студент (Name = st) и Специалист (Name = sp) относятся к одной группе переключателей, отличной от группы переключателей, используемой для выбора города. Теперь поясним, как они будут использоваться.
66
Гпава 2
При выборе переключателя Студент видимыми становятся текстовые окна для заполнения полей анкеты Место учебы (Name = Place) и Курс (Name = Kyrs), а текстовые окна для заполнения полей Место работы (Name = work) и Примечание (Name = Prim) скрываются. Соответственно при выборе переключателя Специалист все наоборот — видимыми становятся текстовые окна, которые должен заполнить специалист.
В нижней части листа на рис. 2.12 располагаются три флажка (кнопка этого элемента управления на панели инструментов Элементы управления — четвертая слева). Имена этих объектов (сверху вниз): Eng, Auto и info. Используем основное свойство флажка — value, которое принимает два возможных значения — False И True.
Таким образом, мы рассмотрели функциональное назначение элементов на листе электронной анкеты. Теперь перейдем к процедурам. Как уже говорилось, при открытии книги по умолчанию должны быть выбраны переключатели НЛовгород и Студент. Лучше всего реализовать это в процедуре Workbook_open (листинг 2.12).
Листинг 2.12. Процедура, выполняемая при открытии книги
Private Sub WorkbookjDpen ()
Worksheets(1).Optl.Value = True
Worksheets(1).Opt2.Value = False
Worksheets(1).City.Visible = False
Worksheets(1).St .Value = True
Worksheets(1).Place.Visible = True
Worksheets(1).Place.Text = " "
Worksheets(1).Kyrs.Visible = True
' По умолчанию рассматривается студент первого курса
Worksheets(1).Kyrs.Text = "1 "
Worksheets(1).Work.Visible = False
Worksheets(1).Work.Text = " "
Worksheets(1) .Prim.Visible = False
Worksheets(1).Prim.Text = " "
Worksheets(1).Eng.Value = False
Worksheets(1).Auto.Value - False
Worksheets(1).Inf©.Value = False
End Sub
Объекты Microsoft Excel
67
В результате мы обеспечили автоматическую установку начальных значений при открытии книги. Словами действие переключателей st и sp мы уже прокомментировали, теперь необходимо привести программные процедуры обработки щелчков на них (листинг 2.13).
Листинг 2.13. Процедуры, выполняемые по щелчку на переключателях Sp и st
Private Sub St_Click() Place.Visible = True Kyrs.Visible = True Work.Visible = False Prim.Visible = False
End Sub
Private Sub Sp_Click() Place.Visible = False Kyrs.Visible - False Work.Visible = True Prim. Visible = True
End Sub
Рис. 2.13. Запись введенной информации в базу данных
Мы обеспечили необходимый интерфейс ввода информации на первый рабочий лист. Будем считать, что информацию с первого листа следует записать в базу данных — на второй лист (рис. 2.13). Здесь для данных по каждому анкетируемому отводится по одной строке. И по щелчку кнопки Записать
68
Гпава 2
иа второй лист информация анкеты переписывается в очередную свободную строку второго листа. В листинге 2.13 приводится текст данной процедуры. Как вы уже заметили, из названия процедуры следует, что для свойства Name кнопки установлено значение wri teList2.
Листинг 2.14. Процедура, выполняемая по щелчку на кнопке Записать на второй лист
Private Sub WriteList2_Click()
* Подсчет количества имеющихся записей на втором листе N = О
While Worksheets(2).Cells(N + 2, 1).Value о ""
N = N + 1
Wend
’ Запись порядкового номера в первый столбец Worksheets(2).Cells(N + 2, Devalue = N + 1
’ Копирование фамилии, имени и отчества
Worksheets(2).Cells(N + 2, 2).Value = Range(”c2”)
Worksheets(2) .Cells (N + 2, 3) .Value = Range(nc4")
Worksheets(2).Cells(N + 2, 4).Value = Range("сб") ' Запись названия города в пятый столбец на втором листе
If Qptl .Value » True Then
Worksheets(2).Cells(N + 2, 5).Value • "Н.Новгород" Else
Worksheets(2).Cells(N + 2, 5).Value = City.Text End If
’ Запись категории в шестой столбец, места работы или учебы -» в седьмой, а примечания - в восьмой
If St.Value = True Then
Worksheets(2).Cells(N + 2, 6).Value = "студент"
Worksheets(2).Cells(N + 2, 7).Value = Place.Text + _
", курс - " + Kyrs.Text
Else
Worksheets(2).Cells(N + 2, 6).Value = "спец, c b/o"
Worksheets(2).Cells(N + 2, 7).Value = Work.Text
Worksheets(2) .Cells(N + 2, 8) .Value = Prim.Text End If
' Характеристики, определяемые флагами If Eng.Value = True Then
Объекты Microsoft Excel  69
Worksheets(2).Cells(N + 2, 9).Value = "Да"
Else
Worksheets(2).Cells(N + 2, 9).Value = "Нет"
End If
If Auto.Value = True Then
Worksheets(2).Cells(N + 2, 10).Value = "Да"
Else
Worksheets(2).Cells(N + 2, 10).Value = "Нет"
End If
If Info.Value = True Then
Worksheets(2).Cells(N + 2, 11).Value = "Да"
Else
Worksheets(2).Cells(N + 2, 11).Value = "Нет"
End If
End Sub
Теперь все процедуры готовы, и можно поработать с созданной электронной анкетой.
Понятно, что данная разработка не включает многие детали, которые в каждой практической ситуации накладывают свои требования. Однако в этой главе и не ставилась цель создать что-то универсальное. Гораздо важнее получить на рассмотренных примерах навыки, необходимые для выполнения самостоятельных разработок.
В следующей главе для того, чтобы познакомиться с конструкциями самого языка программирования, мы рассмотрим примеры, которые отличаются большей алгоритмизацией по сравнению с разработками первой и второй глав.
Для закрепления полученных сведений желательно выполнить несколько самостоятельных заданий, касающихся модификации рассмотренных примеров.
Самостоятельная работа
Задание 2.1
Внесите изменения в разработку, показанную на рис. 2.2.
На первом листе книги не предусмотрен элемент управления, позволяющий дать покупателю скидку, а также нет возможности ввода количества для выбранной позиции номенклатуры. Требуется исправить эти недостатки. В итоге первый лист книги должен принять вид, аналогичный рис. 2.14.
70
Гпава 2
Поясним требуемую новизну разработки. В текстовом окне, расположенном под надписью Скидка, вводится с клавиатуры скидка в процентах (к общей сумме заказа). При этом, по мере ввода величины скидки, итоговая сумма по заказу должна отображаться с учетом этой скидки.
Также программа должна правильно реагировать на ситуацию, когда в текстовом окне для скидки ничего нет, либо когда введенное значение не является числом. Столбец С необходимо использовать для ввода количества, чтобы в заказе можно было оформить больше одного принтера, монитора и системного блока.
Рис. 2.14. Измененный интерфейс
Задание 2.2
Внесите изменения в разработку, показанную на рис. 2.12.
Необходимо добавить на первый лист текстовое поле для ввода имени файла с фотографией заполняющего анкету. Соответственно на втором листе для этой информации следует отвести дополнительную ячейку (столбец). Кроме того, на третьем листе данной книги нужно расположить два элемента управления — "список" и "рисунок". Список должен заполняться фамилиями со второго листа, а при выделении конкретной фамилии в этом списке соответствующая фотография должна отображаться в элементе "рисунок".
Глава 3
Реализация алгоритмов
В главе 1 вы познакомились с начальными сведениями по VBA — узнали про универсальные "строительные кирпичики" для разработки интерфейса рабочих книг Microsoft Excel с использованием кнопок, списков, надписей, рисунков.
В главе 2 мы на примерах рассмотрели, как процедуры могут эффективно взаимодействовать с информацией, имеющейся на рабочих листах. При этом читатель наверняка заметил, насколько сильно отличаются книги, разработанные с применением средств VBA, от обычных, даже если в них используются макросы.
Теперь вам предлагается глава, которая является переходной между первыми двумя и последующими главами. Дело в том, что, начиная с четвертой главы, в книге рассматриваются интересные практические примеры автоматизации, которые базируются на использовании полученных вами сведений. При этом особенностью этих глав (с четвертой по шестую) является достаточная сложность программных конструкций.
Сделать этот переход более легким для читателя и позволяет данная глава. В ней рассматриваются примеры, достаточно понятные по замыслу. Вы познакомитесь с разработкой двух несложных логических игр, которые можно разработать на листе Excel. Также здесь в процессе рассмотрения приведенных примеров будут поясняться новые программные конструкции VBA.
В целом материал этой главы можно считать тренингом для следующих глав, и будет очень полезно, если читатель ее не пропустит.
Имитация передвижения шахматной фигуры
Первой рассмотрим задачу, которая заключается в разработке программы, моделирующей ходы коня на шахматной доске.
72
Гпаев 3
Сформулируем словесное описание разработки. Пользователь выбирает произвольное начальное положение шахматной фигуры, а затем программа автоматически передвигает коня по доске с условием, что дважды побывать на одной клетке фигура не может. Таким образом, маршрут коня завершается, когда нет возможности перейти с текущего поля ни на одну еще не посещенную клетку.
В качестве аналога шахматной доски выберем участок рабочего листа Excel размером восемь на восемь ячеек (рис. 3.1). Здесь необходимо подобрать ширину и высоту ячеек, внешние и внутренние границы, а также формат выводимых символов с выравниванием их по центру ячейки.
Как известно, в шахматах конь может пойти из заданного поля максимум на восемь других полей. Если фигура расположена у края доски, то число возможных ходов уменьшается.
Варианты ходов шахматного коня с произвольного поля показаны на рис. 3.1, при этом нумерация вариантов в дальнейшем будет отражаться в алгоритме маршрута именно в таком виде. Например, вариант с номером 2 связан с перемещением фигуры на две клетки вправо и на одну вверх.
Рис. 3.1. Модель шахматной доски и варианты хода коня
Сформулируем далее алгоритм выбора очередного хода. Так в цикле последовательно просматриваются возможные варианты (рис. 3.1) ходов из текущего поля. Просмотр возможных полей для хода производится последовательно,
Реализация алгоритмов
73
начиная с первого варианта. Если очередной рассматриваемый вариант хода возможен (данная клетка располагается в пределах доски, и конь на этой клетке еще не был), то производится перемещение фигуры в соответствии с этим вариантом. Если этот ход невозможен, то просматривается следующий вариант и так далее, вплоть до восьмого. Если ни один ход из текущей клетки невозможен, то перемещение фигуры на этом завершается.
Теперь нам нужно дополнить шахматную доску элементами управления, с которыми мы далее свяжем программные процедуры. На рис. 3.2 показан интерфейс нашей разработки; в правой части расположены шесть элементов управления.
Рис. 3.2. Интерфейс приложения
В правом верхнем углу на рис. 3.2 располагаются два элемента типа "текстовое окно", позволяющие задать начальное положение шахматной фигуры. Слева от них находятся соответствующие подписи (элементы "надпись").
Примечание
Традиционно принятые обозначения на шахматной доске — по горизонтали буквы (А, В, ... Н), а по вертикали цифры. Однако в разработке мы будем использовать цифры для ввода начального положения фигуры и по горизонтали, и по вертикали.
В качестве значений свойства Name элементов "текстовое окно" (задание координаты по горизонтали и по вертикали) выберем соответственно т_х и t_y.
74
Гпава 3
Пользователь будет вводить в эти элементы числа, определяющие положение шахматной фигуры на доске.
В нижней части рис. 3.2 расположены две кнопки. При нажатии первой кнопки (Начать тур) запускается основной алгоритм, реализующий передвижение фигуры по шахматной доске. Свойство Name этой кнопки установим в значение вдп.
Вторая кнопка (Name = cir) позволяет очистить шахматную доску от номеров ходов. Это связано с тем, что при совершении хода на определенное поле в эту клетку (в ячейку Excel) записывается номер хода (сначала 1, затем 2 и т. д.). А для алгоритма, реализующего передвижение фигуры, присутствие в ячейке числа говорит о том, что ход на эту клетку уже был сделан, поэтому такая ячейка не рассматривается в качестве потенциальной для очередного хода. Технически очистка доски заключается просто в очистке блока из 64 ячеек на листе Excel.
Рассмотрим программное выполнение ходов шахматной фигуры. На рис. 3.1 были показаны возможные ходы шахматного коня из выбранного поля. Эти ходы, как уже говорилось, мы будем называть вариантами. Для обозначения вариантов введем переменную к (индекс), которая может принимать целые значения от 1 до 8 (первый вариант, второй вариант и т. д.).
Текущую позицию шахматной фигуры на доске по вертикали обозначим Y, а по горизонтали х. Все 8 вариантов ходов из исходной позиции описаны в табл. 3.1. Массивы d_x и D_y определяют перемещение фигуры по горизонтали и вертикали в зависимости от индекса к.
Таблица 3.1. Варианты ходов
к	Новое значение y (вертикальная координата)	Новое значение х (горизонтальная координата)	Значение элемента массива D_y(k)	Значение элемента массива D_x(k)
1	Y - 2	X + 1	-2	1
2	Y - 1	X + 2	-1	2
3	Y + 1	X + 2	1	2
4	Y + 2	X + 1	2	1
5	Y + 2	X - 1	2	-1
б	Y + 1	X - 2	1	-2
7	Y - 1	X - 2	-1	-2	f
8	Y - 2	X - 1	-2	-1
Реализация алгоритмов
75
Например, при третьем варианте хода (к = з) к текущему значению координаты х добавляется значение элемента массива п_х(3), а к текущему значению координаты Y добавляется значение п_у (з).
Перейдем теперь к листингу 3.1, где приведена процедура, выполняемая по щелчку на кнопке Начать тур. Массивам d_x и D_y необходимо отвести место в памяти и произвести их инициализацию значениями из табл. 3.1. Эти действия и выполняются в первых четырех строках процедуры. Для инициализации здесь используется функция Array, преобразующая список элементов, разделенных запятыми, в массив значений.
Примечание
Индексация элементов массивов в VBA по умолчанию начинается с нуля, поэтому списки содержат по 9 элементов (самый первый элемент в каждом списке не используется).
Для подсчета ходов в процедуре используется переменная Nomer. В начале процедуры этой переменной присваивается значение 1, а при совершении очередного хода значение переменной Nomer увеличивается на единицу.
Начальное положение фигуры считывается из текстовых окон, после чего для преобразования текстового формата в числовой используется функция Vai. Далее в цикле выбирается потенциальный ход (определяемый значениями var_x и var_y) и проверяется возможность его выполнения. Если данный ход возможен, то изменяются координаты фигуры и начинается просмотр вариантов следующего хода. Для этого переменная к опять сбрасывается в единицу. Используемое в процедуре условие окончания цикла
Loop While k < 9
позволяет завершить алгоритм перемещения фигуры, если ни один из восьми вариантов возможного хода не подходит. Из этого следует, что маршрут шахматного коня завершен.
I Листинг 3.1. Процедура, выполняемая по щелчку на кнопке Начать тур
Private Sub Bgn_Click()
Dim D_x As Variant
Dim D_y As Variant
D_x = ArrayfO, 1, 2, 2, 1, -1, -2, -2, -1)
D_y = ArrayfO, -2, -1, 1, 2, 2, 1, -1, -2)
Nomer = 1	' Эта переменная представляет счетчик ходов
X = Vai(T_X.Text) ' Считывание начального положения Y = Vai(T_Y.Text) ' шахматной фигуры
7»
Гпава 3
Cells(Y, X).Value = Nomer ' В ячейку листа записывается номер хода k = 1 ' Начинаем просмотр с первого варианта Do ' Цикл до строки Loop по количеству вариантов ходов
Var_x = X + D_x(k) 1 Горизонтальная координата потенциального хода Var_y = Y + D_y(k) ' Вертикальная координата потенциального хода • Проверка местоположения клетки потенциального хода If Var_x < 1 Or Var_x > 8 Or Var_y < 1 Or Var_y > 8 Then ' Если выход за пределы доски, то переход к следующему варианту k = k + 1
Elself Cells(Var_y, Var_x) <> "" Then ' Если поле занято, то также к = к + 1	1 переход к следующему варианту
Else ' Выполнение хода, если поле свободно для хода
X = Var_x
Y = Var_y
Nomer = Nomer + 1
Cells(Y, X).Value = Nomer
к = 1 * Для следующего хода начинаем просмотр вариантов с первого End If
Loop While к < 9 ’ Завершение цикла Do (ходов больше нет) End Sub
Программный код, выполняемый по щелчку на кнопке Очистить доску (листинг 3.2), достаточно прост.
| Листинг 3.2. Процедура, выполняемая при щелчке на кнопке Очистить доску
Private Sub Clr_Click()
Range("al:h8").Value = ""
End Sub
На этом описание алгоритма и технических действий по его реализации можно считать завершенными. Теперь вы можете поработать с созданным листом. На рис. 3.3 показан один из возможных маршрутов коня.
Попробуем теперь несколько изменить выполненную разработку. А именно: в созданной процедуре при щелчке на кнопке Начать тур все ходы выполнялись от начальной клетки до конечной (с которой уже нет ходов) практически мгновенно. Теперь реализуем управление очередным ходом со стороны пользователя. В качестве первого шага добавим кнопку Очередной ход Дее свойство Name установим в значение Nxt). В этом случае основной алгоритм
Реализация алгоритмов
77
перед следующим ходом должен ожидать щелчка на данной кнопке. Чтобы реализовать эту возможность, введем в общей области новую переменную flag (рис. 3.4).
Рис. 3.3. Пример маршрута шахматного коня
. Рис. 3.4. Новая переменная
Значение этой переменной будет являться индикатором нажатия кнопки Очередной ход. При совершении очередного хода переменная flag сбрасывается в 0, дальнейшее продолжение перемещения фигуры возможно, только если она примет значение 1. А в значение 1 переменная flag устанавливается только в процедуре обработки щелчка на кнопке Очередной ход. Текст измененной с учетом кнопки Очередной ход процедуры приведен в листинге 3.3.
7$________________________________________________________________Гпава 3
! Листинг 3.3. Измененная процедуре для кнопки Начать тур	|
Private Sub Bgn_Click()
Dim D_x As Variant
Dim D_y As Variant
D_x = Array(0, 1, 2, 2, 1, -1, -2, -2, -1)
D_y = Array(O, -2, -1, 1, 2, 2, 1, -1, -2)
Nomer = 1	' Эта переменная представляет счетчик ходов
X = Vai(Т_Х.Text) ' Считывание начального положения
Y = Vai(T_Y.Text) ' шахматной фигуры
Cells(Y, X) = Nomer ' В ячейку листа записывается номер хода
k = 1 ' Начинаем просмотр с первого варианта
Do ' Цикл до строки Loop - это цикл по количеству вариантов ходов Var_x = X + D_x(k) 1 Горизонтальная координата потенциального хода Var_y = Y + D_y(k) ' Вертикальная координата потенциального хода ' Проверка местоположения клетки потенциального хода If Var_x < 1 Or Var_x > 8 Or Var_y < 1 Or Var_y > 8 Then
* Если выход за пределы доски, то переход к следующему варианту к = к + 1
Elself Cells(Var_y, Var_x) о "" Then ' Если поле занято, то также к в к + 1 1 переход к следующему варианту
Else ‘ Выполнение хода, если поле свободно для хода
X = Var_x
Y = Var_y
Nomer, =. Nomer + 1
Cells(Y, X) = Nomer
к = 1 ' Для следующего хода начинаем просмотр вариантов с первого flag = О
While flag = О DoEvents
Wend
End If
Loop While к < 9 ' Завершение цикла Do (ходов больше нет).
End Sub
Процедура, выполняемая при щелчке на кнопке Очередной ход, приводится в листинге 3.4, а на рис. 3.5 проиллюстрирована работа программы. ♦
Реализация алгоритмов
79
Листинг 3.4. Процедура, выполняемая на кнопке Очередной ход
Private Sub Nxt_Click() flag = 1
End Sub
Рис. 3.5. Новый интерфейс и пример маршрута коня
Пример разработки игровой программы
Перейдем к следующему примеру. Попробуем разработать на листе Microsoft Excel программный вариант игры, известной под названием "Нимбы". В эту игру играют вдвоем. Поле для игры представляет собой прямоугольную область, разделенную на клетки (для определенности будем считать его квадратом 5x5).
Правила игры таковы. Каждому игроку предоставляется для совершения хода одно из двух определенных направлений (вертикальное или горизонтальное), ходы они делают поочередно (один игрок всегда ходит только по горизонтали, а другой — только по вертикали). Переходить можно только в пустую (незанятую) клетку. При этом игрок, кроме клетки, которую он занял сам, автоматически захватывает и все свободные соседние клетки в этой линии. "Горизонтальный" игрок, начиная игру, своим ходом занимает целую строку.
60	Гпава 3
"вертикальный” игрок после хода в свободное поле аналогичным образом занимает клетки столбца (незанятую клетку и все свободные соседние клетки в этом столбце). Игра заканчивается, когда одному из игроков не остается свободной клетки для очередного хода, что означает проигрыш.
На рис. 3.6 показан интерфейс, который нам понадобится создать в новой книге. Диапазон А1:Е5 — это просто ячейки с установленными границами.
Рис. Э.6. Интерфейс для игры в "Нимбы"
Здесь на листе размещены два элемента управления "полоса прокрутки". Свойство Name горизонтальной полосы прокрутки установим в значение L_Gor. Аналогичное свойство вертикальной полосы установим в значение L_Ver.
Зададим у обеих созданных полос прокрутки свойства мах = 5 и Min » 1, а сами полосы разместим так, чтобы положение (одно из пяти) движка соответствовало координате клетки игрового поля. В этом случае с помощью движков полос прокрутки можно выбрать клетку, в которую мы будем производить очередной ход. Точнее, перед совершением хода мы устанавливаем с помощью полос прокрутки координаты поля, с которого будет начинаться ход. *
Реализация алгоритмов
81
Кроме того, на листе нужно расположить три кнопки. Две из них связаны с совершением хода, а одна будет использоваться для очистки игрового поля в начале следующей партии. В дальнейшем клетки, которые занимаются очередным ходом, будут отмечаться определенным фоновым цветом. Используемые далее в программном коде имена командных кнопок приведены в табл. 3.2.
	Таблица 3.2. Значения свойств кнопок для игры "Нимбы"
Name	Caption
C_Gor	Ход игрока по горизонтали
C_Ver	Ход игрока по вертикали
Clr	Очистить поле игры
Как уже говорилось, игроки должны выполнять ходы поочередно, поэтому удобнее организовать программное управление последовательностью ходов. Будем для определенности считать, что первый ход игры всегда делает горизонтальный игрок. Поэтому свойство Enabled объекта c_ver установим в значение False, а аналогичное свойство объекта c_Gor — в значение True. В дальнейшем при совершении хода мы будем изменять значение свойств Enabled этих кнопок. Так, при совершении хода "горизонтальным" игроком мы будем программно производить переключение доступа к кнопкам — разрешать ход по вертикали и соответственно запрещать по горизонтали.
После такого вступительного комментария можно привести процедуру, выполняемую по щелчку на кнопке с именем c_Gor (листинг 3.5).
| Листинг 3.5. Обработка щелчка на кнопке Ход игрока по горизонтали
Private Sub CjGor_Click()
х = L_Gor. Value
у = L_Ver.Value
1 Выделяем ячейку, к которой подведен движок полосы прокрутки
Cells(у, х).Select
' При совершении хода в данной ячейке устанавливается заливка
' с кодом цвета 5
If Selection.Interior.Colorlndex = 5 Then
' Если в данное поле уже был сделан ход (заливка уже установлена)
MsgBox ("Ход невозможен")
Else ' Если поле пустое, то устанавливаем цвет заливки ячейки
Гпава 3
82
Selection. Interior .Colorindex =• 5 For I = x + 1 To 5 ' Заливка ячеек, расположенных справа от выбранной Cells(у, I).Select If Selection.Interior.Colorindex = 5 Then Exit For End If Selection.Interior.ColorIndex = 5 Next ' Заливка ячеек слева от выбранной For I = х - 1 То 1 Step -1 Cells(у, I).Select If Selection.Interior.Colorindex = 5 Then Exit For End If Selection.Interior.Colorindex = 5 Next ’ Переключение доступа к кнопкам C_Ver.Enabled = True C_Gor.Enabled = False End If End Sub
В тексте листинга 3.5 присутствуют несколько новых моментов, которые следует пояснить. Так, в строке Cells(у, х).Select используется метод select объекта cells, предназначенный для выделения ячеек указанного диапазона. В данном случае выделяется ячейка с координатами, определяемыми положением движков на полосах прокрутки. Выполнение указанного метода приводит к созданию объекта selection, который по-другому можно назвать просто выделением.
Далее в тексте листинга с помощью конструкции Selection.Interior.Colorindex
проверяется (и изменяется) цвет фона выбранной (выделенной) ячейки. При этом для отметки о совершенном ходе в текущей клетке используется кдд цвета 5.
Похожая процедура, выполняемая по щелчку на кнопке c_ver (для вертикального игрока), приведена в листинге 3.6.
Реализация алгоритмов
83
Листинг 3.6. Обработка щелчка на кнопке Ход игрока по вертикали
Private Sub C_Ver_Click()
х = L_Gor.Value
у = L_Ver.Value
' Выделяем ячейку, к которой подведен движок полосы прокрутки
Cells(у, х).Select
' При совершении хода в ячейке устанавливается заливка
' с кодом цвета 5
If Selection.Interior.Colorindex = 5 Then
MsgBox ("Ход невозможен")
Else
'Устанавливаем цвет заливки ячейки
Selection.Interior.Colorindex = 5
'Заливка ячеек ниже выбранной
For I = у + 1 То 5
Cells(I, х).Select
If Selection.Interior.ColorIndex = 5 Then
Exit For
End If
Selection.Interior.ColorIndex = 5
Next
'Заливка ячеек выше выбранной
For I = у - 1 То 1 Step -1
Cells(I, x).Select
If Selection.Interior.ColorIndex = 5 Then
Exit For
End If
Selection.Interior.ColorIndex = 5
Next
C_Ver.Enabled = False
C_Gor.Enabled = True .
End If
End Sub
Теперь осталось рассмотреть процедуру (листинг 3.7), выполняемую по щелчку на кнопке Очистить поле игры. Здесь используется метод select объекта Range. Затем с помощью созданного при этом объекта selection устанавливается белый цвет фона всего игрового поля.
84 Гпава 3
| Листинг 3.7. Обработка щелчка на кнопке Очистить поле иеры
Private Sub Clr_Click()
' Выделение диапазона, включающего все игровое поле Range("Al:Е5").Select
* Установка фона для выделенного диапазона Selection.Interior.ColorIndex = О
Range("Fl").Select
' Установка начального доступа к кнопкам
C_Ver.Enabled = False
C_Gor.Enabled = True
End Sub
Итак, разработка готова, и вы можете поиграть (пример положения в начале игры показан на рис. 3.7).
Рис. 3.7. Сделаны первые ходы
Реализация алгоритмов
85
Игра на матрице
Разработаем еще одну игру — так называемую "Игру на матрице". Игра происходит на поле размером NxN клеток. Два игрока, условно называемых "нечетный" и "четный", ставят единицы и нули в свободные позиции (клетки) поля. Каждый из игроков может ставить 1 или 0 в произвольную свободную клетку, тем самым занимая ее. Игра продолжается до заполнения всех клеток на поле.
После этого отдельно суммируются числа вдоль каждой строки, каждого столбца и вдоль двух главных диагоналей. Например, если взять игровое поле размером 5x5, то сумм всего 12 (5 по строкам, 5 по столбцам и 2 по диагоналям). Если число нечетных сумм больше числа четных сумм, то выигрывает "нечетный", а если наоборот, то "четный". Интерфейс игры показан на рис. 3.8.
Рис. 3.8. Интерфейс "Игры на матрице"
На листе располагаются четыре элемента "надпись" и один элемент "кнопка". Две крайние левые надписи содержат поясняющий текст для других надписей, расположенных правее, а две крайние правые надписи предназначены для отображения количества четных и нечетных сумм.

Гпава 3
Свойства Name левых надписей в разработке не задействованы, а для правых установим значения этих свойств следующим образом:
□ ы — надпись "Количество четных сумм";
□ L2 — надпись "Количество нечетных сумм".
Свойство Name кнопки Начать игру установим в значение вид. По щелчку на данной кнопке во все ячейки игрового поля заносятся нули (см. рис. 3.8).
Для игрового поля выберем размер 5x5. В листинге 3.8 приведен текст процедуры, выполняющей данную инициализацию.
Листинг 3.8. Обработка щелчка на кнопке Начать игру
Private Sub BgnjClickO
’ Сброс результатов
LI.Caption = ""
L2.Caption = ""
Range("al:e5").Select
’ Занесение в ячейки нулей
Selection. Value = 0
' Установка фоновой заливки ячеек
Selection.Interior.ColorIndex = 7
' Снятие выделения с игрового поля
Cells(7, 7).Select
End Sub
Технически ходы игроков выполняются следующим образом. Двойной щелчок на ячейке игрового поля изменяет ее значение: если в ячейке был записан О, то после двойного щелчка в ней оказывается 1; повторный двойной щелчок на ячейке возвращает в нее 0.
Реакцию на двойной щелчок на листе обрабатывает процедура worksheet^ BeforeDoubleclick. Для того чтобы перейти к ней, нужно в редакторе кода В списке объектов выбрать Worksheet, а В правом списке BeforeDoubleClick. В листинге 3.9 приводится текст этой процедуры.
Листинг 3.9. Процедура выполнения хода
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range,
Cancel As Boolean)
1 Выделение массива для подсчета сумм
Dim sym(12) As Integer
Реализация алгоритмов
87
Смена значения в ячейке, на которой произведен двойной щелчок If ActiveCell.Value = 0 Then ActiveCell.Value = 1
Else ActiveCell.Value = 0 End If
Установка цвета в ячейке, на которой произведен двойной щелчок ActiveCell.Select Selection.Interior.ColorIndex = 5 Вычисление сумм по строкам For I = 1 То 5 sym (I) =0 For J = 1 To 5 sym(I) = sym(I) + Cellsfl, J).Value Next
Next
Вычисление сумм по столбцам
For I = 1 То 5
sym (I + 5) = 0
For J = 1 To 5
sym(I + 5) = sym(I + 5) + Cells(J, I).Value Next
Next
Вычисление сумм по диагоналям sym (11) = 0 For I = 1 То 5
sym(ll) = sym(ll) + Cells(I, I).Value Next sym (12) = 0 For I = 1 To 5
sym(12) = sym(12) + Cells(6 - I, I).Value Next Подсчет четных и нечетных сумм к = 0 v = 0 For I = 1 То 12
If (sym(I) Mod 2) = 0 Then к = к + 1
Else

Гпава 3
End if
Next
LI.Caption = Str(k)
L2.Caption = Str(v)
Cells(7, 7).Activate
End Sub
Теперь разработка готова, и вы можете ее испытать (рис. 3.9). Следующим правильным шагом будет выполнение самостоятельных заданий, приведенных в конце главы.
Рис. 3.9. Пример результата игры
Самостоятельная работа
Задание 3.1
Измените алгоритм перемещения шахматного коня с учетом приоритетности движения к центру доски: при выборе возможного хода в первую очередь должны рассматриваться варианты движения к центру доски, а не к краю.
Реализация алгоритмов
89
Задание 3.2
Улучшите разработку, интерфейс которой показан на рис. 3.6. А именно требуется обеспечить протоколирование сделанных ходов. Интерфейс в этом случае должен выглядеть аналогично показанному на рис. 3.10. Здесь в правой нижней части расположен элемент "текстовое окно", в котором при совершении очередного хода автоматически выводится такая информация: номер хода, совершивший его игрок и ячейки, заполненные в результате хода.
Рис. 3.10. Вывод информации о сделанном ходе
Задание 3.3
Измените разработку "Игра на матрице" таким образом, чтобы двойной щелчок для ввода 1 или 0 в ячейке срабатывал не более двух раз (чтобы можно было установить 1 первым двойным щелчком и 0 вторым двойным щелчком). В ранее созданной разработке мы двойным щелчком могли изменять значение ячейки неограниченное число раз.
Глава 4
Пример обработки отчетов из программы 1С:Предприятие в книге Excel
В настоящее время в нашей стране применяется несколько популярных программных продуктов для офисных работ, например, приложения Microsoft Word и Microsoft Excel, а также программный комплекс 1С:Предприятие. Часто одни сотрудники организации работают с программой 1С:Предприятие, а другие хранят и обрабатывают данные в более простом приложении Microsoft Excel. В подобном случае обычно требуется передавать информацию между этими приложениями.
В этой главе мы рассмотрим обработку отчета, сформированного при работе с конфигурацией "Бухгалтерский учет" для системы 1С:Предприятие. Сама обработка будет реализована средствами VBA с использованием программирования рабочей книги Microsoft Excel. Однако перед описанием конкретных действий разумно познакомить читателя с системой 1 С:Предприятие и, конечно, дать некоторые пояснения по отчету, который мы будем передавать в Microsoft Excel.
Представление об организации программного комплекса 1С:Предприятие
Основной характерной чертой системы 1 С:Предприятие является возможность ее конфигурирования для каждого варианта использования (программу можно настроить "для себя"). И работа с системой 1 С:Предприятие подразумевает два процесса — конфигурирование (создание варианта использования программы) и собственно работа с программой 1С:Предприятие.
На этапе конфигурирования можно создать структуру необходимых справочников, документов, отчетов, журналов и многое другое. Также на этапе
Гпава 4
92
конфигурирования можно задать алгоритмы обработки информации для этих объектов. А уже в процессе работы мы заполняем данными справочники, создаем электронные документы по шаблону, разработанному в конфигураторе, формируем отчеты по определенным ранее алгоритмам и др.
В настоящее время разработано много готовых конфигураций для разных областей применения. И одной из наиболее популярных является конфигурация "Бухгалтерский учет", которая позволяет работать с бухгалтерскими счетами, операциями и проводками. Система 1 С:Предприятие представляет собой совокупность объектов, аналогичных объектам VBA, которые мы и рассмотрим далее.
Наиболее простые объекты — это константы, предназначенные для работы с постоянной или временно постоянной информацией. На этапе конфигурирования (в программе Конфигуратор) задается список констант и описываются их характеристики. Само значение той или иной константы задается уже в процессе работы с программой 1С:Предприятие.
Более часто используемые объекты — справочники. Как правило, в той или иной задаче встречаются различные списки (материалов, товаров или организаций). Для работы с такими списками и предназначены справочники.
Еще один вид объектов — это перечисления, которые служат для описания постоянных наборов значений, неизменных для конкретной конфигурации. В отличие от справочников, значения перечислений не могут быть изменены в процессе работы в программе 1С:Предприятие. В качестве примера перечисления можно привести "Вид оплаты" (например, для организации может существовать только три варианта — наличные, безналичные, бартер).
Наиболее широко используются документы, предназначенные для хранения информации о событиях на предприятии (их можно считать аналогами реальных документов).
Объектом, который используется в нашей работе, является отчет Карточка счета. Для получения этого отчета следует в программе 1С:Предприятие 7.7 (конфигурация "Бухгалтерский учет") в меню Отчеты (рис. 4.1) выбрать пункт Карточка счета.
После этого перед нами открывается экранная форма ввода (рис. 4.2), где можно задать параметры отчета, который мы намереваемся сформировать.
В верхней части формы нужно определить период, за который нам требуется получить отчет.
Далее следует установить номер бухгалтерского счета (поле Счет). Это новое понятие для тех, кто совсем не знаком с бухгалтерией, и я его поясню..
Пример обработки отчетов из программы 1С:Предприятие в книге Excel
93
Рис. 4.1. Меню программы 1С:Предприятие 7.7, конфигурация "Бухгалтерский учет"
Рис. 4.2. Форма для ввода параметров отчета
Понятно, что в любой организации требуется учитывать денежные и материальные средства не в совокупности, а по разным категориям. Так, в организациях есть расчетный счет в банке, касса для работы с наличной денежной массой, склад и т. д. И для каждой подобной категории есть свой счет — некий регистр, или место хранения информации. У каждого счета есть дебетовая и кредитовая части. Когда на определенный счет поступает сумма, это
94
Гпава 4
приводит к увеличению дебетовой части Счета (на эту сумму). И наоборот, когда со счета нужно перевести часть средств, это приводит к увеличению кредитовой части счета (также на сумму перевода). Таким образом, все поступления на счет увеличивают дебет счета, а отчисления со счета увеличивают кредит счета.
В окне Карточка счета после определения интервала по дате нужно выбрать конкретный бухгалтерский счет, который нас интересует (по которому мы будем формировать отчет).
Следующие параметры, которые надо указать в данном отчете, — Вид субконто и Субконто. Рассмотрим эти понятия на простом примере.
Понятно, что учитывать на счете всю совокупность (товаров или денег) в виде единой суммы не очень интересно. Даже при небольшой номенклатуре товаров (например джинсы, рубашка и брюки) хотелось бы учитывать отдельно, на какую сумму на складе имеется джинсов, на какую — рубашек, а на какую — брюк.
Параметр счета Вид субконто позволяет хранить (и. получать) не всю информацию целиком, а по отдельным категориям. Например, на рис. 4.3 в поле Вид субконто! указано значение Номенклатура. Следующее поле в форме — субконто1, там уже можно указать конкретное значение — Пальто имп. мужское. В этом случае мы получим информацию в отчете по конкретной позиции номенклатуры.
Рис. 4.3. Пример задания параметров счета
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 95
В конфигурации "Бухгалтерский учет" на каждом счете можно задать для ведения учета до трех различных видов субконто.
После открытия формы отчета Карточка счета (см. рис. 4.2) следует установить нужные значения параметров, а затем нажать кнопку Сформировать. После этого в программе 1 С:Предприятие откроется табличная форма сформированного отчета, которую можно сохранить в формате таблицы Microsoft Excel. Для этого в меню Файл следует выбрать пункт Сохранить как и далее указать необходимый тип файла (рис. 4.4). Далее подобный отчет будет анализироваться с помощью средств VBA в Microsoft Excel, поэтому в качестве типа файла надо указать Таблица Excel (*.xls).
Рис. 4.4. Сохранение отчета в формате таблицы Microsoft Excel
После такой вводной информации можно перейти к рассмотрению практической задачи, которая встретилась в одном из высших учебных заведений. Она связана с учетом внесения учащимися платы за обучение. Данная задача может быть весьма актуальной для организаций, где требуется учитывать денежные поступления от учащихся либо слушателей. Понятно, что здесь речь идет о коммерческом, а не бюджетном обучении.
Примечание
Даже если решаемые вами задачи автоматизации офисной работы далеки от темы этой главы, все же рекомендую подробно рассмотреть используемые здесь программные конструкции. Независимо от области применения, в алгоритмах обработки данных есть много общего. Познакомившись с примерами этой и последующих глав, вы сможете самостоятельно решать свои конкретные задачи.
96
Гпава 4
Итак, рассмотрим пример. Задача учета оплаты требует некоторой автоматизации, даже при небольшом количестве учащихся (слушателей).
В данном случае факт внесения очередной суммы за обучение фиксируется в бухгалтерии, где учет ведется с помощью программы 1 С:Предприятие (конфигурация "Бухгалтерский учет"). А именно в журнал операций заносится новая операция об оплате.
У деканата факультета, к которому относятся студенты, нет непосредственного доступа к компьютерной сети бухгалтерии. Такая практика наблюдается в большинстве организаций — бухгалтерские компьютеры стараются оградить от возможных контактов с другими компьютерами. Однако учет сведений по оплате в деканате необходим, и, естественно, желательно организовать его наиболее эффективным образом. Будем считать, что учет в деканате ведется в приложении Microsoft Excel.
Примечание
Такая ситуация может быть связана не только с оплатой за обучение. Например, часто требуется обработать информацию из отчетов 1С. При этом большинство руководителей и менеджеров, как показывает статистика, в основном работают с приложением Microsoft Excel. Фактически, подробное изучение данной главы поможет читателю построить автоматизированную книгу для своей задачи.
В рассматриваемой задаче в книгу Microsoft Excel периодически (по мере внесения плат) добавляются новые рабочие листы с отчетами (Карточка счета) из программы 1С:Предприятие. И уже в книге информация об оплате программно извлекается и представляется в наиболее удобном для пользователя (например, декана) виде.
Таким образом, рабочая книга по структуре представляет собой несколько управляющих листов и несколько листов с данными. В нашем примере используются два управляющих листа, выполняющих все основные функции.
Примечание
В реальной рабочей книге, предназначенной для обработки отчетов, имеется еще несколько элементов управления, однако их функции второстепенны и поэтому здесь не рассматриваются.
Прокомментируем этапы работы, связанные с учетом оплат, в хронологическом порядке.
Сотрудники бухгалтерии периодически (каждый месяц) сохраняют в формате Excel отчет Карточка счета о внесении студентами платы за обучение (рис. 4.5) и передают его в деканат.
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 97
Как видно из отчета, фамилии (с инициалами) располагаются на листе в столбце С, а сумма очередной внесенной платы конкретным студентом — в столбце G. Заметим также, что строки с информацией об оплатах начинаются с десятой. Эта информация будет использоваться в последующих процедурах. Подобная структура представления информации является общей для всех отчетов об оплатах, получаемых из бухгалтерии, на этом и будут строиться алгоритмы обработки.
. Рис. 4.5. Пример отчета
Небольшая техническая трудность заключается в том, что в столбце С отчета кроме фамилии и инициалов присутствует дополнительная (не представляющая интереса при учете оплаты) информация. Поэтому в дальнейшем мы будем программно извлекать из этого столбца только фамилию с инициалами — информацию, присутствующую в начале содержимого каждой ячейки третьего столбца на листе данных.
98
Гпава 4
Основной лист книги
Рассмотрим структуру рабочей книги в целом. Листы, подобные показанному на рис. 4.5, добавляются в книгу, начиная с третьего. Названия этих листов — Данные1, Данные! и т. д. В книгу периодически добавляются новые листы с подобной структурой. Два начальных листа книги (Основной и Индексация) являются управляющими (на рис. 4.6 показан первый из этих листов).
Рис. 4.6. Управляющий лист Основной
Рассмотрим сначала, что расположено на листе и как он организован, а затем перейдем к более формальному разбору программных конструкций. Прямоугольная область, начиная с ячейки Е2 (левый верхний угол прямоугольника), служит для формирования итоговой информации на основе листов данных, которые в книге начинаются с третьего.
При добавлении в книгу очередного листа (или нескольких листов) данных требуется пересчитать итоговые суммы. При этом по щелчку на кнопке Вычислить эта прямоугольная область (белая на рис. 4.6) сначала очищается. В нашем случае удаляется информация из столбцов Фамилия, Итог, Сумма и Дата.
Далее начинается формирование на листе итоговой информации. Сначала заполняется столбец Е фамилиями студентов из листов с информацией об
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 99
оплате (Данные1, Данные! и т. д.). Если фамилия (с инициалами) встречается больше одного раза, то в столбце Е она должна появиться только один раз, что мы далее и реализуем программно.
Затем для каждого студента подсчитывается итоговая сумма оплаты по информации с листов данных и размещается в столбце F рядом с его фамилией. В следующих столбцах перечисляются все произведенные данным студентом оплаты. Формат при выводе внесенных сумм: сумма, дата ее внесения, следующая сумма и следующая дата и т. д.
Таким образом, нажатие кнопки Вычислить позволяет собрать информацию из всех отчетов по оплатам, полученным из программы 1С:Предприятие.
Процедура, выполняемая по щелчку на кнопке Вычислить, приведена в листинге 4.1. Как видно из заголовка процедуры, мы изменили значение свойства Name кнопки, данное по умолчанию, на CommandButtonl. Основные действия этой процедуры прокомментированы прямо в тексте, а некоторые далее поясняются более подробно.
I Листинг 4.1. Обработка щелчка на кнопке Вычислить
Private Sub CommandButtonl_Click()
' Объявление переменных строкового типа
Dim a As String
Dim d As String
Dim z As String
* Изменение надписи на кнопке при начале обработки данных CommandButtonl.Caption = "Подождите"
1 Подсчет количества строк с фамилиями на первом листе N = О
Do While Cells(N + 2, 5).Value <> "" N = N + 1
Loop
' Очистка заполненных ячеек оплат на первом листе For i = 2 То N + 1
3 = 5
Do While Cells(i, j).Value <> ""
Cells(i, j).Value = ""
j = J + 1
Loop
Next
Гпава 4
100
' Цикл по листам данных For i = 3 То Activeworkbook.Worksheets.Count ’ Подсчет количества строк с фамилиями на i-м листе NI = О Do While Worksheets(i).Cells(NI + 10, 3).Value <> "" NI « NI + 1
Loop
' Цикл по количеству строк на i-м листе For j = 10 То 10 + NI - 1
1 Функция, извлекающая из ячейки только фамилию с инициалами z = isv(Worksheets(i).Cells(j, 3).Value )
' Фрагмент для добавления фамилии на первый лист N = 0 Do While Cells(N + 2, 5).Value <> "" N = N + 1
Loop flag = 0 * Индикатор присутствия очередной фамилии ' с листа данных на первом листе For ii я 2 То N + 1 d = Cells(ii, 5).Value If StrComp(d, z) = 0 Then flag = 1 Exit For End If
Next
If flag = 0 Then 'Если фамилия не найдена Cells(N +2, 5).Value = z End If Next Next
* В следующем блоке производится подсчет оплат Nfam = 0 Do While Cells(Nfam +2, 5).Value <> "" Nfam = Nfam + 1 Loop ' Цикл по фамилиям студентов For i » 2 To Nfam + 1 ' В переменной d очередная фамилия d я Celled, 5) .Value
Пример обработки отчетов из программы 1 (^Предприятие в книге Excel 101
пот = 7 ’ В этой переменной организуем счетчик по столбцам sym = 0 1 Переменная для подсчета суммы всех оплат студента ' Цикл по количеству листов данных
For ii = 3 То ActiveWorkbook.Worksheets.Count
' Подсчет количества фамилий на очередном листе данных N = О Do While Worksheets(ii).Cells(N + 10, 3).Value <> "" N = N + 1
Loop
'Цикл по фамилиям на очередном листе с данными For j = 10 То 10 + N - 1
а = Worksheets(ii).Cells(j, 3).Value z = isv(a) If StrComp(d, z) =0 Then 'Если фамилия найдена
If IsNUmeric(Worksheets(ii).Cells(j, 7).Value) = True Then ' Установка суммы очередной оплаты
Cells(i, non).Value = Worksheets(ii).Cells(j, 7).Value ' Установка даты очередной оплаты
Cells(i, non + 1).Value = Worksheets(ii).Cells(j, 1).Value ' Переход к следующей паре столбцов non = nom + 2
'Суммирование оплат конкретного студента
aym = sym + CLng(Worksheets(ii).Cells(j, 7).Value) End If End If Next
Next
' Запись итоговой суммы з шестой столбец
Cells(i, 6).Value = sym Next
' Подсчет в переменной N фамилий студентов N = 0
Do While Cells(N +2, 5).Value <> ""
N = N + 1
Loop
' Заполнение поля co списком фамилиями с первого листа ComboBoxl.Clear For i = 2 То N + 1
d = Worksheets(1) .Celled, 5) .Value
Гпава 4
102
ComboBoxl.Addltem d
Next
' Завершение обработки и смена надписи на кнопке CommandButtonl.Caption = "Вычислить"
End Sub
Теперь рассмотрим конструкции, приведенные в листинге 4.1.
В начале процедуры для трех переменных (a, d, z) указывается строковый тип данных. В дальнейшем мы будем использовать функцию сравнения строк, а по умолчанию без такого описания для переменной строковый тип данных не задается.
При большом объеме информации (много листов данных) процесс вычисления может быть достаточно длительным, и желательно сообщить пользователю о том, что программа не "зависла", а работает. В данном случае предложен следующий вариант. После щелчка на рассматриваемой кнопке текст на ней заменяется на "Подождите", а при завершении процедуры возвращается к первоначальному ("Вычислить").
Теперь нужно очистить первый лист от старой информации, связанной с оплатами. Для этого сначала с помощью уже встречавшегося аналогичного фрагмента в переменной n подсчитывается количество фамилий в столбце Е. Индикатором окончания перечня фамилий является пустая ячейка (без фамилии).
Поскольку у разных студентов различное количество произведенных оплат за обучение, соответственно, и количество заполненных столбцов справа от фамилии для разных студентов будет отличаться. В следующем фрагменте с помощью двух вложенных циклов производится очистка имеющейся информации об оплатах:
For i = 2 То N + 1
j = 5
Do While Cellsfi, j).Value <> ""
Cells(i, j).Value = ""
j = j + 1
Loop
Next
В начале цикла по строкам в переменную j записывается значение 5, поскольку фрагмент фамилий и оплат начинается с пятого столбца.
Примечание
Когда в переменную записывается значение, программисты говорят "переменной присваивается значение".	t
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 103
Далее в процедуре начинается цикл по листам с данными. Как уже говорилось, данные располагаются, начиная с третьего листа, а общее количество листов определяется с помощью свойства count коллекции worksheets. Здесь же, в операторе цикла For используется объект Activewcrkbook, который представляет собой активную книгу Microsoft Excel. В результате обрабатывается столько листов данных, сколько есть в книге.
Далее после подсчета количества строк на очередном листе данных организуется цикл по этим строкам. В первой строке этого цикла
z = isv(Worksheets(i).Cells(j, 3).Value )
последовательно извлекается содержимое ячеек третьего столбца с листов данных. При этом с помощью функции isv мы извлекаем из полученной информации только фамилию с инициалами. Текст этой несложной функции приведен в листинге 4.2.
Листинг 4.2. Функция isv
Public Function isv(stroke As String) As String
fam = "" ' Переменная для выделения фамилии с инициалами
j = 1 ' Счетчик символов в исходной строке
Do
с = Mid(stroka, j, 1) ' Извлечение очередного символа If с о * " Then
fam = fam + с
Else
* После появления пробела считываем еще инициалы fam = fam + с
с = Mid(stroka, j + 1, 1)
fam = fam + с
с = Mid(stroka, j + 2, 1)
fam = fam + c
Exit Do
End If
j = j + 1
Loop While j <= Len(stroka)
isv = fam
End Function
В качестве типа данных для входного и выходного параметров функции указана строка. При этом входной параметр — это строка с фамилией, инициа
104
Гпаев 4
лами и некоторой лишней информацией, содержащейся в ячейке отчета Карточка счета. В результате работы функция выдает в качестве свбего значения только фамилию с инициалами.
Наверное, стоит добавить небольшой комментарий к тексту листинга 4.2. Переменная j используется как счетчик символов исходной строки (строки, где присутствует фамилия с инициалами). Переменная fam вводится для формирования строки, которая содержит только фамилию и инициалы. После этого из исходной строки в цикле извлекается символ за символом до тех пор, пока не встретится пробел. После пробела мы извлекаем еще два символа (инициалы), и функция возвращает результат в исходную программу.
В листинге 4.2 присутствуют две стандартные функции VBA Len и Mid. Первая функция проще— она просто подсчитывает количество символов в строке, заданной в качестве входного параметра. Вторая функция позволяет извлечь фрагмент исходной строки. Первый параметр функции Mid — сама исходная строка, второй — номер позиции символа в исходной строке, начиная с которого мы собираемся извлекать фрагмент, третий— количество символов в извлекаемом фрагменте. Так, в команде
с = Midfstroka, j, 1)
в переменную с записывается j-й по счету символ исходной строки.
Теперь, после того как мы извлекли фамилию (с инициалами) из листа данных, необходимо добавить эту информацию на первый лист, но при условии, что ее там еще нет. Для этого вводится переменная flag — флаг для индикации присутствия фамилии, и ей присваивается значение 0. В следующем цикле, если фамилия студента уже присутствует на первом листе, эта переменная устанавливается в 1. При этом используется стандартная функция strComp, которая сравнивает входные строки и возвращает 0, если они одинаковы. В этом случае мы устанавливаем flag = 1. В дальнейшем при отсутствии очередной фамилии на первом листе, она добавляется на этот лист:
If flag = 0 Then 'Если фамилия не найдена
Cells(N +2, 5).Value = z
End If
Далее в процедуре из листинга 4.1 заносится информация о сделанных оплатах. Переменная sym используется для подсчета суммарной оплаты отдельного студента, а переменная пот позволяет переходить от столбца к столбцу для внесения информации об оплате и дате оплаты. При нахождении рассматриваемой фамилии в листах с данными в строке
If IsNumeric(Worksheets(ii).Cells(j, 7).Value) = True Then предварительно проверяется — является ли информация в седьмом столбце числом. Если это так, то выполняются следующие действия с информацией
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 105
о сумме. Сначала считанная сумма записывается в очередной столбец на первом листе:
Cells(i, nom) .Value = Worksheets(ii).Cells(j, 7) .Value
Затем в следующий столбец записывается дата внесения этой суммы После этого мы переходим к следующей паре (для очередного прохождения цикла) столбцов на первом листе:
пот = пот + 2
Для формирования суммарной оплаты в столбце Итоги (см. рис. 4.6) используется переменная sym, в которой складываются все оплаты конкретного студента:
sym = sym + CLng(Worksheets(ii).Cells(j, 7).Value)
Перед тем, как перейти к последнему фрагменту, небольшое пояснение по интерфейсу на рис. 4.6. На этом рисунке присутствует элемент "поле со списком". Свойство Name этого элемента мы оставим в значении comboBoxi (как установлено по умолчанию).
Примечание
На рис. 4.6 элемент "поле со списком" расположен под надписью Поиск строки.
Понятно, что количество обучающихся студентов может быть очень большим, и часто прокручивать весь рабочий лист для поиска нужной фамилии не очень удобно. Поэтому в программе реализуется следующий сервис. Раскрывающийся список поля заполняется фамилиями всех студентов (это выполняется в заключительной части процедуры из листинга 4.1). Если даже элементов в списке много, то прокручивать его удобнее, чем рабочий лист. Цель процедуры, выполняемой по щелчку на элементе списка,— сделать так, чтобы активизировалась строка рабочего листа с интересующей нас фамилией. Для пользователя это проявляется следующим образом. Если строка с интересующей нас фамилией находится в конце листа (и не видна на экране), при выборе данной фамилии в списке рабочий лист автоматически прокручивается на экране до нужной строки.
Теперь изучим, как это достигается технически. Для этого рассмотрим процедуру, выполняемую по щелчку на элементе "поле со списком" (листинг 4.3).
• ............
I Листинг 4.3. Обработка щелчка на поле со списком
Private Sub ComboBoxl_Click()
N = О
Do While Cells(N + 2, 5).Value <> ""
N = N + 1
106
Гпава 4
Loop
Цикл по количеству фамилий студентов For i = 2 То N + 1
При нахождении на листе фамилии, соответствующей выбранному элементу списка
If StrConp(ConfooBoxl.Text, Cells(i, 5).Value) = 0 Then ' "Подтягивание" найденной строки на экране
Cellsfi, 4).Activate
End If
Next
End Sub
После этого можно считать, что основные действия по первому листу мы выполнили — заполнили ячейки фамилиями студентов и записали произведенные ими оплаты, а также обеспечили удобную навигацию по данным на листе с помощью элемента "поле со списком".
Поговорим еще об одной функциональной возможности, разработанной для первого листа. Из рис. 4.6 видно, что оплаты записываются в строку, и если оплат много, то для просмотра информации приходится прокручивать рабочий лист вправо. Удобнее реализовать для пользователя другую возможность просмотра сделанных оплат (рис. 4.7).
В предлагаемом варианте на листе имеется всплывающее текстовое окно, в котором выводится информация об оплатах конкретного студента. При этом изначально это окно невидимо (его свойство visible установлено в значение False). Теперь, если, например, потребуется просмотреть оплаты студента Веденеева АХ, то мы можем просто выделить ячейку с этой фамилией в столбце Е, а затем щелкнуть на кнопке Просмотр по студенту. В результате на экране появляется текстовое окно, в котором отображаются все оплаты. Даже при большом количестве оплат текстовое окно прокручивать удобнее, чем рабочий лист. Заметим только, что для реализации подобной возможности свойство MultiLine этого элемента необходимо установить в значение True.
Кроме того, мы реализуем и возможность записи оплат данного студента на первый рабочий лист по щелчку на кнопке Просмотр по студенту. На первый взгляд, эта функция дублирует действия кнопки Вычислить, однако на практике она может быть очень полезна. Если требуется посмотреть оплату по конкретному студенту, то нет смысла долго пересчитывать информа1|йю по всем студентам. В этом случае (при щелчке на кнопке Просмотр по студенту) пересчитываются оплаты только по указанному студенту. Эта ситуация
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 107
может быть связана с корректировкой одной из оплат, произведенных конкретным человеком, на листе данных. Текст процедуры, выполняемой при щелчке на кнопке Просмотр по студенту, приведен в листинге 4.4.
Рис. 4.7. Всплывающее текстовое поле
| Листинг 4.4. Обработка щелчка на кнопке Просмотр по студенту
Private Sub CommandButton2_Click()
Dim a As String
Dim z As String
' Вывод в надпись фамилии студента из выделенной (активной) ячейки Lbl. Caption = ActiveCell .Value
' В переменной s фиксируется номер строки выделенной ячейки s = ActiveCell.Row
' В переменной пот организуется счетчик столбцов пот = 7
' В переменной sym организуется подсчет суммы по всем оплатам sym = О
' Очистка всплывающего текстового окна
TextBoxl.Text = ""
' Цикл по листам данных
For i  3 To Activeworkbook.Worksheets.Count N = 0 Do While Worksheets(i).Cells(N + 10, 3).Value <> "" N = N + 1 Loop ' Цикл по строкам на листах данных For j = 10 То 10 + N - 1 a = Worksheets(i).Cells(j, 3).Value z = isv(a)
'Если интересующая фамилия найдена на листах данных If StrComp(Lbl.Caption, z) =0 Then ' Если в поле для суммы оплаты - число If IsNumeric(Worksheets(i).Cells(j, 7).Value) = True Then 'Запись информации на первый лист
Cellsts, nom) .Value = Worksheets(i).Cells(j, 7).value
Cells(s, nom + 1).Value = Worksheets(i).Cells(j; 1).Value 'Увеличение счетчика столбцов nom = nom + 2 'Подсчет суммы sym = sym + CLng(Worksheets(i).Cells(j, 7).Value) 'Вывод информации во всплывающее текстовое окно TextBoxl.Text = TextBoxl.Text + _ CStr(Worksheets(i).Cells(j, 7).Value) + "	"
TextBoxl.Text = TextBoxl.Text + _ CStr(Worksheets(i).Cells(j, 1).Value) + Chr(10) End If End If Next Next ' Вывод итоговой информации Worksheets(1).Cells(s, 6).Value = sym ' Установка видимости текстового окна TextBoxl.Visible = True End Sub
В предпоследней строке процедуры из листинга 4.4 текстовое окно с информацией об оплатах становится видимым. Когда пользователю эта информация будет не нужна, окно следует убрать с экрана. Технически это реализуется с помощью двойного щелчка (листинг 4.5).
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 109
| Листинг 4.5. Обработка двойного щелчка на всплывающем текстовом окне
Private Sub TextBoxl_DblClick(ByVal Cancel As MSForms.RetumBoolean) TextBoxl.Visible = False
End Sub
Итак, мы рассмотрели основной лист, и теперь можно сформулировать краткий итог по основным функциональным возможностям листа:
□	при щелчке на кнопке Вычислить производится автоматическое вычисление итогов по всем листам данных;
□	с помощью элемента "поле со списком" организуется быстрый поиск нужной строки на рабочем листе;
□	реализована возможность просмотра информации во всплывающем текстовом окне при большом количестве оплат.
Лист Индексация
В этом разделе мы рассмотрим сервисные возможности, заложенные во втором рабочем листе, который называется Индексация.
Нужно пояснить механизм индексации оплаты за обучение. При поступлении студента в вуз в договоре фиксируется сумма оплаты всего периода обучения. Если студент вносит всю эту сумму при поступлении, то больше никаких дополнительных расходов он уже не несет. А просрочка оплаты (если студент не внес сумму) приводит к ее индексации на полтора процента за каждый месяц.
Практически студенты вносят оплату за обучение нерегулярно и различными суммами. Скажем, в сентябре 2005 года была определена полная стоимость обучения— 60 000 руб. После поступления студент W заплатил 3000 руб. в ноябре этого года и 8000 руб. в январе следующего. В этом случае быстро ответить на вопрос о величине его задолженности на 1 июня 2006 года достаточно сложно.
Понятно, что если применять более простую (и одновременно более жесткую для учащихся) схему оплаты (за год обучения вперед и без сложной индексации), то проблема учета оплат значительно упрощается. Однако в настоящее время рынок диктует формы оплаты, с одной стороны, более удобные для студента (разбивка на суммы и отсутствие жестких временных границ), с другой, более надежные для учебных заведений в плане защиты от инфляции.
11С
Гпава 4
Во втором листе заложены возможности контроля сделанных оплат с учетом индексации. На рис. 4.8 показан второй лист книги с элементами управления и данными об оплатах. Здесь присутствуют три элемента управления — кнопка, надпись и поле со списком. На рис. 4.8 они расположены в той же последовательности сверху вниз в правой части листа. Значения свойства Name этих элементов, заданные по умолчанию, мы изменять не будем: commandButtoni — для кнопки, comboBoxi — для поля со списком (значение свойства Name надписи мы программно использовать не будем).
Рис. 4.8. Элементы управления на листе Индексация
Первые четыре столбца заполняются пользователем самостоятельно (без участия программы). Дело в том, что это достаточно статическая информация, не требующая частых изменений. В первый столбец заносится фамилия с инициалами (эту информацию можно скопировать из первого листа). Практически, если состав учащихся не изменяется достаточно долго (например, в течение года или семестра), то это действие придется выполнить только один раз.
Второй столбец относится к варианту (форме) обучения. Информация из это/ю столбца листа используется во второстепенных отчетах, которые здесь не рассматриваются.	*
Следующие два столбца очень важны — это дата зачисления учащегося (требуется для индексации) и сумма оплаты на дату зачисления.
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 111
Будем считать, что начальная информация на второй лист книги занесена. Далее на листе производится анализ внесенных сумм (расположенных на листах данных) с учетом их даты. В результате анализа мы получим информацию об оплате с учетом индексации. Столбцы Е, F и G на листе заполнятся автоматически по щелчку на кнопке Вычислить.
Мы рассмотрели необходимые действия, теперь можно перейти к программным конструкциям. В листинге 4.6 приведен текст процедуры, выполняемой по щелчку на кнопке Вычислить.
| Листинг 4.6. Обработка щелчка на кнопке Вычислить
Private Sub CorranandButtonl_Click()
Dim student As String
Dim z As String
' Массив для формирования коэффициентов индексации
Dim mass(100) Аз Single
' Смена надписи на кнопке
CommandButtonl.Caption = "Подождите"
' Вычисление коэффициентов индексации
For i = 0 То 100
mass(i) = (1 + 0.015) л i
Next
' Очистка второго листа от прежней информации
N = 0
Do While Cells(N + 2, 1).Value <> ""
N = N + 1
Loop
For i = 2 To N + 1
Cells(i, 7).Value = ""
Cells(i, 5).Value = ""
Cells(i, 6) .Value = ""
Next
For i = 2 To N + 1 ' Цикл по количеству студентов
student = Cells(i, Ij.Value
sym = 0 ' Переменная для подсчета суммы оплаты
sym2 = 0 ' Переменная для подсчета суммы с учетом индексации
' Цикл по количеству листов с данными
For ii = 3 То ActiveWorkbook.Worksheets.Count
NN = 0
Do While Worksheets(ii).Cells(NN + 10. 3).Value <> nn
Глава 4
11S
NN « NN + 1
Loop
For j = 10 To 10 + NN - 1 'Цикл по строкам a = Worksheets(ii).Cells(j, 3).Value z = isv(a) ' Если фамилия из списка на втором листе ' и фамилия с одного из листов данных совпадают If StrComp(student, z) = 0 Then
If IsNUmeric(Worksheets(ii).Cells(j, 7).Value) = True Then ' Суммирование оплат
sym = sym + CLng(Worksheets(ii).Cells(j, 7).Value) ' Вычисление количества месяцев ' между датой оплаты и датой поступления
interval = DateDiff("m", Cells(i, 3).Value, _ CDate(Worksheets(ii).Cells(j, 1).Value)) ' Вычисление суммы с учетом индексации sym^ = sym2 + _
Worksheets(ii).Cells(j, 7).Value I mass(interval) End If End If Next ' Завершение цикла по строкам Next ' Завершение цикла по листам данными
' Запись на лист сумм оплаты (без индексации и с индексацией)
Cells(i, 5).Value = sym
Cellsfi, 6).Value = sym2
' Разность между суммой за обучение и сделанной оплатой dolg = Celled, 4) .Value - Celled, 6) .Value
'Количество месяцев между текущей датой и днем зачисления interval = DateDiff ("m", Cellsd, 3) .Value, NowO) 'Долг на текущий день Cells(i, 7).Value = dolg * mass(interval) Next 'Завершение цикла по количеству студентов ' Заполнение списка фамилиями студентов ComboBoxl.Clear For i = 2 То N + 1 ComboBoxl.Additem Cells(i, 1).Value Next ' Изменение надписи на кнопке
CommandButtonl.Caption = "Вычислить" End Sub
Пример обработки отчетов из программы 1С:Предприятие в книге Excel 113
Теперь поясним некоторые конструкции листинга 4.6. В начале процедуры вычисляются значения элементов массива mass. Значение элемента массива mass(i) показывает, во сколько раз возрастает исходная сумма оплаты за обучение, если произвести ее спустя i месяцев. Например, mass(i) показывает, во сколько раз возрастает неоплаченная сумма при задержке оплаты на один месяц. Соответственно mass (2) определяет увеличение неоплаченной суммы при задержке на два месяца.
В строке
interval = DateDiff("m", Cells(i, 3).Value, _
CDate(Worksheets(ii).Cells(j, 1).Value))
вычисляется количество месяцев между датой текущей оплаты и датой поступления. После этого с помощью значения элемента массива mass (interval) можно определить, во сколько раз за этот период времени возрастает сумма.
Далее в строке
sym2 = sym2 + Worksheets(ii).Cells(j, 7).Value / mass(interval)
мы вычисляем чистую сумму оплаты, в которой учтены индексационные издержки.
После этого в столбец Е записывается оплаченная сумма без индексации (просто сколько человек всего оплатил), а в столбец F — сумма за вычетом процентов, связанных с просрочкой во времени. Разность между суммой оплаты за весь период и зачтенной оплатой (из столбца F) устанавливается в столбце G.
В результате выполненных вычислений мы можем подсчитать долг без индексации на сегодняшний день:
dolg = Cells(i, 4).Value - Cells(i, 6).Value
Для пересчета этой суммы с учетом просрочки платежа сначала подсчитывается количество месяцев между текущей датой и датой зачисления:
interval = DateDiff ("m", Cells(i, 3) .Value, NowO)
После этого в столбце G устанавливается долг на текущий день:
Cellsd, 7).Value = dolg * mass (interval)
Итак, мы рассмотрели действия, выполняемые при щелчке на кнопке Вычислить. Теперь поговорим об элементе управления "поле со списком" (см. рис. 4.8). Дело в том, что информация в столбцах Е и F носит интегральный характер — сколько всего заплачено каждым учащимся. Понятно, что начиная "разборку" — кто, сколько и когда платил, — хотелось бы получить
114
Гпава 4
детальный отчет. И процесс его получения на листе таков. Поле со списком заполняется фамилиями, присутствующими на втором листе. Это заполнение производится и по щелчку на кнопке Вычислить, и в предопределенной процедуре, выполняемой при открытии книги. Это разумно, т. к. часто при открытии книги требуется не пересчитывать лист заново, а только посмотреть оплаты конкретного студента. Тогда после открытия книги вы на листе Индексация сразу можете выбрать фамилию интересующего вас студента.
Далее, по щелчку на поле со списком выполняется процедура, которая заполняет диапазон ячеек в интервале от столбца Н до столбца К. Здесь каждая строка содержит информацию об очередной оплате. Столбцы Дата и Сумма очевидны и не требуют комментария. Столбец Номер показывает номер строки на листе данных, где зафиксирована соответствующая оплата. При этом может возникнуть резонный вопрос: а на каком, собственно, листе данных (в книге их много)? Дело в том, что на практике названия листов данных более информативны — включают название месяца и года (т. е. по дате оплаты мы сразу определяем, где искать строку с определенным номером).
В листинге 4.7 приведена процедура, выполняемая по щелчку на поле со списком.
I Листинг 4.7. Обработка щелчка на поле со списком
Private Sub ConiboBoxl_Click ()
Dim d As String
Dim z As String
Dim mass(100) As Single
' Очистка диапазона ячеек Range("Нб:К200"). Value =""
' Вычисление коэффициентов индексации
For i = 0 То 100
mass(i) = (1 + 0.015) л i
, Next
1 Заполнение диапазона информацией начинается с шестой строки strока = 6
' Цикл по листам данных
For i = 3 То ActiveWorkbook.Worksheets.Count N = О
Do While Worksheets(i).Cells(N +10, 3).Value <> ""
N = N + 1
Пример обработки отчетов из программы 1 (^Предприятие в книге Excel 115
Loop ' Цикл по строкам на листе данных
For j = 10 То 10 + N - 1 а = Worksheets(i).Cells(j, 3).Value z = isv(a) If StrComp(ComboBoxl.Text, z) = 0 Then NunCol = 8 ' Счетчик по столбцам If isNumeric(Worksheets(ii).Cells(j, 7).Value) = True Then ' Если информация в ячейке - число
Cells(stroka, NunCol) = Worksheets(ii).Cells(j, 7).Value NunCol = NunCol + 1 Cells(stroka, NunCol) = Worksheets(ii).Cells(j, 1).Value NunCol = NunCol + 1 ' Запись номера строки на листе Cells(stroka, NunCol) = j NunCol = NunCol + 1 Interval = DateDiff("m", Cells(ComboBoxl.Listindex +2, 3), _ Worksheets(ii).Cells(j, 1).Value) ' Запись проиндексированной суммы Cells(stroka, NunCol) = _
Worksheets(ii).Cells(j, 7).Value I mass(Interval) stroka = stroka + 1 End If End If Next Next End Sub
Примечание
Листинг 4.7 прокомментирован не очень подробно, поскольку большинство используемых здесь программных действий мы уже рассматривали.
Итак, мы рассмотрели второй управляющий лист книги (лист Индексация). Его основные функциональные возможности:
□	при щелчке на кнопке Вычислить автоматически вычисляются итоги по оплате для студентов с учетом механизма индексации;
□	с помощью элемента "поле со списком" организован просмотр детальной информации по оплатам каждого студента.
116
Гпаев 4
Процедура Workbook_Open
Понятно, что для работы с рассмотренной книгой требуется начальная инициализация (заполнение фамилиями) элементов "поле со списком", расположенных на первом и втором листах. В уже рассмотренных процедурах эти элементы заполняются по нажатию кнопок Вычислить. Однако часто требуется после открытия книги оперативно посмотреть информацию по конкретному студенту. Для этого элементы "поле со списком" должны быть уже заполнены. Такое действие удобно выполнить в процедуре workbook_0pen, текст которой приведен в листинге 4.8.
I Листинг 4.8. Процедура, выполняемая при открытии книги
Private Sub Workbook_Open()
' Подсчет фамилий студентов на первом листе (в пятом столбце) N = О
Do While Worksheets(1).Cells(N + 2, 5).Value <> "" N = N + 1
Loop
' Заполнение поля co списком фамилиями студентов
Worksheets (1). CariboBoxl. Clear
For i = 2 To N + 1
d = Worksheets(1).Cells(i, 5).Value
Worksheets(1).CoiriboBoxl.AddItem d
Next
' Подсчет фамилий студентов на втором листе (в пятом столбце) N = О
Do While Worksheets(2).Cells(N + 2, 1).Value <> "" N = N + 1
Loop
' Заполнение поля co списком фамилиями студентов
Worksheets(2).CoiriboBoxl.Clear
For i = 2 To N + 1
d » Worksheets(2).Cells(i, 1).Value
Worksheets (2) .CoiriboBoxl .AddItem d Next
' Установка надписей кнопок на управляющих листах Worksheets(1).CommandButtonl.Caption = "Вычислить" Worksheets(2).CommandButtonl.Caption = "Вычислить"
End Sub
Пример обработки отчетов из программы 1С:Предприятие в книге Excel П7
Теперь после открытия книги пользователь может сразу приступить к работе с уже имеющейся в ней информацией. Если на первом листе строка, соответствующая интересующему нас студенту, не видна, то после выбора его фамилии в списке нужная строка активизируется на экране. На втором листе можно сразу после открытия книги просмотреть сделанные оплаты с учетом индексации.
Можно спросить: нужны ли два листа, если их функции несколько схожи? Здесь следует заметить следующее. Как показала практика, первый лист (Основной) удобнее использовать при анализе оплат в процессе текущей работы, а когда для учащегося приближается окончание обучения, возникает потребность в листе Индексация. В основном это связано с тем, что сводная информация на первом листе заполняется исключительно по имеющимся данным (по листам, которые являются отчетами, полученными из программы 1С:Предприятие). Пользователю при этом нужно только щелкнуть на кнопке Вычислить на листе Основной. Просмотр информации по конкретному учащемуся реализуется исключительно* с помощью щелчков мыши. Лист Индексация уже требует начальной информации — дат зачисления учащихся и их сумм за весь период обучения. И в связи с некоторой инерционностью работы любого человека эта информация заполняется только тогда, когда она уже требуется явно.
Выводы
В этой главе мы разработали приложение, которое позволяет эффективно извлекать и обрабатывать информацию из отчетов, сформированных в программе 1 С: Предприятие.
Сразу после прочтения может возникнуть вопрос: какова практическая польза от рассмотрения этой разработки для читателя, не имеющего отношения к приведенному анализу денежных сумм? Дело в том, что рассмотренные действия применимы не только к учету платы за обучение. В процессе офисной работы часто требуется обработать в приложении Microsoft Excel информацию из отчетов программы 1С:Предприятие. Это связано с тем, что, как показывает статистика, большинство руководителей и менеджеров, в основном, работают с приложением Microsoft Excel. Тщательное изучение данной главы поможет вам построить автоматизированную книгу для своей задачи. Если взять и разложить вашу задачу на отдельные детали или составляющие, то вы увидите, что многие технические моменты для ее реализации вам уже знакомы.
118 Гпава 4
В заключение приведем основные практические результаты этой главы:
□	обработка отчетов из программы 1С:Предприятие в формате таблицы Microsoft Excel;
О создание автоматизированной книги с использованием двух управляющих листов и нескольких листов данных;
□	автоматическая обработка информации из отчетов;
□	получение сводной и детальной информации из отчетов с использованием элементов управления VBA.
Глава 5
Организация электронного документооборота
В настоящее время электронный документооборот стремительно совершенствуется, и существуют программные системы, позволяющие реализовать практически любую сложную циркуляцию документации. Подобные программные комплексы широко внедряются в крупных организациях и успешно справляются как с внутренним документооборотом, так и с потоком документов извне.
В то же время универсальные программные продукты (например, Microsoft Office) располагают неплохими средствами организации безбумажного обмена документацией. Здесь имеются в виду и электронная подпись документа, и возможность внесения изменений и резолюций разными лицами в разработанный документ, и возможности для отслеживания пути прохождения документа.
Можно сказать, что на данный момент в большинстве организаций в том или ином объеме реализуются электронные документы. Технически это производится либо с помощью достаточно дорогих специализированных программных продуктов, либо с помощью возможностей универсального программного обеспечения. Часто при этом на первый план выходит вопрос удобства работы, т. е. достаточно ли дружелюбен интерфейс программы для руководителей, которые, как правило, не являются опытными компьютерными пользователями. Фактически, нередко это серьезный аргумент для возможного использования той или иной программы.
В этой главе мы рассмотрим пример построения автоматизированной книги Excel, позволяющей реализовать функции электронного документооборота внутри организации. Познакомившись с этой разработкой, читатель при необходимости сможет легко внести в нее изменения с учетом специфических требований своей организации.
120
Гпава 5
Одним из основных компонентов безбумажного документооборота является защита фрагмента документа (или всего документа) электронной подписью автора. В этом случае получатели документа могут его читать, но не могут изменить его содержание. С другой стороны, получатели документа тоже должны иметь возможность наложить на него резолюцию и защитить ее электронной подписью (уже своей). Другими словами, в этом случае в документ вносится новая информация, которая защищается от ее возможного изменения следующими читателями. Так, если цепочка пересылки документа продолжается, то следующий получатель может внести свои замечания и тоже защитить их своей электронной подписью. Эта последовательность теоретически может быть очень значительной, однако реапьно большинство документов ограничивается подписями четырех-пяти лиц.
Итак, рассмотрим ситуацию, когда в организации одно из подразделений (фактически, его руководитель) выносит на согласование и подписывает проект документа, и этот проект затем последовательно рассматривается другими руководителями подразделений, которые заверяют его свой подписью.
В этой главе вы познакомитесь с возможностью размещения информации в рабочей книге Microsoft Excel, которая будет выступать в роли контейнера, включающего всю информацию (исходный документ, резолюции и электронные подписи) с необходимым механизмом защиты.
Описание элементов управления
На рис. 5.1 показан основной лист рассматриваемой рабочей книги для электронного документооборота. Идея заключается в том, что на рабочем листе размещаются элементы управления, позволяющие разным лицам вносить информацию, а затем защищать ее электронной подписью. В книге несколько листов, выполняющих различные функции. При этом все управление со стороны пользователя сосредоточено в объектах, расположенных на первом листе книги (рис. 5.1), который носит название Основной.
В верхней части листа расположены три элемента "надпись" — От, Название и Кому. Их роль достаточно проста и заключается в добавлении надписей для соответствующих элементов типа "текстовое окно", расположенных ниже (выделены серой заливкой).
Текстовое окно От предназначено для указания фамилии автора документа. В качестве значения его свойства Name выберем тх. Элемент, расположённый правее окна От, предназначен для ввода названия документа (Name = Т2). При этом, если нет необходимости отдельно указывать название (напри*мер, оно может быть фактически в самом документе), это текстовое окно можно
Организация электронного документооборота
121
не заполнять. Аналогичный элемент Кому (Name = тз) предназначен для указания лиц, которым направляется документ.
Рис. 5.1. "Авторские" элементы управления на листе Основной
Сам документ вводится пользователем с клавиатуры в элемент "текстовое окно" (Name = Т4), который на рис. 5.1 занимает центральную часть. Как видите, ему отводится ббльшая часть первого листа. При этом если вводимый документ становится достаточно большим по размеру (превосходит размеры текстового окна), то в элементе Т4 автоматически появляется полоса прокрутки.
Таким образом, элементы ti, т2, тз, т4 на первом листе предназначены для автора. В них он располагает содержание своего документа с поясняющей информацией.
Следующее действие после создания документа должно заключаться в защите введенной информации. Для этого предназначены элементы, расположенные в нижнем (левом) углу окна на рис. 5.1.
Крайний левый элемент внизу — поле со списком (Name = Personal), в котором автор документа перед внесением электронной подписи выбирает свою фамилию (указывает, кто подписал документ). Здесь подразумевается, что
122
Гпава 5
все фамилии руководителей, имеющих право подписи, предварительно внесены в программу. Технически это реализуется в процедуре workbook_oPen, о которой мы поговорим в дальнейшем.
Справа от рассмотренного поля со списком расположены два элемента управления — надпись и текстовое окно. В надписи располагается поясняющий текст для текстового окна, расположенного правее.
Примечание
В программных процедурах элемент “надпись" не используется, поэтому его свойство Name можно установить в любое значение.
Соседнее текстовое окно (Name = Pari) позволяет автору документа ввести с клавиатуры свою подпись (уникальный набор символов для каждого ответственного лица). При этом каждый руководитель знает свою электронную подпись и может подписаться только под своей фамилией.
Перейдем к элементу, расположенному правее текстового окна Pari — это кнопка (Name = ci). Щелчок на ней позволяет установить защиту от изменений для авторской части документа (защита для элементов Tl, Т2, тз, т4), а также заблокировать доступ к списку Personal (установить его свойство Enabled в значение False). После этого любой другой читатель не сможет изменить содержание документа. Внести изменения в документ можно только при вводе правильной подписи в элемент Pari для фамилии, зафиксированной В списке Personal.
Понятно, что при разработке документов мы, как правило, работаем с удобными текстовыми редакторами — в основном, с Microsoft Word. Поэтому необходимо предусмотреть для пользователя более быстрый механизм передачи информации из Microsoft Word в рассматриваемую рабочую книгу. Для этого в разработке используется буфер обмена Windows. Так, если у вас уже есть необходимый документ, созданный в приложении Microsoft Word, то нужно предварительно скопировать его содержимое в буфер обмена, а затем воспользоваться кнопкой Вст. из буф. обмена (Name = С2), при нажатии которой информация из буфера обмена размещается в текстовом окне Т4. В результате на первом листе книги вы увидите свой документ.
Другая ситуация связана с тем, что при черновой работе с документом требуется сначала быстро очистить окно Т4, а затем начать работу с документом заново. Для этого предназначена кнопка Очистить (Name = сз).
Понятно, что если документ в окне т4 достаточно велик, читателю удобнее знакомиться с ним в приложении Microsoft Word. Для этого предусмотрена кнопка Просмотр в Word (Name = с4), нажатие которой автоматически от
Организация электронного документооборота 123
крывает приложение Microsoft Word, а информация из окон ti, Т2, тз, Т4 переносится в новый документ, созданный в этом приложении. В большинстве ситуаций это может быть более удобной формой для ознакомления с документом.
Примечание
Кнопки С2 и сз функционируют только в том случае, если защита для авторской части документа еще не установлена, — они предназначены только для автора.
Итак, мы рассмотрели элементы управления из первого листа книги, связанные с авторской частью. Фактически, после заполнения текстовых окон ti, т2, тз, Т4 и внесения подписи документа рассматриваемую книгу можно отправлять первому адресату. Кроме элементов для автора, на первом листе книги присутствуют элементы управления, предназначенные для получателя. На рис. 5.2 показана нижняя часть рассматриваемого рабочего листа, где видны новые элементы, предназначенные для руководителя, которому документ направлен для резолюции.
Рис. 5.2. Элементы управления, предназначенные для получателя документа
Лицо, которому направлен.данный документ, может ввести нужный текст (замечания по исходному варианту) в элементе "текстовое окно" (Name = Т5), который На рис. 5.2 занимает большую часть окна.
После внесения замечаний по документу их нужно подписать. Для этого, во-первых, следует выбрать свою фамилию в элементе "поле со списком" (Name = Persona2), расположенном в правой части окна под кнопкой Просмотр в Word (см. рис. 5.2). Технически это поле со списком заполняется
W_________________________________________________________ Главе 5
В процедуре WorkbookjOpen одновременно С заполнением элемента Personal, о котором мы уже говорили.
После выбора своей фамилии следует ввести соответствующую подпись в нижнем элементе управления "текстовое окно" (Name = Раг2), расположенном справа от надписи Подпись.
Ниже элемента Раг2 находятся три кнопки, функции которых аналогичны кнопкам ci, С2 и сз. Значения свойства Name для этих новых элементов приведены в табл. 5.1.
Таблица 5.1. Кнопки
Кнопка	Значение свойства Name	Назначение
УстУснять защиту	С5	Установка/снятие защиты
Вст. из буф.	Сб	Вставка в поле т5 текста из буфера
обмена	С7	обмена
Очистить		Очистка поля Т5
Итак, мы рассмотрели все элементы управления, присутствующие на первом листе книги.
В большинстве ситуаций исходный документ подписывается 4—5 лицами. Значит, в рассматриваемую книгу следует внести еще несколько блоков, аналогичных приведенному фрагменту (включая элементы Т5, Persona2, Раг2, С5, сб и с?). Каждый получатель документа заносит резолюцию в очередной свободный блок и защищает ее электронной подписью. В книге мы ограничились одним блоком (одним местом для одной подписи), т. к. при необходимости можно легко добавить на рабочий лист еще несколько подобных секций.
Примечание
На сопроводительном компакт-диске книги имеется вариант рабочей книги с выделением места для четырех резолюций по исходному документу.
Примечание
Далее мы будем программно работать с рассмотренными элементами первого листа, поэтому, если вы параллельно выполняете указанные действия на компьютере, следует использовать приведенные имена элементов.
Перейдем ко второму листу книги (рис. 5.3), который содержит служебную информацию для работы программы и используется программными, процедурами независимо от пользователя.
Организация электронного документооборота
125
Рис. 5.3. Второй рабочий лист книги: 1—5 — текстовые окна; 6—диапазон 01:12
Для всех пользователей второй лист недоступен и защищен от возможного ручного изменения данных паролем (средствами Microsoft Excel).
Примечание
Аналогичным образом защищены элементы управления на первом листе (иначе их можно просто удалить с листа).
Для установки защиты следует в приложении Microsoft Excel выбрать пункт Защита меню Сервис. В появившемся списке нужно выбрать пункт Защитить лист и установить защиту с использованием пароля.
На рис. 5.3 цифрой 6 обозначен диапазон ячеек G1:I2. Далее вы увидите, каким образом программные процедуры самостоятельно (независимо от пользователя) записывают служебную информацию в эти ячейки. А пока рассмотрим эту служебную информацию.
Если на первом листе с помощью кнопки У стеснять защиту устанавливается защита для первого фрагмента документа (авторская часть, расположенная в элементах ti, Т2, тз, Т4}, то в ячейку G1 программно записывается 1. Тем самым отмечается факт, что защита для авторской части установлена. Также программно в ячейку Н1 записывается фамилия лица, которое эту защиту установило. Кроме того, в ячейку II заносится индекс элемента списка
126
Гпава 5
personal, содержащего указанную фамилию. Подчеркнем: все эти действия выполняются по щелчку на кнопке УстУснять защиту. Снятие защиты с авторской части (щелчком на данной кнопке) приводит к удалению информации из ячеек G1:I1.
Примечание
Установив защиту, пользователь не сможет редактировать свой документ, а его фамилия в списке (слева от подписи) становится недоступной (отображается бледным цветом). Когда защита снимается, список для выбора фамилии становится доступным для подписавшего (в нем можно выбрать любую фамилию из имеющихся).
Примечание
Р^пя пользователя второй лист защищен от изменений, и программная процедура, выполняемая по щелчку на кнопке Уст./снять защиту, самостоятельно на момент записи сначала снимает защиту, а затем ее опять восстанавливает (как это реализовано в программе, мы рассмотрим далее).
Следующие три ячейки (G2, Н2 и 12) на втором листе относятся к управлению защитой фрагмента для внесения резолюции по документу. При этом в G2 программно записывается 1 при установке защиты, в Н2 фиксируется фамилия подписавшего лица, а в 12 записывается индекс элемента списка Persona?, содержащего указанную фамилию.
Если секций для резолюций больше, то для них используются следующие ячейки (G3, НЗ и 12 для третьего лица и т. д.). На рис. 5.3 заливкой выделены две строки для возможных подписей, поскольку в приведенной книге всего два комплекта элементов управления для внесения подписей (на компакт-диске имеется вариант книги с четырьмя комплектами).
Таким образом, мы рассмотрели основные функции второго листа. Поясню назначение расположенных на нем элементов управления. Цифрами 1—5 обозначены текстовые окна, которые используются самостоятельно программными процедурами и для пользователя недоступны. В значениях свойства Name этих элементов присутствует число, соответствующее числовым обозначениям на рис. 5.3: ti, т2, тз, Т4, т5. Их назначение связано с используемым механизмом защиты. А именно: при установке защиты автором документа (с помощью кнопки УстУснять защиту на первом листе) информация из текстовых окон ti, Т2, тз, т4 первого листа копируется в соответствующие текстовые окна ti, Т2, тз, т4 второго листа. Тем самым на втором листе фиксируется информация документа в оригинале. Аналогично, после внесения резолюции по документу и установки защиты для нее информация из текстового окна т5 первого листа копируется в соответствующее текстовое окно Т5 на втором листе. Тем самым на втором листе фиксируется
Организация электронного документооборота 127
информация о внесенной подписанной резолюции. В этом заключается подготовительная часть механизма защиты.
Далее программно реализовано следующее. Если читатель документа, просматривая его, попытается что-либо в нем изменить, то исходная информация автоматически восстанавливается с помощью второго листа. Например, если внести изменения в окне Т4 на первом листе, то содержимое Т4 автоматически заменится истинной информацией из элемента т4, расположенного на втором листе. Аналогичным образом защита устанавливается и для других текстовых окон.
Итак, в этом разделе мы рассмотрели функциональное назначение первых двух листов книги. Для создания документа, внесения подписи и добавления резолюций по нему используется первый лист книги. Второй лист предназначен исключительно для защиты информации и в свою очередь защищен от случайных или умышленных действий пользователя.
Процедура установки защиты
Описав структуру листов книги, перейдем к программным конструкциям. Поэтому вернемся к первому листу и далее рассмотрим текст процедуры, выполняемой по щелчку на кнопке У стеснять защиту (Name = ci), с помощью которой можно либо установить защиту для авторской части документа, либо наоборот снять ее (листинг 5.1). В этой процедуре выполняется проверка соответствия фамилии руководителя, которому разрешено подписывать документы, его уникальной электронной подписи.
Листинг 5.1. Процедура, выполняемая по щелчку на кнопке
Уст ./снять защиту для авто/ а
Private Sub Cl_Click()
' Ячейка G1 на втором листе отводится для индикатора
’ установки защиты авторской части документа.
' Ячейка Н1 на втором листе отводится для фамилии лица,
' поставившего свою подпись под авторской частью документа
а = Personal.Text ' Запись в переменную а фамилии
с = Pari.Text	* Запись в переменную с подписи
' Переменная flag - индикатор соответствия подписи и фамилии flag = О
• В переменной Chislo предварительно (в процедуре Workbook_Open)
' установлено число лиц, имеющих право подписи
Гпава 5
126
For i = 1 То Chislo b = polsovt(i) ' В этот массив предварительно заносятся ' все фамилии лиц, имеющих право подписи If b « a Then
If с = parols(i) Then
' Если найдено соответствие фамилии и введенной подписи If Worksheets(2).Cells(1, 7).Value = "" Then
' Если защиты для авторской части на первом листе не было Worksheets(2).Unprotect ("23")' Снятие защиты со второго листа
' В ячейке G1 на втором листе отмечаем факт защиты Worksheets(2).Cells(1, 7).Value = "1"
1 В ячейку Hl на втором листе записываем фамилию Worksheets(2).Cells(1, 8).Value = а
' В ячейку II записываем номер элемента, выбранного
* в поле со списком Personal Worksheets(2).Cells(1, 9).Value = i - 1
' Блокировка списка Personal Personal.Enabled = False
' Копирование текста из элемента Т1 первого листа на второй лист Worksheets(2).Tl.Text = Tl.Text
' Копирование текста из элемента Т2 первого листа на второй лист Worksheets(2).Т2.Text = Т2.Text
' Копирование текста из элемента ТЗ первого листа на второй лист Worksheets(2).ТЗ.Text = ТЗ.Text
' Копирование текста из элемента Т4 первого листа на второй лист Worksheets(2). Т4.Text = Т4.Text
' Блокировка элементов С2 и СЗ на первом листе С2.Enabled = False СЗ.Enabled = False flag = 1 ' Отмечаем факт внесения подписи Exit For
Else ' Если пароль уже был установлен, то мы его снимаем Worksheets(2).Unprotect ("23") ' Удаляем информацию о подписи из ячеек Gl, Hl, II Worksheets(2).Range("Gl:I1").Value = ""
' Разрешаем доступ к списку лиц на первом листе Personal.Enabled = True Personal.Listindex - -1
’ Разрешение доступа к кнопкам С2 и СЗ на первом листе
Организация электронного документооборота 129
С2.Enabled = True СЗ.Enabled = True flag = 1 ' Факт снятия подписи Exit For End If End If End If Next ' Установка защиты на втором листе Worksheets(2) .Protect Password:="23", _ Drawingobjects:=True, Contents:=True, Scenarios:=True Pari.Text = ""	' Очистка окна для подписи
' Если не найдено соответствие фамилии и подписи If flag = 0 Then
MsgBox ("Ошибка при вводе пароля!") End If End Sub
Данная процедура основана на том, что предварительно заносится информация в массивы polsovt и parols. Массив polsovt отводится для фамилий руководителей, которым разрешено подписывать документ, а массив parols содержит индивидуальные пароли (подписи) для каждого руководителя. Механизм проверки соответствия элементов этих массивов таков: polsovt (1) — фамилия лица, a parols (1) — его подпись. Еще одна переменная (chisio) служит для определения количества лиц, которым разрешено подписывать документ. Инициализация этих данных производится в предопределенной процедуре workbook_open, выполняемой при открытии книги (с ней мы познакомимся далее).
Строки процедуры из листинга 5.1 достаточно подробно прокомментированы.
Примечание
Программные конструкции листинга 5.1 соответствуют описанию организации книги, приведенном в предыдущем разделе этой главы.
Перед тем, как продолжить рассмотрение программной реализации, разберем на примере создание и возможное продвижение одного из гипотетических документов с добавлением к нему резолюций и внесением подписей. Это будет полезно, т. к. вы увидите возможные действия с рассматриваемой книгой.
130
Гпава 5
Пример создания электронного документа
Допустим, один из деканатов вуза выносит на рассмотрение проект о плане приема на ряд специальностей. На рис. 5.4 показан возможный вариант документа, где после ввода авторского текста из списка лиц выбрана фамилия руководителя и в текстовом окне набрана его электронная подпись. Теперь создателю документа осталось только щелкнуть на кнопке У стеснять защиту. После этого действия текст документа становится недоступным для изменения. А вернуть документ в режим редактирования можно только с помощью ввода уникальной подписи автора (в данном случае автором документа является Петров Г. П.).
Рис. 5.4. Пример защищенного документа
После этого созданную рабочую книгу Microsoft Excel следует сохранить и отправить по электронной почте получателю. В рассматриваемом примере это первый проректор Иванов А. Н. Он может внести резолюцию и защитить эту информацию своей электронной подписью (рис. 5.5).
Уже говорилось о том, что в книге может быть больше одного комплекта элементов управления для внесения резолюций. В этом случае Иванов А. Н.
Организация электронного документооборота
может отправить документ следующему получателю, скажем, ректору. Ректор накладывает резолюцию и также защищает ее своей электронной подписью.
Рис. 5.5. К документу добавляется резолюция
Затем эту книгу Microsoft Excel можно отправить обратно Петрову Г. П., который на основании сделанных электронных резолюций сможет создать печатный вариант документа, уже не требующий согласования (т. е. дополнительных затрат времени).
Примечание
Важно, что в результате выполненных действий у каждого участника компьютерного обмена остался электронный документ с электронными подписями, что весьма важно в случае возможных взаимных претензий.
Итак, мы рассмотрели процесс работы с автоматизированной книгой, но осталось много нерассмотренных моментов по программному коду, и в следующем разделе мы разберем одну из ключевых процедур данной разработки.
Процедура Workbook_Open
Вернемся к программированию. В рассмотренной ранее процедуре (см. листинг 5.1) использовались массив для хранения фамилий лиц, имеющих право подписи, и массив для подписей. Для определения этих массивов и выделения для них памяти создадим новый модуль (рис. 5.6). Технически для создания нового модуля следует воспользоваться пунктом Module меню Insert. Эти массивы будут доступны изо всех процедур рабочей книги. О назначении каждого массива, а также о переменной chisio говорилось выше. Здесь же.
132
Гпава 5
в листинге 5.2, приведена процедура workbook_open, выполняемая при открытии книги, где и выполняется инициализация массивов и переменной chisio. Кроме того, в этой предопределенной процедуре задаются начальные установки элементов управления первого листа при открытии книги.
Рис. 5.6. Новый модуль
Листинг 5 2. Процедура, выполняемая при открытии книги
Private Sub Workbook_Open ()
* Инициализация массивов фамилий лиц, имеющих право подписи, и их паролей polsovt(1) я "Петров ГП" parols(1)  "123456789" polsovt (2) » «Иванов АН" parols(2) я "234567891" polsovt(3)  "Сидоров АД" parols(3)  "345678912" polsovt(4) я "Афанасьев ЛА" parols(4) я "456789123" polsovt(5)  "Логинов ЮВ" parols(5) » "567891234"
' Занесение в переменную Chisio количества лиц, имеющих право подписи Chisio я 5
' Заполнение списков лиц с предварительной очисткой Worksheets(1).Personal.Clear Worksheets(1).Persona2.Clear For i » i то Chisio
Организация электронного документооборота 133
Worksheets(1).Personal.Additem polsovt(i)
Worksheets(1).Persona2.Additem polsovt(i) Next If Worksheets(2).Range("Gl").Value <> 1 Then ' Если подпись в авторской части не установлена
Worksheets(1). Personal.Enabled = True
Worksheets(1) .Personal.Listindex = -1
Worksheets(1).C2.Enabled = True
Worksheets(1).C3.Enabled = True
Else
' Если подпись в авторской части установлена
Worksheets(1).Personal.Listindex = _
Worksheets(2) .Cells(1, 9) .Value
Worksheets(1). Personal.Enabled = False
Worksheets(1).C2.Enabled « False
Worksheets(1).C3.Enabled = False
End If
If Worksheets(2).RangelHG2H).Value <> 1 Then ' Если подпись в блоке для резолюции не установлена
Worksheets(1).Persona2.Enabled = True
Worksheets(1).Persona2.Lietlndex = -1
Worksheets(1).C5.Enabled • True
Worksheets(1).C6.Enabled » True
Else 1 Если подпись в блоке для резолюции установлена
Worksheets(1).Persona2.Listindex « _
Worksheets(2).Cells(2, 9).Value
Worksheets(1). Persona2.Enabled « False
Worksheets(1).C5.Enabled 3 False
Worksheets(1).C6.Enabled 3 False End If ' Активизация первого листа книги Worksheets(1).Activate ' Очистка окон, где расположены подписи Worksheets(1).Pari.Text » "" Worksheets(1).Par2.Text » "" End Sub
Кроме инициализации массивов и переменной chislo, в процедуре workbook_0pen выполняется ряд технических действий, которые прокоммен
134
Гпава 5
тированы далее. Так, в следующих строках в списки заносятся фамилии лиц, имеющих право подписи:
For i = 1 То Chislo
Worksheets(1).Personal.Additem polsovt(i)
Worksheets(1) .Persona2.Additem polsovt(i)
Next
Как уже говорилось, доступ к элементу Personal блокируется после щелчка на кнопке УстУснять защиту (Name = ci), если предварительно в поле pari была внесена правильная подпись. При этом (см. листинг 5.1) в ячейку G1 программно записывается 1 (флаг установки защиты).
Также в процедуре workbook_0pen в зависимости от выполнения условия
If Worksheets(2).RangeСGl").Value <> 1 Then
при открытии книги по-разному устанавливаются значения свойств элементов управления. Так, при включенной защите для авторской части в поле со списком с помощью свойства Listindex устанавливается фамилия лица, подписавшего документ:
Worksheets(1).Personal.Listindex = Worksheets(2).Cells(1, 9).Value
В этом случае блокируется доступ к элементам управления, с помощью которых можно внести изменения в документ:
Worksheets(1). Personal.Enabled = False
Worksheets(1).C2.Enabled = False
Worksheets(1).C3.Enabled = False
Аналогично действиям с авторской частью документа, в процедуре workbooK_0pen выполняется начальная установка для области резолюции. Так, в зависимости от выполнения условия
If Worksheets(2).Range("G2").Value <> 1 Then
по-разному устанавливаются значения свойств элементов управления, связанных с резолюцией по документу. При наличии указанной защиты для этой части документа в списке Persona2 при открытии книги устанавливается фамилия лица, поставившего свою подпись под резолюцией:
Worksheets(1).Persona2.ListIndex = Worksheets(2).Cells(2, 9).Value
При этом также блокируется доступ к элементам управления, с помощью которых можно внести изменения в эту часть документа:
Worksheets(1). Persona2.Enabled = False
Worksheets(1).C5.Enabled = False
Worksheets(1).C6.Enabled = False
Организация электронного документооборота 135
Остальные строки процедуры прокомментированы в листинге 5.2, и на них останавливаться не будем.
Примечание
При увеличении количества полей для резолюций и подписей в процедуре Workbook_0pen должны присутствовать подобные фрагменты программного кода, производящие необходимую инициализацию при открытии книги.
Механизм защиты документа
В этом разделе мы рассмотрим наиболее интересный прием из приведенных в этой главе — механизм организации защиты информации для текстовых окон на первом листе. Чтобы изложение было более конкретным, разберем этот механизм для текстового окна Т4, которое содержит авторский документ.
Для этого требуется оформить предопределенную процедуру T4_change, выполняемую при изменениях в текстовом окне Т4, в соответствии с листингом 5.3. Так, если кто-то, читая имеющийся документ, введет в него хотя бы одну новую букву, происходит автоматическое восстановление текста документа с помощью второго листа (т. е. информации из текстового окнат4 на этом листе).
I Листинг 5,3 Процедура, выполняемая при изменении в текстовом окне Т4 первого листа
Private Sub T4_Change()
If Worksheets(2).Cells(1, 7).Value = "1" Then
If Worksheets(2).T4.Text <> T4.Text Then
T4.Text = Worksheets(2).T4.Text
End If
End If
End Sub
На рис. 5.7 показан второй лист книги в варианте, когда защита установлена. По содержимому диапазона ячеек G1:I2 видно, что защита установлена и для авторской части документа, и для области резолюции.
Процедуры, выполняемые при внесении изменений в других текстовых окнах на первом листе, аналогичны листингу 5.3, поэтому здесь не приводятся (они присутствуют на сопроводительном компакт-диске книги).
136
Гпава 5
Рис. 5.7. Второй лист книги с установленной защитой
Процедура установки защиты
для резолюции
Мы уже достаточно подробно рассмотрели процедуру, реализующую установку защиты для авторской части документа (см. листинг 5.1). В этом разделе показано, как программно организовать защиту информации для области резолюции, когда добавлена электронная подпись. Как уже говорилось, защита в этом случае касается информации в текстовом окне т5 на первом листе. В листинге 5.4 приведена процедура, выполняемая по щелчку на кнопке УСТЕСНЯТЬ защиту (Name = С5).
| Листинг 5.4. Обработка щелчка на кнопке УстЛнять защиту (для резолюции)
Private Sub C5_Click()
' Ячейка G2 на втором листе отводится для индикатора установки
' защиты резолюции по документу.
' Ячейка Н2 на втором листе отводится для фамилии лица,
’ поставившего свою подпись под резолюцией а = Persona2.Text
с = Par2.Text
' Переменная flag - индикатор соответствия подписи и фамилии flag = О
Организация электронного документооборота
137
В переменной Chislo предварительно (в процедуре Workbook_Open) установлено число лиц, имеющих право подписи For i = 1 То Chislo
b = polsovt(i) ' В этот массив предварительно заносятся ' все фамилии лиц, имеющих право подписи If b = a Then
If с = parols(i) Then
1 Если найдено соответствие фамилии и введенной подписи If Worksheets(2).Cells(2, 7).Value = "" Then ' Если защита не была установлена
Worksheets(2).Unprotect ("23") ' Снятие защиты со второго листа 1 В ячейке G2 на втором листе отмечаем факт защиты
Worksheets(2).Cells(2, 7).Value = "Iй
' В ячейку Н2 на втором листе записываем фамилию Worksheets(2).Cells(2, 8).Value = а
' В ячейку 12 записываем номер элемента, выбранного
' в поле со списком Persona2 Worksheets(2).Cells(2, 9).Value = i - 1
' Блокировка списка Persona2 Persona2.Enabled = False
' Перенос информации на второй лист Worksheets(2).Т5.Text = Т5.Text
' Блокировка кнопок по изменению фрагмента Сб.Enabled = False С7.Enabled = False
flag = 1 ' Отмечаем факт подписи резолюции Exit For
Else
' Если пароль был установлен, то мы его снимаем Worksheets(2).Unprotect ("23") Worksheets(2).Range("G2:12").Value = ""
' Доступ к списку лиц на первом листе Persona2.Enabled = True Persona2.Listindex = -1 C6.Enabled = True C7.Enabled = True flag = 1 1 Факт снятия подписи Exit For
End If
End If
13# Глева 5
End If
Next
' Установка защиты на второй лист
Worksheets(2) .Protect Password: =" 2 3", _
Drawingobjects:=True, Contents:=True, Scenarios:=True
Par2.Text = ""	' Очистка информации о подписи
If flag = 0 Then * Если не найдено соответствие фамилии и подписи
MsgBox ("Ошибка при вводе пароля!")
End If
End Sub
Сервисные возможности книги
Мы рассмотрели основные компоненты автоматизированной книги Microsoft Excel, которая выполняет функции контейнера, вмещающего авторский текст документа, резолюции и электронные подписи. Пока остались непрокоммен-тированными кнопки Вст. из буфера, Очистить и Просмотр в Word. Эти элементы связаны с сервисными возможностями для автора, и в этом разделе мы рассмотрим программные процедуры, которые их обеспечивают.
Уже говорилось о том, что при наличии готового документа, созданного в одном из текстовых редакторов, автору удобнее непосредственно вставить свой текст в элемент Т4 с помощью буфера обмена Windows. В листинге 5.5 приведена процедура обработки щелчка на кнопке Вст. из буфера для авторской части документа.
^Листинг 5.5. Вставка текста из буфера обмена в элемент т4 первого листа
Private Sub C2_Click()
Т4.Paste
End Sub
Здесь используется метод Paste, позволяющий разместить содержимое буфера обмена в текстовом окне. В области резолюции (см. рис. 5.2) имеется аналогичная кнопка, и текст процедуры в этом случае практически такой же (листинг 5.6).
| Листинг 5.6. Вставка текста из буфера обмена в элемент Т5 первого листа
Private Sub C6_Click()
Т5.Paste
End Sub
Организация электронного документооборота
139
Подобная работа с буфером обмена может существенно упростить работу как для автора, так и для лица, вносящего замечания по документу. Процедура очистки окна документа еще проще (листинг 5.7).
рГистинг 5.7. Очистка окна документа
Private Sub C2_Click()
T4.Text = ""
End Sub
Теперь перейдем к рассмотрению наиболее интересной сервисной функции для получателя документа.
Мы уже говорили о том, что кнопка Просмотр в Word позволяет скопировать исходный авторский документ в приложение Microsoft Word, которое при этом запускается автоматически. Для пользователя в этом случае информация из текстовых окон тх, тг, тз, Т4 просто копируется в новый файл, создаваемый в приложении Microsoft Word. Понятно, что подобный вариант просмотра существенно удобнее, особенно если документ достаточно велик.
Эта возможность реализуется с помощью средства Automation — одного из наиболее популярных компонентов технологии ActiveX. В нем заложена идея программного управления объектами одного приложения из других приложений. В результате в настоящее время эта технология стала серьезным интеграционным ресурсом для выполнения офисных разработок. И перед тем как вернуться к программированию для нашей книги, прокомментируем компонент Automation.
Все приложения (в том числе Microsoft Word и Microsoft Excel), поддерживающие средство Automation, делятся на две категории — клиенты и серверы. Серверами считаются приложения, которые предоставляют свои объекты для использования. А те приложения, которые используют объекты другого приложения, называются клиентами.
В нашем случае в качестве клиента выступает табличный процессор Microsoft Excel, а сервером является текстовый процессор Microsoft Word. В дальнейшем вы узнаете, как вызывать приложение Microsoft Word из книги Excel. И не просто вызывать, но и использовать объекты Word (работать со свойствами и методами этих объектов). Фактически, в этом случае приложение Microsoft Word предоставит нам свои ресурсы по созданию и форматированию документов.
С точки зрения пользователя, по щелчку на кнопке Просмотр в Word на первом листе нашей книги документ создается сам, и от него ничего не требуется (кроме предварительного написания программы).
Заметим, что такое средство разработки, как VBA, является общим для всех составляющих Microsoft Office. Интересный вопрос: в чем особенность программных конструкций, использующих свойства и методы объектов приложения-сервера? Как вы увидите далее по синтаксису программных примеров, для приложения-клиента обращение к свойствам и методам объектов приложения-сервера аналогично использованию своих собственных.
Теперь мы можем перейти к пояснению программных конструкций, используемых в следующей процедуре.
Одной из возможностей создания объекта для Automation является использование функции Createobject, которая имеет следующий синтаксис:
Createobject(класс, имя сервера)
Здесь класс — имя класса объекта Automation, а имя сервера в нашей разработке является необязательным параметром (используется при работе в сети). Для запуска приложения Microsoft Word из процедуры, расположенной в книге Excel, следует использовать следующий набор команд:
Dim appWD As Object
Set appWD = Createobject("Word.Application")
appWD.Visible = True
Здесь функция Createobject создает объект Microsoft Word и возвращает ссылку на это приложение. Теперь уже с помощью этой ссылки можно программно работать с объектами процессора Microsoft Word — документами и их составляющими (абзацами, символами и т. д.). В третьей строке приведенного фрагмента используется свойство visible (видимость) — с помощью присвоения ему значения True окно текстового процессора появляется на экране. Если эти три строки оформить в виде текста процедуры, выполняемой по щелчку на кнопке, то, щелкнув на этой кнопке, мы из приложения Microsoft Excel "попадем" в приложение Microsoft Word.
После создания ссылки на приложение Microsoft Word можно работать с объектами и коллекциями, входящими в данный объект. Так, для добавления нового документа можно воспользоваться коллекцией Documents. Эта коллекция включает объекты Document, каждый из которых есть не что иное, как документ Microsoft Word. Например, если добавить к трем предыдущим строку
appWD.Documents.Add
то это приведет к появлению нового документа в окне текстового редактора.
В рассматриваемой далее процедуре (выполняемой при щелчке на кнопке Просмотр в Word) часто будет использоваться объект ActiveDocument, представляющий собой активный документ, открытый в приложении Microsoft Word. С его помощью можно получить доступ к содержанию документа через так называемые внутренние объекты — абзацы, предложения, слова и т. д.
Организация электронного документооборота 1 41
В предыдущем фрагменте после выполнения команды appWD.Documents .Add автоматически происходит создание объекта ActiveDocument. Перейдем на более низкий уровень и посмотрим, как работать с объектами, составляющими документ. Так, для добавления в активный документ нового абзаца следует воспользоваться следующей командой:
appWD.ActiveDocument.Paragraphs.Add
Здесь мы учли сделанную ранее ссылку appWD на объект Microsoft Word, а также использовали коллекцию Paragraphs, представляющую собой все абзацы документа. Затем мы использовали метод Add этой коллекции для добавления нового абзаца в документ.
Для программной вставки текста в документ (как в новый, так и в уже имеющийся) применяется объект Range, представляющий собой любую часть текста документа (в том числе, и только что созданный абзац). Этот объект в какой-то степени похож на уже известный вам одноименный объект из приложения Microsoft Excel. И там, и здесь Range представляет собой диапазон. В приложении Microsoft Word объект Range может быть создан разными способами. Например, можно указать номер абзаца или начальный и конечный символы диапазона.
Вставить текст в документ позволяют два метода объекта Range — insertBefore (можно перевести как "до диапазона") и insertAf ter ("после диапазона"). Например, вставить текстовый фрагмент можно с помощью следующей конструкции:
appWD.ActiveDocument.Paragraphs(1).Range().InsertAfter ("текст 1")
У коллекции Paragraphs есть свойство Count, позволяющее получить количество абзацев в документе. В следующей конструкции в переменной а подсчитывается количество имеющихся абзацев в активном документе:
a=appWD.ActiveDocument.Paragraphs.Count
Также для определенного абзаца с помощью объекта Range можно изменить шрифт текста. Например, установим 14-й размер шрифта для первого абзаца:
appWD.ActiveDocument.Paragraphs(1).Range().Font.Size = 14
Можно также задать стилевое оформление текста. Так, если наш первый абзац мы хотим оформить как заголовок второго уровня, то следует написать:
appWD.ActiveDocument.Paragraphs(1).Rangef).Style="Заголовок 2П
Приведу еще несколько примеров по важным методам, хотя и не используемых в нашей дальнейшей процедуре.
□	Открытие существующего документа Microsoft Word из приложения Microsoft Excel:
appWD.Documents.Open(Имя файла)
142
Глава 5
П Простое сохранение документа:
MyDoc - appWD.ActiveDocumentO
MyDoc.Save()
□	Программное сохранение файла под конкретным именем:
MyDoc = appWD.ActiveDocumentO
MyDoc.SaveAs (Имя файла)
□	Закрытие документа:
MyDoc.Close О
□	Закрытие самого приложения Word:
appWD.QuitО
Итак, мы рассмотрели основные сведения по объектам Microsoft Word, которые понадобятся нам прямо сейчас.
После отступления вернемся к нашей задаче. В листинге 5.8 приведена процедура, выполняемая по щелчку на кнопке Просмотр в Word.
^Листинг 5.8. Процедура обработки щелчка на кнопке Просмотр е Word	I
Private Sub C4_jClick()
Dim appWD As Object
*	Открытие приложения Microsoft Word
Set appWD = CreateObject("Word.Application")
appWD. Visible = True'
' Создание нового документа
appWD.Documents.Add
’ В документ Word вставляется слово "От"
appWD.ActiveDocument.Paragraphs(1).Range().InsertAfter ("Or ")
•	Установка размера шрифта
appWD.ActiveDocument.Paragraphs(1).Range().Font.Size = 10
•	Добавление абзаца в документ
appWD.ActiveDocument.Paragraphs.Add
'	Вставка в документ информации из текстового окна Т1
appWD.ActiveDocument.Paragraphs(2).Range(j.InsertAfter (Tl.Text)
' Подсчет количества абзацев
par_new = appWD.ActiveDocument.Paragraphs.Count
* Изменение размера шрифта для информации в окне Т1
For i = 2 То par_new
appWD.ActiveDocument.Paragraphs(i).Range().Font.Size = 16
Next
* Добавление абзаца в документ
Организация электронного документооборота 143
appWD.ActiveDocument.Paragraphs.Add
' В документ вставляется слово "Кому"
par_old = appWD.ActiveDocument.Paragraphs.Count appWD.ActiveDocument.Paragraphs(par_old).Range().InsertAfter ("Кому") appWD.ActiveDocument.Paragraphs(par_old).Range().Font.Size = 10
' Добавление абзаца в документ
appWD.ActiveDocument.Paragraphs.Add
par_old = appWD.ActiveDocument.Paragraphs.Count
1 Вставка в документ информации из текстового окна ТЗ appWD.ActiveDocument.Paragraphs(par_old).Range().InsertAfter (T3.Text) par__new = appWD. ActiveDocument. Paragraphs. Count
' Изменение размера шрифта для информации в окне ТЗ
For i = par_old То par_new
appWD.ActiveDocument.Paragraphs(i).Range().Font.Size = 18 Next
' Добавление абзацев в документ
appWD.ActiveDocument.Paragraphs.Add
appWD.ActiveDocument.Paragraphs.Add
par_old = appWD.ActiveDocument.Paragraphs.Count
' Вставка поясняющего текста
appWD.ActiveDocument.Paragraphs(par_old).Range().InsertAfter _ ("Название документа")
appWD.ActiveDocument.Paragraphs(par_old).Range().Font.Size « 10
' Добавление абзаца в документ
appWD.ActiveDocument.Paragraphs.Add
par_old = appWD.ActiveDocument.Paragraphs.Count
' Вставка в документ информации из текстового окна Т2
appWD.ActiveDocument.Paragraphs(a).Range().InsertAfter (T2.Text) par_new » appWD.ActiveDocument.Paragraphs.Count
' Изменение размера шрифта для информации в окне Т2
For i = par_old То par_new
appWD.ActiveDocument.Paragraphs(i).Range().Font.Size = 22
Next
' Добавление абзацев в документ
appWD.ActiveDocument.Paragraphs.Add
appWD.ActiveDocument.Paragraphs.Add
appWD.ActiveDocument.Paragraphs.Add
par_old = appWD.ActiveDocument.Paragraphs.Count
' Вставка поясняющего текста
appWD.ActiveDocument.Paragraphs(par_old).Range().InsertAfter _
("Текст документа")
144
Гпава 5
appWD-ActiveDocument.Paragraphs(par_old) .Range() .Font.Size = 1-0
• Добавление абзаца в документ
appWD.Act iveDocument.Paragraphs.Add
par_old = appWD.ActiveDocument.Paragraphs.Count
' Вставка в документ информации из текстового окна Т4
appWD.ActiveDocument.Paragraphs(а).Range().InsertAf ter (T4.Text) par_new = appWD.ActiveDocument.Paragraphs.Count
' Изменение размера шрифта для информации в окне Т4
For i = par_old То par_new
appWD.ActiveDocument.Paragraphs(i) .Range().Font.Size = 14 Next
End Sub
Если после создания процедуры, приведенной в листинге 5.8, щелкнуть на кнопке Просмотр в Word, то мы увидим окно приложения Microsoft Word. Если на первом листе книги Microsoft Excel авторская часть документа пуста, то перед нами откроется пустое окно нового документа.
Вернемся к рис. 5.4, где показан вариант документа. Созданная процедура позволяет передать его в Microsoft Word, где мы увидим автоматически созданный текст (рис. 5.8).
Рис. 5.8. Создан документ Microsoft Word
Организация электронного документооборота
145
Дополнительные листы
Если снова взглянуть на рис. 5.4, то кроме двух первых листов книги, которые мы уже рассмотрели, видны ярлычки листов Приложение 1, Приложение 2, Приложение 3. Если указанных выше возможностей программы достаточно, то эти листы, в принципе, можно не использовать.
А теперь о том, что можно размещать на этих листах и зачем они нужны. Ранее говорилось, что исходный документ, созданный автором, размещается в текстовом окне с именем Т4 (см. рис. 5.1). Однако если документ большой и имеет сложное форматирование, то лучше передать его еще и в оригинальном виде (т. е. в том приложении, в котором он был создан). На листе с названием Приложение 1 автор может разместить свой оригинальный документ.
Поясню технические шаги, которые в этом случае нужно сделать. Находясь в приложении Microsoft Excel, выберите пункт Объект меню Вставка — откроется окно, показанное на рис. 5.9.
Рис. 5.8. Диалоговое окно Вставка объекта
Перейдите, на вкладку Из файла. Здесь следует выбрать нужный файл с документом, который в результате будет размещен на листе Microsoft Excel. Аналогичные листы (Приложение 1, Приложение 2 и т. д.) позволяют другим участникам электронного обмена при необходимости размещать свои оригинальные документы в одной книге Microsoft Excel.
146
Гпава 5
На рис. 5.10 показано размещение одного из возможных документов. Двойной щелчок на объекте на листе Microsoft Excel позволяет просмотреть его оригинальный вариант в приложении, в котором он был создан.
Рис. 5.10. На лист Excel вставлен объект
Шаблон книги
Цель, поставленная в начале главы, практически достигнута. Все созданные на первом листе книги элементы управления работают. Авторский документ можно легко защитить электронной подписью. При создании документа автор может пользоваться буфером обмена. А для получателя в книге имеется область для внесения резолюции, которая тоже может быть защищена электронным паролем. Второй лист книги выполняет служебную роль и используется независимо от пользователя программными процедурами.
Таким образом, книга готова, осталось только дать небольшие рекомендации о том, как с ней работать.
Как известно, для документов существует такое понятие, как шаблон. Шаблон — это заготовка для будущего документа (шаблон в Microsoft Excel — это заготовка для книги). Поэтому нашу разработку лучше сохранить как шаблон. В этом случае для создания нового документа потребуется лишь двойной щелчок на пиктограмме шаблона. В результате на его основе будет создана новая рабочая книга (сам шаблон остается без изменений). Внеся в созданную книгу текст документа, автор сможет затем отправить ее получателям, например по электронной почте.	»
Глава 6
Задача управления ресурсами
В этой главе мы рассмотрим достаточно интересную разработку, позволяющую автоматизировать процесс составления расписания занятий в учебном заведении (это может быть вуз, колледж, школа и др.). Фактически мы попробуем построить информационную систему для эффективного управления ресурсами. При этом основным ресурсом будет фонд аудиторий, где мы должны организовать учебный процесс, а в понятие управления вкладывается создание разнообразных сервисных функций для пользователя, необходимых ему при составлении расписания учебных занятий, например: создание интеллектуальных форм для ввода данных, представление имеющейся информации в виде разнообразных отчетов, удобные возможности корректирования уже имеющейся информации.
Как вы увидите, решение рассматриваемой задачи приводит к разработке сложного управления информационной базой. Целью управления является оптимизация расписания учебных занятий по группам учащихся, по фонду аудиторий и по преподавателям. Большинство процедур, составляющих данную разработку, достаточно велики и поэтому вынесены в приложения 1—9.
В то же время в содержании главы приводится подробный комментарий всех основных программных конструкций.
Автоматизированная книга включает в себя множество листов, электронных форм ввода и разнообразных отчетов. Разработанные алгоритмы позволяют пользователю исключать ошибки и принимать правильные решения при составлении расписания занятий и подборе аудиторий.
Функциональные возможности книги рассчитаны на различные категории пользователей. В связи с тем что все читатели книги знакомы с учебным процессом по школе, колледжу или вузу, перечисленные далее основные сервисные возможности разработки должны быть понятны:
□	ввод заявок на проведение учебных занятий с помощью электронной формы:
148
Глава 6
□	подбор свободных (близких по вместимости) аудиторий для занятий;
□	автоматический подбор аудитории при проведении занятий по одной дисциплине в нескольких группах (у одного преподавателя);
□	автоматическая подготовка печатной формы расписания по группам и потокам на базе введенных заявок;
□	контроль соответствия числа студентов и вместимости аудиторий с точки зрения более эффективного использования фонда аудиторий;
□	возможность быстрого получения информации о свободном фонде аудиторий;
□	удобная возможность корректировки расписания (в том числе перевод занятий из одних аудиторий в другие);
□	получение различных отчетов по информации, содержащейся в заявках.
Ввод начальной информации
Понятно, что рассматриваемая разработка требует некоторой начальной информации — о группах, фонде аудиторий и т. д. Фактически необходимы справочники по группам, аудиториям, преподавателям и т. д. Такие данные заносятся на второй лист книги; один из вариантов его заполнения представлен на рис. 6.1.
Рис. 6.1. Вариант заполнения второго листа книги
Задача управления ресурсами 149
Здесь в столбцы А и В нужно ввести информацию об имеющихся аудиториях (при этом в первый столбец заносится номер аудитории, а во второй — количество мест в ней). Важным моментом является то, что информация по аудиториям должна вводиться в порядке возрастания их вместимости. В дальнейшем это обеспечит подбор классов, максимально близких по числу мест к количеству студентов.
В столбец С следует занести номера учебных недель в семестре (нумерация недель достаточно широко распространена в учебных заведениях).
В столбце D располагаются учебные дни в течение недели, а столбец Е отводится для времени начала и окончания занятий. Так, во второй строке этого столбца отображается время начала первого занятия, в третьей строке — начало второго занятия и т. д. Сами занятия могут быть часовыми или двухчасовыми (пары). Начиная с 21-й строки (того же столбца Е) размещается время окончания занятий (соответственно, время окончания первого занятия, затем второго и т. д.). Эта информация в дальнейшем потребуется для отчета по расписанию (в нем как раз указывается время начала и окончания занятий).
В следующих столбцах располагаются другие списки: заявители (это могут быть названия факультетов или фамилии руководителей учебных программ), затем — преподаватели, группы и потоки (с указанием количества учащихся). Количество учащихся потребуется для подбора близкой по вместимости аудитории. В последнем столбце располагаются названия учебных дисциплин.
Примечание
Пустых ячеек внутри списков рассмотренных данных быть не должно. Пустая ячейка в столбце для всех приводимых далее процедур является индикатором того, что ниже этой ячейки данных уже нет.
Таким образом, второй лист книги представляет собой совокупность исходных данных для работы программы составления расписания и должен заполняться в первую очередь. Все рассматриваемые далее процедуры используют эту начальную информацию.
Перейдем к рассмотрению первого листа (рис. 6.2).
Традиционно в наших разработках на первом листе рабочей книги располагаются элементы управления, связанные с основными действиями пользователя, и здесь также не будет исключения.
Основное содержание первого листа — регистрация заявок на проведение учебных занятий и аудиторий, которые для этих занятий выделяются. В верхней части листа располагаются элементы управления (эта область выделена серой заливкой). Об этих элементах мы поговорим позднее, но уже из названий, видимых на рис. 6.2, понятны их функции.
ISO
Гпава 6
Рис. 6.2. Первый лист книги
Посмотрим теперь на информацию, расположенную, начиная с четвертой строки листа (третья строка отводится для заголовков столбцов). Здесь каждая строка содержит заявку на проведение определенного занятия — новая заявка вводится в очередную свободную строку на этом листе.
При этом информацию по заявке условно можно разделить на две категории:
О начальная информация о занятиях (номер, заявитель, преподаватель, день, время, группа, количество студентов в группе, название дисциплины и номера учебных недель, когда занятия должны проводиться);
□ информация об обслуживании данной заявки (обслужена ли она и номер аудитории, выбранной для проведения занятий по заявке).
Алгоритм подбора аудитории составляет важную содержательную часть выполненной разработки. Здесь учитывается много факторов — наличие групповых (для нескольких групп или потоков) лекций, наличие последовательных во времени занятий в группе (в этом случае подбирается одна аудитория — для исключения переходов из одной комнаты в другую) и ряд других факторов.
Так, в каждой строке столбцы G и Н отводятся для записи информации об обслуживании заявки (подобранной для нее аудитории). И если аудитория подобрана, то в столбец G программно записывается слово "да", а в следующий столбец вписывается номер аудитории.
Фактически, информация на первом листе представляет собой некоторую базу данных. Столбец Номер позволяет ввести для каждой заявки поясняющий числовой или текстовый номер. При этом для определенного блока заявок,
Задача управления ресурсами
151
если потребуется, можно указать один и тот же номер. Номер заявки определяет не ее уникальность, а принадлежность заявки к определенной группе или блоку. Уникальность записи о заявке — это фактически уникальность каждой строки Microsoft Excel.
Следующие столбцы содержат информацию о заявителе, преподавателе, дне и времени проведения занятий. Эта информация не требует ручного заполнения, а извлекается из предварительно заполненного второго листа, как описано ранее. Непосредственно ввод данных будет выполняться с помощью специально разработанной формы ввода. Например, при вводе фамилии преподавателя мы будем выбирать ее из списка, предварительно заполненного на втором листе.
В столбце F для каждой заявки указывается количество студентов, которые учатся в данной группе. Эта информация вносится автоматически после выбора названия группы (вы уже видели, что на втором листе присутствуют два связанных столбца — название группы и число студентов в ней). В столбцах, начиная с К, отмечаются недели, когда должны проводиться занятия по данной заявке. Звездочка в соответствующем столбце говорит о том, что на этой неделе занятие проводится (на рис. 6.2 для всех заявок звездочками отмечены занятия на первой и второй неделе).
Нумерация учебных недель является типичной для учебных заведений. Это связано с тем, что количество аудиторных часов для разных дисциплин по учебному плану неодинаково. В связи с этим какие-то дисциплины в семестре ограничены семью занятиями, а какие-то продолжаются в течение семнадцати недель. Что касается нулевой недели, то ее введение относится к ситуации, когда день начала семестра расположен в середине недели (подобную неделю иногда называют нулевой).
Рассмотрим элементы управления на рис. 6.2. Это три кнопки, которые на листе расположены в области первых двух строк. В табл. 6.1 приведены значения ИХ СВОЙСТВ Name И Caption.
Таблица 6.1. Значения свойств кнопок
Name	Caption
Input_New	Ввод новой заявки
Input_auditогiа	Подбор аудитории
De_lete	Снятие с обслуживания
Понятно, что заполнение информации о заявке и тем более подбор для нее подходящей аудитории требуют некоторой интеллектуальности алгоритма.
152
Гпава 6
Так, программа должна обнаруживать возможный ввод некорректных заявок. Например, при вводе очередной заявки преподаватель может быть в указанное время уже занят. Другая возможная ситуация — для указанной в заявке группы уже зафиксировано другое занятие в это время. Все эти и другие подобные ситуации создаваемая разработка должна отслеживать. При этом автоматическая блокировка подобных накладок не требуется, т. к. возможно, они закладываются в расписание не случайно.
Для исключения ручного изменения информации на первом листе в книге предусматривается установка защиты этого листа от изменений. А такие технические действия, как формирование новых заявок и подбор аудитории для них, выполняются с помощью экранных форм. При этом программные процедуры этих форм самостоятельно снимают защиту с листа. В следующем разделе мы рассмотрим одну из экранных форм.
Форма для ввода заявок
Форма, которую мы здесь рассмотрим, связана с вводом новой заявки на проведение занятий. Пользователю для вызова этой формы нужно просто щелкнуть на кнопке Ввод новой заявки. После этрго автоматически выполняется предопределенная процедура, приведенная в листинге 6.1.
j Листинг 6.1. Обработка щелчка на кнопке Ввод новой заявки
Private Sub Input_New_Click()
F_Add.Show
End Sub
Здесь F_Add — значение свойства Name формы, которую мы далее разработаем для ввода информации. Выполняется метод show этой формы, который загружает ее в память и отображает на экране. Фактически, для пользователя щелчок на кнопке ввода новой заявки приводит к появлению формы на экране.
С этим элементом мы еще не сталкивались, поэтому рассмотрим процесс его создания поподробнее. Вообще форму можно интерпретировать как контейнер для элементов управления. Такие элементы управления, как кнопки или текстовые окна, мы можем размещать не только на листе, но и в форме.
Итак, для создания программной формы необходимо перейти в редактор Visual Basic. Для этого в окне приложения Microsoft Excel выберем в меню Сервис пункт Макрос и далее пункт Редактор Visual Basic. Теперь в окне редактора программного кода в меню Insert (рис. 6.3) выберем пункт UserForm. В результате на экране появится пустая форма.
Задача управления ресурсами
153
Рис. 6.3. Создана новая форма
Рис. 6.4. Готовая форма для ввода заявок
154
Гпава 6
ПРИМЕЧАНИЕ
В форме, как и на рабочем листе, можно размещать различные элементы управления.
Размещение элементов в форме выполняется, как обычно. Для того чтобы добавить в форму, скажем, кнопку, следует выбрать ее на панели инструментов Элементы управления, а затем с помощью мыши разместить в форме. Далее можно изменять размеры кнопки и другие ее характеристики в окне свойств. Фактически работа с элементами управления в форме не отличается от работы с элементами, расположенными на листе Excel.
Готовая форма для ввода заявок, содержащая все необходимые элементы управления, показана на рис. 6.4.
Установим свойство Name формы в значение F_Add.
В верхней левой части формы располагаются два элемента управления '’флажок”. Свойство Name флажка Не проверять уникальность номера установим в значение ch_Nom. Если установить этот флажок, то при работе с формой не будет проверяться однозначность номера заявки. Если флажок не установлен, то программный код обеспечивает проверку уникальности номера заявки — при вводе заявки с номером, который уже до этого встречался, программная процедура выведет на экран предупреждающее сообщение. При этом, если потребуется, пользователь все равно сможет принять решение о записи заявки с таким номером.
Примечание
Практически во всех подобных ситуациях наш алгоритм не блокирует возможные некорректные действия, а лишь предупреждает пользователя о том, что они имеют место.
Примечание
При вводе группы заявок с одним номером полезно отключить эту функцию проверки, чтобы на экране не появлялось предупреждающее сообщение.
Флажок Не проверять преподавателя (Name = ch_Pr) позволяет исключить или сохранить контроль занятости преподавателя при вводе новой заявки. В обычном режиме форма обеспечивает (с помощью программной процедуры, которую мы рассмотрим далее) проверку занятости преподавателей. При этом, если в очередной заявке указана фамилия преподавателя, у которого уже есть другое занятие в это время, выводится сообщение.
Ниже рассмотренных флажков в форме расположен элемент "текстовбе окно" для ввода номера заявки (Name = Num_z) с поясняющей надписью Номер.
Задача управления ресурсами
Ниже поля Номер расположено несколько элементов "поле со списком" (в табл. 6.2 приведены значения их свойства Name). Для каждого подобного объекта слева имеется поясняющая надпись. При открытии формы эти элементы автоматически заполняются информацией со второго листа книги. Скажем, при щелчке на списке Преподаватель мы увидим фамилии преподавателей, предварительно внесенные нами на второй лист.
Таблица 6.2. Элементы "поле со списком"
Значение свойства Name
Надпись
Boss	Заявитель
Prepod	Преподаватель
Day	День
Time	Время
Group	Г руппа
Disp	Дисциплина
Ниже расположено текстовое окно Количество студентов (Name = col_stud).
В верхней части формы присутствует большой набор элементов "флажок". Каждый флажок предназначен для указания определенного номера недели, когда должно проводиться занятие. Значения свойства Name формируются как комбинация символов ch и номера недели: cho, chi, ch2 и т. д. Здесь предполагается, Что в семестре не больше 18 учебных недель, а отсчет начинается с нулевой недели.
Примечание
При необходимости можно легко скорректировать форму для большего количества учебных недель.
Ниже флажков расположены два элемента "надпись" (в форме они выделены цветом, отличным от цвета фона). Эти элементы будут использоваться программно, поэтому важны значения их свойств Name (табл. 6.3).
Таблица 6.3. Элементы "надпись"
Значение свойства Name	Надпись
L_group	Заявки в группе
ь_ргер	Заявки преподавателя
6 Зак 925
156
Гпаев 6
Также в форме расположены два списка (белые), с помощью которых при вводе новой заявки автоматически отображаются уже имеющиеся занятия в рассматриваемой группе и у выбранного преподавателя: Name » Lis_Gr (для группы) и Name » Lis_Pr (для преподавателя).
В правом верхнем углу формы расположены четыре кнопки, которые позволяют устанавливать флажки недель по определенному принципу: включить все недели, исключить все недели, установить только четные или только нечетные недели. К этим кнопкам нет обращения из программного кода, поэтому их имена здесь не указаны (они могут быть любыми).
В нижней части формы располагаются три важные функциональные кнопки. При щелчке на кнопке Выход (Name ~ com_out) форма просто закрывается, и никакой записи информации в базу данных первого листа не производится. В листинге 6.2 приведен текст предопределенной процедуры для обработки щелчка на кнопке Выход. Метод Hide позволяет закрыть форму и вернуться на рабочий лист.
| Листинг 6.2. Обработка щелчка на кнопке Выход	|
Private Sub CcnuOut_Click()
F_Add.Hide
End Sub
Другие две кнопки позволяют перенести на рабочий лист данные, внесенные пользователем в форму. При этом одна из кнопок (Зафиксировать и ввести следующую, Name = comjsrext) после записи оставляет форму активной, а другая (Name = Com_wr0ut) закрывает ее.
С формами, как и с элементами, связано много различных событий. Одно из событий, наиболее часто используемых в программировании, — активизация формы. Как вы видели (см. листинг 6.1), по щелчку на кнопке Ввод новой заявки выполняется метод show формы, который и приводит к ее активизации. Для дальнейшей работы нам необходимо заполнить списки преподавателей, групп и т. д. Данные для заполнения при этом берутся со второго листа, как уже говорилось. При активизации формы автоматически выполняется предопределенная процедура userForm_Activate; ее текст приведен в листинге 6.3.
| Листинг 6.3. Процедура, выполняемая при активизации формы ввода заявок
Private Sub UserFomcActivate () Num_Z.Text = ""
Ch_Nom.Value = True ' Установка флажков
Задача управления ресурсами
157
Ch_Pr.Value = False ChO.Value = False Chi.Value = False Ch2.Value = False Ch3.Value = False Ch4.Value = False Ch5.Value = False Ch6.Value = False Ch7.Value = False Ch8.Value = False Ch9.Value = False ChlO.Value = False Chll.Value « False Chl2.Value = False Chl3.Value = False Chl4.Value = False Chl5.Value = False Chl6.Value = False Chl7.Value = False Заполнение списка заявителей N = О
While Worksheets(2).Cells(N + 2, 6).Value <> "• N » N + 1
Wend Boss.Clear For i = 1 To N
Boss.Additem Worksheets(2).Cells(i + 1, 6).Value Next Заполнение списка преподавателей N = О While Worksheets(2).Cells(N + 2, 7).Value <> ""
N = N + 1 Wend Prepod.Clear For i = 1 To N
Prepod.Additem Worksheets(2).Cells(i + 1, 7).Value Next Заполнение списка учебных дней N = О
While Worksheets(2).Cells(N + 2, 4).Value <> "" N = N + 1
Wend
Day.Clear
For i = 1 To N
Day.Additem Worksheets(2).Cells(i + 1, 4).Value Next ' Заполнение списка занятий N = О While Worksheets(2).Cells(N + 2, 5).Value <> ""
N = N + 1
Wend
Times.Clear For i = 1 To N
Times.Additem Worksheets(2).Cells(i + 1, 5).value Next
• Заполнение списка названий групп N = О
While Worksheets(2).Cells(N + 2, 8).Value <> nn
N = N + 1
Wend
Group.Clear For i = 1 To N
Group.Additem Worksheets(2).Cells(i + 1, 8).Value Next
* Заполнение названий дисциплин N = О While Worksheets(2).Cells(N + 2, 10).Value <> nn N = N + 1
Wend
Disp.Clear For i = 1 To N
Disp.Additem Worksheets(2).Cells(i + 1, 10).Value Next Col_Stud.Text = "" End Sub
Выполнение рассмотренной процедуры приводит к тому, что при активизации формы ввода все расположенные на ней списки автоматически заполняются.
Задача управления ресурсами 159
Перейдем к процедуре обработки щелчка на кнопке Зафиксировать и ввести следующую.
Примечание
Эта процедура велика по объему, поэтому ее полный текст приведен в приложении 1, а здесь лишь пояснено, как она организована и прокомментированы ее основные программные конструкции.
В начале процедуры подсчитывается количество уже имеющихся заявок на первом листе:
N = О
While Worksheets(1).Cells(N + 4, 1).Value <> ""
N = N + 1
Wend
Это делается для того, чтобы записать новую заявку в очередную свободную строку. Однако до этого проверяется, введены ли все данные: номер заявки, преподаватель, группа и т. д. Например, в следующем фрагменте показана реакция процедуры на ситуацию, когда не введен номер заявки:
If Num_Z.Text = "" Then
MsgBox (”Введите номер заявки")
Exit Sub
End If
Что касается полей co списками, то для них индикатором выбора элемента в списке является значение свойства Listindex (номер выбранного элемента): -1 означает, что в списке не выбран ни один элемент. Например, если не указан день, то следующая конструкция выводит соответствующее сообщение и процедура на этом завершается:
If Day.Listindex = -1 Then
MsgBox ("Выберите день")
Exit Sub
End If
Программный фрагмент проверки ввода числа студентов немного сложнее. Так, для дальнейших действий в этом поле обязательно должно быть число, и это проверяется с помощью внутренней функции isNumeric:
If IsNumeric(Col_Stud.Text) = False Then
MsgBox ("Введите число студентов")
Exit Sub
End If
160
Гпава в
Ранее вы познакомились с функцией isNumeric, которая возвращает значение False, если входной параметр не является числом. Таким образом, если вместо количества студентов пользователь введет строку с включением букв или других символов, то процедура воспримет подобную информацию как некорректную.
Итак, мы рассмотрели так называемый блок предварительной проверки данных.
Далее в процедуре, приведенной в листинге П1.1 (см. приложение 1), идет фрагмент, позволяющий выявить противоречия с уже имеющимися данными. Для этой проверки вводится переменная key, которая в начале проверки принимает значение 0, а если в процессе просмотра имеющихся заявок обнаруживается накладка (или по номеру заявки, или по преподавателю, или по группе), программно устанавливается в значение 1. Это является индикатором для вывода информационного сообщения в форму в конце процедуры. Сама проверка технически достаточно проста — проверяется, есть ли в указанное время занятия в выбранной группе и у данного преподавателя. Однако несколько деталей мы все же проясним.
Так, в начале процедуры определены массивы mass и mass2. При вводе новой заявки процедура просматривает все предыдущие, проверяя, нет ли накладок в расписании по преподавателю и группе. Допустим, преподаватель может вести занятие для нескольких групп. Тогда при вводе новой заявки, если у преподавателя уже есть заявка на это время, в массиве mass запоминается ее строка на первом листе книги, а в счетчик заявок chumass добавляется 1. Например, если в результате просмотра всех имеющихся заявок в переменной Ch_jtnass будет число 5, это говорит о том, что у преподавателя в это время уже есть 5 других занятий (такое возможно при проведении занятия для нескольких групп одновременно). В конце процедуры на экран будет выведено одно сообщение с упоминанием обо всех этих заявках
Массив mass2 предназначен для проверки накладок по группе. Если у рассматриваемой группы уже есть заявка на это время, то в массиве mass2 запоминается номер строки этой имеющейся заявки, а в счетчик заявок Ch_ma3s2 добавляется 1. Например, если в результате просмотра всех имеющихся заявок в переменной ch_mass2 будет число 1, это говорит о том, что у группы в это время уже есть другое занятие. В конце процедуры на экран выводится окно сообщения с упоминанием обо всех этих заявках. Фактически, предназначение массивов — служить буфером для хранения информации, который очищается в конце процедуры.
Учитывая большой объем данных на первом листе, разумно установить защиту листа от изменений (мы уже говорили, каким образом это можно
Задача управления ресурсами
161
сделать в Microsoft Excel). Теперь, когда процедура будет записывать очередную строку с заявкой на лист, необходимо сначала снять защиту, а уже после этого записать строку. Для снятия защиты с первого листа используется следующий метод:
Worksheets(1).Unprotect
Далее, после снятия защиты производится перенос информации из элементов формы в новую строку заявки рабочего листа.
Теперь несколько слов о завершении процедуры. Если накладок нет, то заявка, созданная в форме, просто остается записанной на первом листе. Если обнаруживается противоречие по группе или преподавателю, то предлагается либо удалить заявку, либо продолжить ее корректировать, либо просто ее оставить на листе. Это реализуется с помощью уже известной вам стандартной функции:
inform = МздВохСЕсли все равно записать, то нажмите — Да. " + _
" Если продолжить редактировать, то нажмите - Отмена. " + _
" Если удалить заявку, то нажмите - Нет. ", vbYesNoCancel)
В этом месте процедуры на экран выводится стандартное диалоговое окно с кнопками Да, Нет и Отмена. В случае выбора варианта Отмена либо Нет выполняется очистка только что введенных данных на листе:
If inform = vbNo Or inform = vbCancel Then
For i = 1 To 28
Worksheets(1).Cells(N + 4, i).Value = ""
Next
End If
В этом случае пользователь может отредактировать имеющуюся заявку в форме либо создать новую. А если накладок нет, то набранная заявка просто остается записанной на первом листе.
Рассмотрим еще одну сервисную возможность при работе с формой ввода заявок. При вводе номера заявки для удобства работы пользователя поля со списками автоматически заполняются данными из ближайшей (к началу листа) заявки с подобным номером. Для этого используется предопределенная процедура, которая автоматически выполняется при изменении информации в текстовом окне с номером заявки (Name = Num_z). Полный текст процедуры Num_z_change приведен в приложении 1, а здесь поясняются ее основные конструкции.
В начале процедуры подсчитывается количество данных, имеющихся на втором листе. Далее в строке
N_text = Len(Num_Z.Text)
162
Гпава в
с помощью внутренней функции ьеп вычисляется длина текста, набранного в окне для номера заявки. После этого в цикле
For i » 1 То N ' Цикл по заявкам на первом листе
frame_text « Mid(Worksheets(1).Cells(i + 3, 1).Value, 1, N_text)
отыскивается ближайшая заявка по набранному номеру (либо по части набранного номера). Теперь осталось заполнить поля формы информацией из ближайшей имеющейся заявки с подобным номером.
И еще об одном ресурсе ввода новых заявок. В центре окна, показанного на рис. 6.4, расположены два элемента типа "список" (их оттенок отличается от цвета фона). При вводе фамилии преподавателя в список Lis_Pr автоматически заносятся уже имеющиеся у этого преподавателя занятия на данный день (если день выбран). Понятно, что это является хорошей информативной подсказкой для того, кто составляет расписание, — видя занятость преподавателя, можно составить его расписание более компактно. Предопределенная процедура, позволяющая это реализовать, приведена в Листинге 6.4.
| Листинг 6.4. Процедура, выполняемая при изменении списка преподавателей
Private Sub Prepod-Change()
’ Подсчет числа заявок на первом листе
N = О
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
Lis_Pr.Clear ' Очистка списка для преподавателя
For i = 1 То N ' Цикл по заявкам
If Worksheets(1) .Cells(i + 3, 4) .Value = Day.Text And _
Worksheets(1).Cells(i + 3, 3).Value = Prepod.Text Then
' Если найдено занятие для указанного преподавателя,
' то оно вносится в список
Lis_Pr.AddItem Worksheets(1).Cells(i + 3, 5).Value + " " + _
Worksheets(1).Cells(i + 3, 10).Value + " " _
+ Worksheets(1).Cells(i + 3, 9).Value
End If
Next
L_prep.Caption = Prepod.Text
End Sub
Задача управления ресурсами
163
Аналогичным образом заполняется список Lis_Gr, когда мы выбираем группу в элементе Group (листинг 6.5).
Листинг 6.5. Процедура, выполняемая при изменении списка групп учащихся
Private Sub Group_Change()
N = 0 ' Подсчет количества заявок
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
Lis_Gr.Clear
For i = 1 To N ' Цикл по заявкам
If Worksheets(1).Cells(i + 3, 4).Value = Day.Text And _ Worksheets(1).Cells(i + 3, 9).Value « Group.Text Then ' Внесение в список занятия для данной группы
Lis_Gr.Additem Worksheets(1).Cells(1 + 3, 5).Value + " " + _ Worksheets(1).Cells (i + 3, 10).Value
End If
Next
L_group.Caption » Group.Text
If Group.Listlndex > -1 Then
Col_Stud.Text = Worksheets(2).Cells(Group.Listindex + 2, 9).Value End If
End Sub
В этой процедуре, кроме автоматического заполнения списка групп, заполняется текстовое окно coi_stud (количество студентов).
Понятно, что при смене дня в форме списки Lis_Pr и Lis_Gr должны также автоматически заполняться заново. Предопределенная процедура, выполняемая при выборе другого дня в соответствующем списке, компонуется из фрагментов процедур Prepod_change и Group_change; ее текст приведен в приложении 1.
На рис. 6.5 показана заполненная форма ввода новой заявки. Видно, что списки по указанной группе и выбранному преподавателю автоматически заполнились уже имеющимися заявками. Теперь можно зафиксировать ее на первом листе щелчком по одной из двух кнопок для записи заявки.
Подведем итоги. Мы познакомились с процедурами, связанными с формой для ввода заявок. Однако, несмотря на внешне привлекательный вид электронной формы и некоторые сервисные возможности, подобное заполнение заявок при активной работе пользователя является несколько примитивным.
164
Гпаев 6
Рис. 8.6. Заполненная форма ввода новой заявки
В дальнейшем мы рассмотрим более удобную возможность формирования новых заявок на базе имеющихся. При этом наши действия будут аналогичны функциям команд Копировать и Вставить меню. В этом случае при минимуме действий со стороны пользователя автоматически будет формироваться новая строка на первом листе, частично заполненная информацией. Стоит заметить, что в ряде ситуаций свои преимущества имеет и рассмотренная здесь форма ввода заявок.
Форма для подбора аудитории
В этом разделе мы рассмотрим один из наиболее интересных компонентов разработки — форму, позволяющую подобрать наиболее подходящую аудиторию для обслуживания заявки. Сама форма с разнообразными элементами управления приведена на рис. 6.6, а для ее активизации на первом листе имеется соответствующая кнопка. В листинге 6.6 приведен текст несложной процедуры, позволяющей вывести рассматриваемую электронную форму
Задача управления ресурсами 165
на экран. Из текста видно, что свойство Name формы подбора аудитории установлено в значение F_Podbor.
........... .. .......Г»...	.
Листинг 6.6. Обработка щелчка на кнопке Подбор аудитории на первом листе
........ ..............
Private Sub Input_auditoria_Click()
F_Podbor.Show
End Sub
Рис. 6.6. Форма для подбора аудитории
Перейдем к рис. 6.6 и последовательно рассмотрим ее основные элементы.
В левом верхнем углу находится список Номер строки (Name = Nunk_str). Этот список при активизации формы автоматически заполняется заявка-
166
Гпава 6
мм, для которых еще не подобрана аудитория (точнее, не самими заявками, а номерами строк первого листа, где эти заявки расположены). В дальнейшем, выбрав (выделив) в списке номер заявки, мы будем подбирать для нее наиболее подходящую аудиторию.
Понятно, что при большом количестве заявок удобнее обслуживать их отдельно по конкретной группе или по конкретному преподавателю. Для этого предназначены шесть элементов управления, расположенных справа от списка заявок: кнопка, 3 переключателя и 2 поля со списком. В табл. 6.4 приведены значения свойства Name для этих элементов.
Таблица 6.4. Элементы управления для отбора заявок
Элемент управления	Значение свойства Name	Назначение
Переключатель Все	Opti	Включение всех заявок
Переключатель По группе	Opt 2	Включение заявок по выбранной группе
Переключатель По преподавателю	Opt2	Включение заявок по преподавателю
Кнопка Включить	Com_Otbor	Заполнение списка Nuitt_str
Поле со списком (верхнее)	Sel_Gr	Список групп для отбора
Поле со списком (нижнее)	Sel_Pr	Список преподавателей для отбора
Группа из трех переключателей позволяет выбрать вариант работы с заявками — либо включать в список Num_str их все, либо только по конкретному преподавателю или по определенной группе.
Например, мы хотим, чтобы в списке Num_str отразились только те заявки, которые относятся к группе ЗА1. В этом случае следует щелкнуть на переключателе По группе (opt2), а затем выбрать интересующую нас группу в правом поле со списком. Теперь с помощью кнопки Включить можно заполнить список Num_str только заявками по группе ЗА1.
Аналогичным образом можно включить в список только заявки для определенного преподавателя. А если далее мы хотим продолжить работу' со всеми оставшимися заявками, то следует выбрать переключатель Все (opti) и щелкнуть на кнопке Включить.
Задача управления ресурсами
167
В левой части рис. 6.6 расположена группа элементов "надпись" — они предназначены для отображения параметров заявки, выбранной в списке Num_str. Эти элементы (табл. 6.5) выделяются цветом на фоне формы, слева от них расположены названия. На рис. 6.7 показана ситуация, когда после указания в списке Num_str номера строки заявки ее параметры отображаются в соответствующих надписях.
Рис. 6.7. Пример выбора строки заявки
Теперь перейдем к элементу "рамка" Поиск аудитории, который включает несколько объектов. В верхней части этого условного контейнера объектов располагается кнопка Начать (Name = Begin_Poisk), щелчком, по которой запускается алгоритм подбора аудитории для указанной в списке Num_str заявки.
168
Гпава 6
Таблица 6.S. Назначение элементов "надпись"
Значение свойства наше	Назначение
Num_z	Номер
Boss	Заявитель
Prepod	Преподаватель
Day	День
Times	Время начала занятия
Group	Г руппа
Ned	Недели занятий
Disp	Дисциплина
Col_Stud	Количество студентов
Часто при поиске не обязательно требуется отбирать все возможные аудитории по конкретной заявке на занятие (чтобы ускорить поиск, можно ограничиться и меньшим их количеством). Для реализации подобной возможности в программе предусмотрены два флажка (в форме они располагаются ниже кнопки Начать), позволяющие ограничить подбор аудиторий для указанной заявки одной либо тремя, ближайшими по вместимости. Значения свойств этих флажков указаны в табл. 6.6.
Таблица 6.6. Значения свойств флажков
Name	Caption
Ch_3A	Подбирать не более 3 аудиторий
Ch_lA	Подбирать не более 1 аудитории
При большом объеме данных эти флажки позволяют значительно ускорить процесс подбора аудиторий.
Теперь еще об одном флажке — Не обрабатывать последоват-ные заявки (Name = ch_Posl). Частр у определенной группы в течение дня есть несколько последовательных по времени занятий (только для этой группы). В подобном случае удобнее назначить всем этим занятиям одну аудиторию (студентам не потребуется переходить из одного помещения в другое).
Правда, есть и ситуации, когда этот режим необходимо исключить. Например, нет свободной аудитории для всех последовательных по времени занятий. Или определенное занятие обязательно должно проводиться в конкретной
Задача управления ресурсами 1б9
аудитории (например, занятия по информатике следует проводить в компьютерном классе). В этом случае флажок Не обрабатывать последоват-ные заявки следует установить. А если этот флажок не установлен, то поиск свободной аудитории будет производиться для всех последовательных занятий группы в течение дня.
Кроме последовательных во времени заявок программа обнаруживает совместные заявки на одно занятие для нескольких групп и подбирает им одну (достаточно вместительную) аудиторию. Так. при выборе в списке Num_str заявки для обслуживания возможна ситуация, когда у указанного преподавателя есть аналогичное занятие и в других группах. Эту ситуацию программа видит (при выделении одной из таких групповых заявок в списке Num_str) и запоминает во внутренней структуре данных. В дальнейшем по щелчку на кнопке Начать производится поиск общей аудитории для всех этих групп. Для включения или, наоборот, исключения такой возможности обслуживания заявок используется флажок Не обрабатывать групповые (Name = ch_Group). На практике в ряде ситуаций может потребоваться установить данный флажок.
Продолжим обсуждение элементов, находящихся в рамке Поиск аудитории формы. Элемент типа "список" (Name = L_otbor), в который процедура записывает аудитории, подходящие для заявки, расположен в правой части рамки и выделен светлым фоном. Действия пользователя заключаются в указании конкретной аудитории в этом списке (следует выделить одну из подходящих аудиторий щелчком). Элемент управления "надпись" Вместимость (Name = inf_vmesti) служит для отображения вместимости выбранной аудитории в списке L_otbor.
Теперь пользователю следует нажать кнопку Записать аудиторию (Name = com_writei), что позволит записать аудиторию, выбранную в списке, в строку заявки на первом листе.
Важно отметить следующую особенность, о которой уже говорилось. При выборе в списке Num_str заявки для обслуживания алгоритм автоматически просматривает наличие групповых занятий (одно занятие для нескольких групп) и занятий, последовательных во времени. Эта ситуация запоминается во внутренней структуре данных, которая будет в дальнейшем использоваться при подборе аудитории. •
В самой нижней части экрана расположен элемент "надпись" (Name = inf_z). предназначенный для вывода информационных сообщений о наличии групповых и последовательных по времени заявок. Заполнение этого элемента производится при щелчке на списке Num__str. В этом случае указывается, какие заявки комбинируются с выбранной (рис. 6.8 и 6.9).
170
Гпава 6
Рис. 6.8. Для текущей заявки есть одна совместная (одно занятие для нескольких групп)
Рис. 6.9. Результат щелчка на кнопке Начать — в этом случае подбираются аудитории, подходящие по вместимости для двух групп
Задача управления ресурсами
171
Группа переключателей (табл. 6.7) позволяет ограничить поиск аудитории определенным корпусом или произвести поиск аудитории во всех корпусах.
Таблица 6.7. Значения свойств переключателей
Name	Caption
Corpus1	1 корпус
Corpus2	2 корпус
Corpus3	3 корпус
Corpus4	4 корпус
All_Corpus	Все корпуса
В правой части формы подбора аудитории располагается рамка Выбор аудитории, элементы которой позволяют обеспечить выбор аудитории напрямую, без алгоритма подбора (если для определенного занятия требуется конкретная аудитория, такая возможность может оказаться весьма полезной). Здесь применяются алгоритмы проверки занятости, а также наличия групповых и последовательных по времени занятий.
Ключевой элемент в правой рамке — поле со списком Аудитория (Name = vibor_room). От пользователя требуется щелчком выбрать в этом списке необходимую аудиторию для обслуживания заявки (которую он предварительно указал в списке заявок Номер строки). После выбора аудитории в затемненной надписи Вместимость (Name = inf_vmest2) программная процедура отобразит количество мест в этой аудитории.
Следующее возможное действие пользователя заключается в проверке — занята аудитория или нет, для чего следует щелкнуть на кнопке Проверить (Name = com_Test). Над кнопкой Записать аудиторию расположен элемент управления "надпись" (Name = inf_zan2), в котором отображается результат проверки — свободна аудитория или занята.
Понятно, что в случае занятости аудитории, хотелось бы получить ответ на вопрос — кем? Для этого в форме есть кнопка Отчет (Name = comjResui t). В этом случае в списке (Name = L_otchet), расположенном в нижней части формы (под переключателями с номерами корпусов) отображаются занятия, которые проводятся в данной аудитории. Кнопка Записать аудиторию (Name = Com_write2) позволяет записать выбранную аудиторию в строку на первом листе, соответствующую данной заявке.
На рис. 6.10 показана ситуация выбора аудитории для занятия в рамке Выбор аудитории. Здесь мы можем указать эту аудиторию для занятия, несмотря
172
Гпава 6
на то. что вместимость указанной аудитории (2118) несколько меньше количества студентов при совместном занятии.
Итак, мы рассмотрели основные элементы управления, присутствующие в форме, и можем перейти к описанию программного кода.
По щелчку на кнопке Подбор аудитории на первом листе происходит активизация этой формы. В этом случае выполняется предопределенная процедура userFornuActivate (ее текст приводится в листинге 6.7).
Рис. 6.10. Выбор аудитории в рамке Выбор аудитории
Листинг 6.7. Процедура активизации формы подбора аудитории
Private Sub UserFonn_Activate()
' Активизация переключателя "1 корпус" для подбора аудитории
Corpus1.Value = True
Задача управления ресурсами
173
Подсчет числа групп N = О
While Worksheets(2).Cells(N + 2, 8).Value о ""
N = N + 1
Wend
Заполнение списка групп
Sel_Gr.Clear
For i = 1 To N
Sel_Gr.AddItem Worksheets(2).Cells(i + 1, 8).Value Next Подсчет числа преподавателей N = О While Worksheets(2).Cells(N + 2, 7).Value <> "" N = N + 1 Wend Заполнение списка преподавателей Sel_Pr.Clear For i = 1 To N
Sel_Pr.Additem Worksheets(2).Cells(i + 1, 7).Value Next Подсчет числа заявок на первом листе N = О
While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1
Wend
Подсчет числа аудиторий
N_roctms = О
While Worksheets(2).Cells(N_rooms + 2, 1).Value <> "" N_rooms = N_rooms + 1
Wend
Заполнение списка заявок Num_Str.Clear For i = 1 To N
If Worksheets(1).CellsCi + 3, 7).Value = "” Then
Nunt-Str.Additem Worksheets(1).Cells(i + 3, 1).Row End If Next Заполнение списка аудиторий Vibor_room.Clear
174
Глеев 6
For i = 1 То N_rooms Vibor_room.AddItem Worksheets(2).Cells(i + 1, 1).Value
Next
End Sub
Действия, выполняемые в данной процедуре, достаточно просты, поэтому мы ограничимся комментарием, присутствующим в тексте листинга.
Перейдем к процедуре, выполняемой по щелчку на списке Num_str (Номер строки), текст которой достаточно велик (см. приложение 2), и прокомментируем ее основные программные конструкции.
В начале процедуры в элементы "надпись" формы записывается информация о выбранной заявке. Например, для записи
Boss.Caption = Worksheets(1).Cells(select_vibor, 2).Value
заполняется поле заявителя в форме (элемент "надпись" с именем Boss). Далее, в цикле в надпись для сообщений (Ned) записываются номера недель, когда занятия будут проводиться:
For i = 11 То 28
If Worksheets(1).Cells(select_vibor, i).Value <> "" Then
Ned.Caption = Ned.Caption + CStr(i - 11) +
End If
Next
Как уже говорилось, если на первом листе в соответствующей ячейке присутствует символ "звездочка", то занятие на этой неделе есть.	,
Для отслеживания последовательных и групповых занятий в разделе General определяются: счетчики количества групповых (N_Group) и последовательных во времени (n_pos1) занятий; два массива — для номеров строк заявок с общим одновременным занятием в одной аудитории (Mass_Group) и для номеров строк последовательных по времени занятий для одной группы (Mass_Posl). На рис. 6.11 показана область описания общих переменных для рассматриваемой формы.
Основной цикл процедуры Num_str_ciick состоит в переборе всех необслу-женных заявок на первом листе. В начале этой процедуры значение переменной N_Group устанавливается в 0, а при обнаружении такого же занятия (с тем же названием и у того же преподавателя) в другой группе увеличивается на11.
Аналогично, индикатором для последовательных по времени заявок служит переменная n_pos1, значение которой также в начале устанавливается в О, а при обнаружении соседнего во времени занятия в той же группе увеличивается на 1.
Задача управления ресурсами
175
Рис. 6.11. Область General
Если у выбранной заявки в списке Num_str есть совместные занятия, то они выводятся в элемент "надпись", расположенный в нижней части формы:
If NjGroup > 0 Then
inf_z.Caption = "Совместные заявки в строках "
End If
For i = 1 То NjGroup
•. Корректировка числа студентов
Col_Stud.Caption = CInt(Col_Stud.Caption) + _
Worksheets(1).Cells(Mass_Group(i), 6).Value
' Перечисление строк групповых заявок на первом листе
inf_z.Caption = inf_z.Caption + Str(Mass_Group(i)) +
Next
Примечание
Здесь суммируется количество студентов во всех объединяемых группах; результат отображается в надписи Col.stud.
Аналогичным образом проверяется наличие последовательных по времени занятий для одной группы. Заметим, что при этом сначала выполняется поиск групповых заявок, а если групповых заявок не обнаружено, то выполняется поиск последовательных по времени занятий для одной указанной группы.
Таким образом, если выделить в списке одну из заявок, то в предопределенной процедуре, обрабатывающей щелчок в списке Num_str (Номер строки), выполняются следующие действия:
1.	Информационные надписи (в левой части формы) заполняются данными заявки на форме.
2.	Проверяется наличие групповых заявок, и если они есть, то в массив Mass_Group записываются номера строк, в которых эти заявки расположены
176
Гпава 6
на первом листе; количество групповых заявок отображается в переменной N_Group.
3.	Если групповых занятий нет, то проверяется наличие последовательных во времени заявок. При их обнаружении в массив Mass_Posi записываются номера строк, в которых расположены эти заявки. Количество последовательных по времени заявок отображается в переменной n_pos1.
4.	Информация об имеющихся групповых или последовательных занятиях выводится в информационную надпись, расположенную в нижней части экрана.
Итак, активизируя в списке Num_str определенную заявку, мы видим на экране ее параметры и информацию о наличии групповых или последовательных по времени (связанных) заявок. Понятно, что информация о последовательных и групповых заявках должна быть известна и процедурам, связанным с их обслуживанием, а именно — процедуре поиска аудитории и процедуре записи выбранной аудитории. Поэтому память под переменные и массивы для рассматриваемой формы мы и отвели в общей области определения.
Таким образом, в результате описанных действий мы подготовились к процедуре, выполняемой при щелчке на кнопке Начать, запускающей алгоритм поиска подходящих аудиторий для указанной заявки. Эта процедура Begin_Poisk_ciick полностью приведена в приложении 2, здесь мы прокомментируем лишь ее основные моменты. Так, в начале процедуры проверяется — сделан ли выбор заявки, и если нет, то процедура завершается, т. к. обслуживать нечего:
If NuxnjStr. Liat Index. Lie t Index » -1 Then
MsgBox ("He выбран номер строки заявки")
Exit Sub
End If
Для подсчета количества найденных аудиторий используется переменная shot. Мы уже говорили, что флажки сь_за и сь_1а формы введены для ускорения поиска и позволяют ограничить список подходящих аудиторий одной либо тремя. Реализовать именно эту возможность и позволяет переменная shot.
Исходные данные формируются с учетом того, что номер аудитории может обозначаться четырехзначным числом или сочетанием четырех цифр и буквы, например, 1205 или 2401а. Первая цифра такой записи — номер корпуса, где находится аудитория. То есть для того, чтобы выяснить, в каком корпусе расположена та или иная аудитория, следует выделить первую цифру:
ayd = Worksheets(2).Cells(i + 1, 1).Value
If IsNumeric(ayd) = True Then
Задача управления ресурсами
177
ayd_Ch = ayd
Else
ayd_Ch = CInt(Mid(ayd, 1, 4))
End If
shif - ayd_Ch \ 1000
При наличии буквы в номере аудитории из него с помощью уже встречавшейся функции Mid извлекаются первые четыре символа, а затем операция целочисленного деления выделяет первую цифру из этих четырех. В зависимости от выбранного переключателя (корпус, где следует подобрать аудиторию) и этой цифры, аудитория либо принимается к дальнейшему рассмотрению, либо отбрасывается.
После этого в процедуре сравнивается количество мест в аудитории с числом студентов, и если аудитория мала, то она также не рассматривается. Это реализуется с помощью следующей строки, где учитывается, что количество мест в аудитории указывается во втором столбце на втором листе:
If Worksheets(2).Cells(i + 1, 2).Value < CInt(Col_Stud.Caption) Then
В следующей части процедуры при наличии последовательных по времени занятий проверяется, свободна ли аудитория для каждого занятия. Если хотя бы для одного занятия из рассматриваемой цепочки аудитория не подходит (занята другим занятием), то она также исключается из рассмотрения.
Заметим, что при необходимости можно подбирать аудитории без учета последовательных по времени занятий (флажок ch_posi установлен). По щелчку на кнопке Начать происходит заполнение списка L_otbor. В результате мы получаем рекомендуемый фонд аудиторий для обслуживания выбранного занятия. В случае, если переменная-счетчик числа аудиторий для занятия остается равной 0, программа выводит информационное сообщение:
If shot = 0 Then
inf_ayd.Caption » “Для данной заявки аудиторий нет"
End If
На рис. 6.9 была показана форма с подбором возможных аудиторий для указанной заявки. Далее пользователь должен щелчком в списке с отобранными аудиториями указать, какую конкретно он намеревается записать для обслуживаемой заявки.
При щелчке на списке выполняется предопределенная процедура L_otbor_click. Основное ее назначение — фиксация (для процедуры, выполняемой при щелчке на кнопке Записать аудиторию) конкретной аудитории для заявки, а также вывод информации о ее вместимости. Сама процедура приведена в листинге 6.8.
178
Глава 6
I Ди< тин! 6.8. Процедура обработки щелчка на списке L otbor	|
Private Sub L_otbor_Click()
• Подсчет числа аудиторий на втором листе N = О
While Worksheets(2).Cells(N + 2, 1).Value <> ""
N = N + 1
Wend
For i = 2 To N + 1
If Luotbor.Text = Worksheets(2).Cells(i, 1).Value Then
' При нахождении выбранной аудитории на втором листе Inf_vmestl.Caption = Worksheets(2).Cells(i, 2).Value Exit For
End If
Next
' Разрешается доступ к кнопке для записи аудитории Cont-Wri tel. Enabled = True
End Sub
Мы подошли к ключевой процедуре, определяющей запись аудитории в базу данных на первом листе. Она выполняется по щелчку на кнопке Записать аудиторию в рамке Поиск аудитории. Ее текст приведен в листинге 6,9.
I Листинг 6.9. Обработка щелчка на кнопке Записать аудиторию в рамке Поиск аудитории
Private Sub ConL.Writel_Click()
If L_otbor.ListIndex = -1 Then
' Для записи необходимо выбрать аудиторию MsgBox ("Не выбрана ни одна аудитория") Exit Sub
End If
Worksheets(1).Unprotect ' Снятие защиты
Inf_vmestl.Caption = "" 'Очистка информации о вместимости
inf_z.Caption = ""	' Очистка надписи для информационного сообщения
If Ch_Group.Value = True Then
N_Group = 0 ' Сбрасываем групповые заявки, если флажок установлен
End If	f
If Ch_Posl.Value = True Then
Задача управления ресурсами 179
N_Posl = 0 1 Сбрасываем последовательные заявки, ’ если флажок установлен
End If
If N_Group > 0 Then
Worksheets(1).Cells(CInt(NumJStr.Text), 7) = "да" ayd = L_otbor.Text
Worksheets(1).Cells(CInt(NUin_Str.Text), 8) = ayd ' Запись
For 'i = 1 To N_Group
Worksheets(1).Cells(Mass_Group(i), 7).Value = "да"
Worksheets(1).Cells(Mass_Group(i), 8).Value = L_otbor.Text Next
Else
For i = 0 To NJPosl
Worksheets(1).Cells(Mass_Posl(i), 7).Value = "да"
Worksheets(1).Cells(Mass_Posl(i), 8).Value = L_otbor.Text Next End If Coirv_Writel. Enabled = False Nun\_Str .Clear L_otbor.Clear If Optl.Value = False And Opt2.Value = _
False And Opt2.Value = False Then
Optl.Value = True
End If
vkl ' Обновление списка заявок на обслуживание End Sub
Наиболее интересный момент связан с обслуживанием групповых заявок. В переменной N_Group, как уже говорилось, предварительно сформировано (процедурой выбора заявки в списке заявок) количество групп для совместного занятия, а в массиве Mass_Group присутствуют номера этих групповых заявок.
В процедуре из листинга 6.9 аудитория сначала записывается для исходной заявки, а затем та же аудитория в цикле записывается и для всех совместных с ней заявок.
При отсутствии групповых заявок в процедуре рассматривается обслуживание последовательных по времени. Количество таких заявок уже сформировано в переменной n_pos1 при выборе заявки в списке заявок. Однако если
ISO Гпава 6 в форме установлен флажок запрета обслуживания подобных заявок ch_posi, то переменная n_pos1 принудительно сбрасывается в 0.
После обслуживания заявки (записи аудитории) происходит повторное заполнение списка заявок (т. к. некоторые из них мы только что обслужили), и пользователь может перейти к следующей. Для этого используется сервисная процедура vki, приведенная в листинге 6.10.
Листинг 610. Текст процедуры заполнения списка заявок	|
Sub vkl ()
N = 0
While Worksheets(1).Cells(N + 4, 1).Value <> ""
N = N + 1
Wend
NunuStr. Clear
’ Цикл по количеству заявок на первом листе
For i = 1 То N
al = Worksheets(1).Cells(i + 3, 7).Value
If al = "" Then
' Если заявка не обслужена
If Optl.Value = True Then
* Если установлен переключатель — все заявки
NunuStr .Additem Worksheets (1).Cells (i + 3, 1).Row
Elself Opt2.Value = True Then
' Если выбран переключатель "По группе"
а2 = Worksheets(1).Cells(i + 3, 9).Value
If a2 = Sel_Gr.Text Then
NunuStr .Additem Worksheets(1).Cells(i + 3, 1).Row
End If
Elself Opt3.Value = True Then
' Если выбран переключатель "По преподавателю"
а2 = Worksheets(1).Cells(i + 3, 3).Value
If a2 = Sel_Pr.Text Then
NuncStr.Additem Worksheets(1).Cells(i + 3, 1).Row
End If
End If
End If
Next
End Sub
Задача управления ресурсами 181
Перейдем к блоку элементов, расположенных в правой части формы (см. рис. 6.7). Как уже говорилось, кроме подбора аудитории иногда требуется рассмотреть конкретную аудиторию для проведения занятия (это может быть связано, например, с пожеланием преподавателя). В этом случае следует использовать элементы в правой части окна формы. Так, в списке vibor_room присутствуют все аудитории, которыми мы располагаем.
Последовательность действий в рамке Выбор аудитории такова. В списке заявок Номер строки мы выбираем заявку (как и раньше), а затем вместо щелчка на кнопке Начать выбираем в списке vibor_room,конкретную аудиторию. При выборе аудитории в поле Вместимость отобразится ее вместимость. Технически это реализуется с помощью процедуры, приведенной в листинге 6.11.
Листинг 6.11. Обработка щелчка на списке vibor_room
Private Sub Vibor_roorr\_Click ()
N = О
While Worksheets(2).Cells(N + 2, 1).Value <> ""
N = N + 1
Wend
For i = 2 To N + 1
If Vibor.jrocni.Text = Worksheets(2) .Cells(i, 1) .Value Then infjvmest2.Caption = Worksheets(2).Cells(i, 2).Value Exit For
End If
Next
End Sub
Далее, для того чтобы узнать — свободна она или нет, в форме присутствует кнопка Проверить, щелчок по которой предоставляет информацию о занятости (процедура, реализующая это действие, приведена в приложении 2). В каких-то случаях может понадобиться получить информацию о том, кто все-таки ее занял. Для этого в форме есть кнопка Отчет, щелкнув на которой можно получить полную информацию о том, какими группами аудитория занята.
Обслужим первую нашу заявку и введем еще одну (рис. 6.12).
Далее (рис. 6.13), при попытке поставить новое занятие в аудиторию 1203 появится сообщение, а при щелчке на кнопке Отчет будет предоставлена информация о занятости.
182
Гпава 6
Рис. 6.12. Заявка обслужена
Рис. 6.13. Аудитория занята
Задача управления ресурсами
183
Таким образом, мы рассмотрели возможности обслуживания заявки на занятие как путем автоматизированного подбора аудитории, так и с помощью самостоятельного выбора пользователем конкретной аудитории.
Примечание
Полный текст большинства процедур приведен в приложении 2, что связано с их объемом. Фактически информация, представленная в этом разделе, составляет наиболее существенную часть разработки.
Форма для снятия заявки с обслуживания
В форме, показанной на рис. 6.2, осталась одна не рассмотренная кнопка — Снятие с обслуживания. Ее функциональное назначение связано с необходимостью в ряде случаев снимать обслуживание заявок с подобранными аудиториями. В данном разделе мы рассмотрим электронную форму, позволяющую это сделать (рис. 6.14).
В листинге 6.12 приведен текст несложной процедуры, предназначенной Для вывода рассматриваемой электронной формы на экран. Из текста видно, что в качестве значения свойства Name для формы подбора аудитории выбрано F_Podbor.
Рис. 6.14. Форма, открываемая нажатием кнопки Снятие с обслуживания
164
Гпава 6
Листинг в.12. Обработка щелчка на кнопке Снятие с обслуживания на первом листе
Private Sub De_lete_Click()
F_NoService.Show
End Sub
Перейдем к рис. 6.14 и последовательно рассмотрим все показанные на нем элементы. В левом верхнем углу находится поле со списком Номер строки (Name » Nunu.str). Этот элемент при активизации формы (листинг 6.13) автоматически заполняется обслуженными заявками, для которых уже подобрана аудитория (конечно, не самими заявками, а номерами строк первого листа, где эти заявки указаны). В дальнейшем, выбрав (выделив) в списке номер заявки, мы можем снять ее с обслуживания с помрщью щелчка на кнопке Отменить заявку.
| Листинг 6.13. Процедура активизации формы отмены обслуживания заявок
Private Sub UserForncAetivate ()
' Подсчет числа заявок на первом листе
N = О
While worksheets(1).Cells(N + 4, 1).Value <> ""
N = N + 1
Wend
* Заполнение поля co списком
NumjStr. Clear
For i = 1 To N
If worksheets(1).Cells(i + 3, 7).Value <> "" Then
' Если заявка обслужена, то ее включаем в список
NumjStr.AddItem i + 3
End If
Next
End Sub
В процедуре из листинга 6.13 производится добавление в список номеров строк заявок с первого листа при условии, что в седьмом столбце присутствует отметка об обслуживании. Основную площадь формы на рис. 6.14 занимает группа элементов "надпись", предназначенных для отображения параметров заявки, выбранной в списке Num_str. Эти элементы (табл. 6.8) на рисунке выделяются цветом на фоне формы, сверху от них расположены названия.
Задача управления ресурсами		185
Таблица 6.8. Назначение надписей		
Значение свойства Name	Назначение	
Num_z	Номер
Boss	Заявитель
Prepod	Преподаватель
Day	День
Times	Время начала занятия
Group	Группа
Ned	Недели занятий
Disp	Дисциплина
После активизации формы на экране от пользователя требуется только выбрать номер строки обслуженной заявки щелчком в списке Num_str. В листинге 6.14 приведена процедура, которая автоматически выполняется по щелчку на этом элементе.
| Листинге 14 Процедура, выполняемая по щелчку на поле со списком
Private Sub NUm_Str_Click()
Num_Z .Caption = Worksheets(1) .Cells(CInt (Num_Str.Text), 1) .Value
Boss.Caption = Worksheets(1) .Cells(CInt(NumJStr.Text), 2) .Value
Prepod.Caption = Worksheets(1) .Cells(CInt(Nunv_Str.Text), 3) .Value
Day.Caption = Worksheets(1).Cells(CInt(NUm_Str.Text), 4).Value
Times.Caption = Worksheets(1) .Cells(CInt(NUm_Str.Text), 5) .Value
Disp.Caption = Worksheets(1).Cells(Clnt(Num_Str.Text), 10).Value
Group.Caption = Worksheets(1).Cells(CInt(Num_Str.Text), 9).Value
Ned.Caption » ""
Inform. Caption = ""
For i = 11 To 28
If Worksheets(1).Cells(CInt(Nurt\_Str .Text), i).Value <> "" Then
Ned.Caption = Ned.Caption + CStr(i - 11) +
End If
186
Глава 6
В начале процедуры в надписи формы записывается информация о выбранной заявке. Например, для записи
Prepod. Caption = Worksheets (1) .Cells (CInt (Nun\_Str. Text), 3).Value
в форме заполняется поле заявителя — элемент "надпись" с именем Prepod. Далее, в цикле в надпись Ned записываются номера недель, когда будут проводиться занятия. Теперь пользователь может снять данную заявку с обслуживания с помощью кнопки Отменить заявку (листинг 6.15).
Листинг 6.15. Обработка щелчка на кнопке Отменить заявку
Private Sub Ccn\_NoService_Click()
Inform.Caption = ""
If NunuStr.ListIndex = -1 Then
MsgBox ("He выбрана заявка")
Exit Sub
End If
• Снятие защиты с первого листа
Worksheets(1).Unprotect
Worksheets (1) .Cells (CInt (Nun\_Str.Text), 7) = ""
Worksheets(1).Cells(Clnt(Num_3tr.Text), 8) = ""
* Установка защиты первого листа
Worksheets(1).Protect DrawingObj ects:=True, _
Contents:=True, Scenarios:=True
N = 0
While Worksheets(1).Cells(N + 4, 1).Value <> ""
N = N + 1
Wend
NunuStr. Clear
For i = 1 To N
If Worksheets(1).Cells(i + 3, 7).Value <> "" Then
Nuirt-Str. Additem i + 3
End If
Next
Inform.Caption = "Заявка отменена"
End Sub
На рис. 6.15 показана ситуация, когда после щелчка на кнопке Отменить заявку произошло изменение на первом листе.
Задача управления ресурсами
187
Рис. 6.15. Заявка отменена
Итак, мы рассмотрели все действия, связанные с элементами управления на первом листе. Можно возразить в том смысле, что не было сказано ничего об удалении заявок в целом (всей строки) и об их коррекции (изменение преподавателя, дисциплины, номеров недель). Действительно, эти функции важны и они реализованы в книге. Однако реализованы на другом листе, что связано с удобством работы для пользователя.
Лист Расписание
В рассматриваемой книге Microsoft Excel много листов, реализующих разнообразные функциональные задачи по работе с расписанием занятий. В этом разделе мы рассмотрим одну из основных возможностей программы — составление расписания (как электронной формы, так и его печатного варианта). Для этого в программе используются три листа:
□	Расписание
□	Потоки
□	Печ. расп.
18S
Гпаев 6
Лист Потоки является вспомогательным и служит для задания потоков и групп, для которых мы намереваемся построить расписание занятий. Поэтому некоторые созданные нами ранее группы мы объединим в общий поток и внесем в лист Потоки (рис. 6.16). При этом структура листа такова: в первом столбце располагаются потоки, а в последующих столбцах соответствующей строки — группы, входящие в поток.
Примечание
Название потока может быть взято из списка групп (расположенного на втором листе книги), а может быть чисто символическим; запись в первом столбце даже может отсутствовать, но в последующих столбцах названия групп должны присутствовать (тогда они будут отражены в расписании).
Рис. 6.16. Фрагмент листа Потоки
Далее необходимо перейти на лист Расписание, выбрать на этом листе интервалы недель (рис. 6.17) и щелкнуть на кнопке Заполнить.
Из сопоставления рис. 6.12 и 6.17 видно, что созданные нами ранее заявки по указанным (на листе Потоки) группам попали в расписание. Фактически то, что мы видим на листе Расписание, — почти готовый вариант реального расписания (осталось лишь удалить с листа ненужную информацию).
Сначала рассмотрим элементы управления, показанные на рис. 6.17.
Поля со списками позволяют выбрать интервал недель, для которого мы хотим составить расписание. Значения свойства Name этих элементов выбраны соответственно ci и С2, а для кнопки Заполнить установим свойство Name в значение com_start. В табл. 6.9 перечислены значения свойств флажков, которые присутствуют на листе.
Задача управления ресурсами
189
Рис. 6.17. Лист Расписание
Таблица 6.9. Значения свойств флажков
Name	Caption
Chi	He выводить недели
Ch2	Указать номер строки
Ch3	Удалять пустые строки
Ch4	Только предметы
Ch5	Показывать необслуженные
Флажок Не выводить недели позволяет исключить вывод недель в формируемое на листе расписание (в каких-то ситуациях это может потребоваться, а в каких-то нет). Установка флажка Удалять пустые строки позволяет при составлении расписания автоматически удалять с листа пустые строки. Например, если в выводимых данных занятия в 15-10 во вторник отсутствуют (в это время нет занятий ни в одной из указанных в расписании групп), то и этой строки в расписании не будет совсем. Флажок Указать номер строки заявки позволяет показать’ в расписании, откуда пришла данная заявка (из какой строки на первом листе). Флажок Только предметы полезен при черновой работе с расписанием, т. к. позволяет отобразить на экране одновременно большее количество строк. Флажок Показывать необслуженные
Гпава 6
19П
позволяет отображать в расписании только обслуженные (с подобранными аудиториями) заявки или, наоборот, все имеющиеся на первом листе: если при не установленном флажке щелкнуть на кнопке Заполнить, то в расписании отображаются только заявки с указанными аудиториями; при установленном флажке по щелчку на кнопке Заполнить в расписании отображаются все заявки.
Рассмотрим некоторые конструкции процедуры, выполняемой по щелчку на кнопке Заполнить.
Вначале производится очистка имеющейся старой информации на листе: Range("a5:Z200").Select Selection.ClearContents
Здесь выделяется, а затем очищается заведомо большая область на листе, внутри которой находится информация о расписании. В следующем фрагменте подсчитывается количество потоков, выводимых в расписании: NP = 0
While Worksheets(5).Cells(NP + 2, 1).Value <> "" _
Or Worksheets(5).Cells(NP + 2, 2).Value <> "" NP = NP + 1
Wend
Затем в элементы массива mass записывается результат вычисления количества групп в каждом потоке. Так, в элементе mass(i) подсчитывается количество групп в первом выводимом в расписание потоке, в mass (2) — во втором и т. д. Процесс заполнения массива mass выполняется следующим образом: For i = 1 То NP mass(i) = 0 j = о While Worksheets(5).Cells(i + 1, j + 2).Value <> "" j = j + 1
Wend mass(i) = j Next
Далее в пятую и шестую строки листа Расписание выводятся названия потоков и групп, для которых мы составляем расписание. Аналогичным образом, в первые два столбца листа программно заносятся учебные дни и время^нача-ла занятий.
После этого выполняется цикл по всем строкам на первом листе, и если при этом очередная заявка относится к одной из рассматриваемых групп, то она
Задача управления ресурсами
191
выводится в соответствующую ячейку (которая определяется днем, временем, группой либо потоком). Данная процедура в зависимости от установки флажков на листе позволяет выводить в ячейки расписания различную информацию.
Кнопка Обслужить на этом листе просто дублирует кнопку Подбор аудитории с первого листа. Ее размещение здесь связано с частым использованием подбора аудитории при работе с листом Расписание.
Интересная функция заложена в кнопку Компоновка. Так, в расписании могут присутствовать последовательные по времени занятия у одного преподавателя для одной группы. Если таких ситуаций много, то удобнее вывести эти занятия в одной клетке с указанием интервала времени, когда эти занятия проводятся.
Рассмотрим практический пример. В наши данные добавим еще две заявки для группы ЗАЗ. В качестве занятия выберем Английский яз., а преподавателем в этих новых заявках будет Шорохов ДЛ. Время занятий выберем 10-00 и 11-35, день — понедельник (пон). На рис. 6.18 показан результат готового расписания после обработки введенных заявок.
Далее, если мы щелкнем на кнопке Компоновка, то вид листа изменится, как показано на рис. 6.19. В этом случае две клетки расписания для группы ЗАЗ трансформировались в одну.
Рис. 6.18. Готовое расписание: занятия записаны в двух клетках
192
Главе 6
Рис. 6.19. Готовое расписание: занятия записаны в одной клетке
Рис. 6.20. Лист Печ. расп.
Задача управления ресурсами
193
Если подвести некий промежуточный итог, то можно сказать: мы имеем почти готовую версию расписания, однако для получения печатного варианта требуется очистить лист (см. рис. 6.19) от элементов управления. Для этого в программе необходимая информация переносится на другой лист Microsoft Excel, который называется Печ. расп. (для его заполнения нам осталось щелкнуть на кнопке Печать) (рис. 6.20).
Фактически, на этом функциональные возможности листа можно было бы считать исчерпанными. Однако мы реализуем еще одну сервисную возможность по вводу заявок.
До этого момента новая заявка вводилась с помощью формы, открываемой щелчком на соответствующей кнопке первого листа. Однако есть более удобная возможность, аналогичная работе с традиционными кнопками Копировать и Вставить. В этом случае выделенная заявка сначала копируется во внутренний буфер, а затем вставляется в другую клетку расписания. В результате автоматически создается новая заявка на первом листе книги.
Поясним эту возможность на конкретном примере.
Допустим, требуется поставить в расписание новое занятие для группы ЗАЗ. Занятие по дисциплине Информатика (ч.1) намечается на среду (15-10), с первой по третью недели, а преподавателем должен быть Грушин ВА.
Для этого на листе Расписание щелкнем на кнопке Заполнить — для начала нам необходимо иметь перед собой заполненное расписание. Затем выделим любую занятую ячейку расписания (с любым занятием), например, ячейку С7, где для группы ЗА1 в понедельник в 10-00 поставлено занятие по дисциплине Информатика (ч.1). Затем щелкнем на кнопке Сору, расположенной в правой части листа. При этом во внутренний буфер записывается информация о выделенной заявке, а в текстовом окне (расположенном в правом верхнем углу на рис. 6.21) выводится номер строки первого листа, где эта заявка расположена.
Примечание
Для пользователя это просто индикатор того, что заявка скопирована во внутреннюю структуру данных.
Если вы повторите описанные действия на своем компьютере, то должен получиться результат, аналогичный показанному на рис. 6.21.
Далее нужно выделить ячейку на листе Расписание, в которую мы хотим скопировать данное занятие. В нашем случае это ЕЮ (группа ЗАЗ, день — среда, время — 15-10). Осталось только щелкнуть на кнопке Paste, и лист Расписание будет выглядеть так, как показано на рис. 6.22.
194
Глева 6
Рис. 6.21. Нажата кнопка Сору
Таким образом, в результате выполненных действий на первом листе появилась новая заявка. Хронологически при копировании сначала на первом листе появилась новая строка (с занятием для группы ЗАЗ), а затем она отобразилась на листе Расписание.
Понятно, что при таком копировании информация о преподавателе, названии занятия и интервале учебных недель осталась такой же, как и у исходной заявки. Ранее упоминалось о существовании ресурса для коррекции параметров заявки. И сейчас мы с ним познакомимся.
Для смены информации в ячейке расписания мы будем использовать событие — двойной щелчок на указанной ячейке. В результате автоматически выполняется предопределенная процедура Worksheet_BeforeDoubleClick.
Программный код, позволяющий откорректировать параметры заявки, приведен в приложении 4. Для пользователя данная процедура выводит на экран окно, в котором можно изменять преподавателей, предметы и недели (рис. 6.23). Здесь для смены преподавателей и дисциплин служат поля со списком, а для указания учебных недель — флажки.
На рис. 6.24 показано наше расписание после введенных изменений. Если посмотреть на первый лист, то можно увидеть в последней заполненной строке эту только что скорректированную заявку.
Задача управления ресурсами
195
Рис. 6.22. Нажата кнопка Paste
Рис. 6.23. Окно коррекции
196
Гпава 6
Рис. 6.24. Расписание откорректировано
Аналогичным образом можно вводить и последующие заявки на основе уже имеющихся (даже одной). Понятно, что этот способ существенно эффективнее рассмотренного ранее, когда требовалось полностью заполнять форму ввода. Хотя здесь само действие выполняется в два этапа (сначала копируется заявка, а затем изменяются ее параметры), такой способ более удобен для пользователя.
Кнопка Delete, присутствующая на листе Расписание (см. рис. 6.24), предназначена для удаления заявок. Для этого требуется лишь предварительно выделить заполненную ячейку расписания.
Сводный отчет по загрузке
В этом разделе мы рассмотрим еще одну возможность работы с расписанием. На рис. 6.25 показан лист с названием Отчет 2. Фактически это отчет, который позволяет показать загруженность фонда аудиторий по заявителям (кто использует фонд аудиторий больше, а кто меньше).
Если фонд аудиторий ограничен и между разными факультетами возникают противоречия по поводу его загрузки, представляет интерес такой сводный
Задача управления ресурсами 197
отчет, в котором наглядно отражены занятия по различным факультетам. Эта ситуация вполне типична для сегодняшнего дня, когда в вузах, наряду с бюджетным обучением, есть и коммерческое. Многие возникающие вопросы по фонду аудиторий могут быть успешно решены с помощью предлагаемого в этом разделе отчета.
Рис. 6.25. Лист Отчет 2
На листе, показанном рис. 6.25, по горизонтали в пятой и шестой строках выводятся дни и время начала занятий (фактически в этих строках перечислены все занятия в течение недели). В первом столбце указаны все аудитории, которыми располагает учебное заведение. И если в определенный день и конкретное время в аудитории по расписанию поставлено занятие, то в соответствующей ячейке это отмечается определенной заливкой (для каждого факультета свой цвет заливки) и отображается количество студентов. Например, из рис. 6.25 видно, что аудитория 1203 в понедельник (время 11-35) занята группой студентов (15-человек) с факультета ФФЯ.
Рассмотрим программный код, реализующий построение данного отчета, и в качестве первого шага прокомментируем элементы управления, расположенные на листе (см. рис. 6.25).
В левом верхнем углу находится поле со списком (Name = ы). Этот элемент при открытии книги автоматически заполняется информацией об учебных неделях (процедура workBcok_0pen). Справа от поля со списком располагается
198
Гпава 6
кнопка Заполнить (Name = comi), позволяющая заполнить лист информацией. В результате щелчка по этой кнопке ячейки листа заполняются информацией (количество занимающихся студентов и заявитель).
На этом листе мы легко можем посмотреть информацию о вместимости конкретной аудитории. Для этого нужно лишь щелкнуть по ячейке, содержащей номер аудитории. Например, на рис. 6.25 выделена аудитория 2118, и в верхнем текстовом окне (Name = inf 1) сообщений сразу же появится необходимая информация по вместимости.
Теперь прокомментируем некоторые программные конструкции, выполняемые по щелчку на кнопке Заполнить. Полный текст процедуры обработки щелчка по этой кнопке приведен в приложении 5. В начале процедуры в массиве colors устанавливаются цвета для заливки ячеек с заявками различных факультетов, что обеспечивает наглядность представления информации.
После установки заливки ячеек (определенный цвет связан с конкретным заявителем) сначала выполняется очистка области для вывода:
Range("а5:ZZ200").Select
Selection.ClearContents
Также устанавливается белый цвет заливки для области, где будет присутствовать информация о занятиях:
Range("Ь7:ZZ200").Select
With Selection.Interior
.Colorindex = 0
.Pattern = xlSolid
End With
После этого подсчитывается количество заявителей на втором листе:
N_Boss = О
While Worksheets(2).Cells(N_Boss + 2, 6).Value <> ""
NJBoss = NJBoss + 1
Wend
В качестве следующего действия на лист выводятся названия заявителей и соответствующие им цвета. Для вывода этой информации используются первая и вторая строки листа:
For i = 1 То NJBoss
Cells(2, 2 + i * 2).Select
With Selection.Interior
.Colorindex = colors (i)
.Pattern = xlSolid	*
Задача управления ресурсами 199_
End With
Cells(l, 2 + i * 2).Value = Worksheets(2).Cells(i + 1, 6).Value
Next
Следующий фрагмент позволяет установить в пятой и шестой строках подписи дней и время начала занятий:
st = 1
For i = 1 То N_Day
For j = 1 To N_Times
St = St + 1
Cells(5, St).Value = Worksheets(2).Cells(i + 1, 4).Value
Cells(6, St).Value = Worksheets(2).Cells(j + 1, 5).Value
Next
Next
На этом подготовительная часть для формирования отчета завершена, и далее для заполнения отчета в цикле просматриваются все заявки. Если заявка обслужена (для нее подобрана аудитория) и на указанной неделе занятие по данной заявке проводится, то далее она анализируется. В противном случае для данного отчета она не рассматривается.
В следующем фрагменте производится вычисление номера строки, где она должна быть отражена:
stroka = О
For i = 1 То пот
If N_Ayd = CStr(Cells(i + 6, 1).Value) Then
stroka = i + 6
Exit For
End If
Next
Аналогично вычисляется значение столбца на листе АФ, где необходимо отразить данную заявку:
For m = 1 То DaysTimes
If CStr(Worksheets(1).Cells(i, 4).Value) _
= CStr(Cells(5, 1 + ’m).Value) Then
If CStr(Worksheets(1).Cells(i, 5).Value) _
= CStr(Cells(6, 1 + m).Value) Then
stolbec = 1 + m
Exit For
End If
End If
Next
200
Гпава 6
Таким образом, мы определили ячейку на листе, где следует отразить информацию по данной заявке.
Следующее действие — закраска ячейки цветом того факультета, к которому данная заявка относится:
Name_Boss = CStr(Worksheets(1).Cells(i, 2).Value)
For nomer = 1 To N_Boss
If Name_Boss = CStr(Worksheets(2).Cells(nomer + 1, 6).Value) Then
Exit For
End If
Next
Cells(stroka, stolbec).Select
With Selection.Interior
.ColorIndex = colors(nomer)
.Pattern = xlSolid
End With
Теперь осталось в выбранной ячейке указать количество студентов, занимающихся в аудитории. Программно это реализуется с помощью одной строки:
Cells(stroka, stolbec).Value = Cells(stroka, stolbec).Value + _
Worksheets(l).Cells(i, 6).Value
Мы говорили, что на этом листе можно посмотреть информацию о вместимости аудитории. Для этого разработана следующая предопределенная процедура, которая выполняется при выделении той или иной аудитории. В результате необходимая информация выводится в окно для сообщений (листинг 6.16).
Private Sub Worksheet_SelectionChange(ByVai Target As Range)
’ Вычисление строки и столбца выделенной ячейки Stroka = ActiveCell.Row Stolbec = ActiveCell.Column If Stolbec <> 1 Then
* Информационное окно видимо только при выделении первого столбца Infl.Visible = False Elself Stroka > 6 Then
Infl. Visible = True
Infl.Text = "Вместимость " + _ Str (Worksheets(2).Cells(Stroka - 5, 2))	+ "чел"
End If
End Sub
Задача управления ресурсами 201
Отчет по ресурсам фонда аудиторий
Рассмотренный в предыдущем разделе отчет позволяет компактно, с помощью различных цветных заливок ячеек представить информацию об использовании фонда аудиторий заявителями (факультетами или руководителями программ). Числовая информация, выводимая в ячейки листа, показывает соотношение вместимости аудитории и количества студентов в группах.
Важным представляется ответ на вопрос: каков свободный ресурс аудиторий в определенном интервале учебных недель? Ответ на него можно получить на девятом листе книги Microsoft Excel, который называется Отчет 3. Вариант подобного отчета показан на рис. 6.26. По горизонтали на этом листе в пятой и шестой строках выводятся дни и время начала занятий (фактически в этих строках перечислены все занятия в течение недели), а в первом столбце указаны все аудитории, которыми располагает учебное заведение. В этом плане начало составления отчета ничем не отличается от предыдущего.
Однако теперь в сводной таблице выводится количество занятий в аудиториях в указанном интервале недель. При этом разная загруженность (различное количество занятий в выбранном интервале) дополнительно выделяется разными цветами. На листе реализованы 4 градации цвета в зависимости от загруженности:
□	максимальная загруженность;
□	загруженность выше средней;
□	загруженность ниже средней;
□	в выбранном интервале недель нет занятий.
В этом случае пользователю часто достаточно взглянуть на отчет, чтобы определить, есть ли аудитории, скажем для организации дополнительной учебной программы.
Кроме цветовой и числовой информации в ячейках можно получить более детальную информацию. Например, чтобы уточнить, какими занятиями аудитория все-таки занята, потребуется всего лишь двойной щелчок на выбранной ячейке. На листе откроется текстовое окно, отображающее все занятия, соответствующие выбранной ячейке. На рис. 6.26 показано отображение информации по занятиям в аудитории 1203 в группе ЗДВ2 у преподавателя Чикова НД.
Примечание
Чтобы убрать это текстовое окно с экрана, нужно сделать в нем двойной щелчок.
202
Гпаев 6
Рис. 6.26. Пример отчета
На листе для работы с отчетом заложена еще одна интересная возможность, связанная с двумя кнопками — Подготовить к перемещению и Переместить. С помощью этих кнопок можно перемещать занятия из одних аудиторий в другие. Допустим, требуется переместить указанное на рис. 6.26 занятие из аудитории 1203 в аудиторию 3205. Для этого нужно выделить исходную ячейку и щёлкнуть на кнопке Подготовить к перемещению — информация о заявке по указанной ячейке зафиксируется во внутренней структуре Данных (буфере). После этого пользователю нужно лишь выделить ячейку, куда он намеревается перенести занятие, и щелкнуть на кнопке Переместить.
В результате таких простых действий в отчете произошли изменения на первом листе заявок. Исходная заявка удалена, но при этом появилась новая (с выбранной аудиторией 3205).
Заметим, что алгоритм переноса заявки в новую аудиторию характеризуется определенным "интеллектом". Перед переносом заявки сначала анализируется возможность переноса — нет ли в этой аудитории занятий в рассматриваемые интервалы недель. Например, если мы переносим две заявки (в одной ячейке может быть несколько занятий, если они проводятся в разные недели) из одной аудитории в другую, то в случае невозможности переноса одной из них эта заявка остается без изменений.
Задача управления ресурсами 203
Рассмотренный отчет, таким образом, кроме получения наглядной сводной информации по загрузке, позволяет оперативно менять аудитории в составленном расписании. Из отчета при необходимости можно быстро найти свободные классы для занятий и планировать циклы дисциплин на определенное время.
Отчет по предмету
Рассмотрим в этом разделе отчет, для которого отводится лист с названием Отчет 4 (рис. 6.27). Его появление в книге связано с тем, что часто требуется просмотреть расстановку занятий в течение недели по определенному предмету. Это может быть связано с тем, что всегда есть удобное время для проведения занятий и менее удобное. Например, занятия, которые начинаются в середине дня, и те, которые начинаются рано утром. Просмотреть "справедливость" расстановки занятий и позволяет подобный отчет.
Пользователь в списке дисциплин (элемент "поле со списком") сначала должен указать предмет, который его интересует. Затем в двух других списках (элементы "поле со списком") следует указать рассматриваемый интервал недель и щелкнуть на кнопке Заполнить для заполнения отчета. В результате мы получим отчет, в котором по горизонтали (шестая строка на листе) выводятся учебные дни, а по вертикали в первом столбце выводится время начала всех занятий в течение дня. В ячейке же на пересечении определенных строки и столбца отображается количество занятий по выбранной дисциплине в течение указанного интервала недель. Так, из примера на рис. 6.27 видно, что для дисциплины Информатика ч.1 отводятся понедельник и среда.
В качестве дополнительной сервисной возможности на этом листе заложена возможность просмотра занятий — какие занятия проводятся в определенное время и в указанный день. Для этого достаточно двойного щелчка на интересующей нас ячейке листа мышью. В результате в правой части листа открывается текстовое окно, в котором выводится подробная информация о занятиях.
Примечание
Программные процедуры, обеспечивающие выполнение вышеупомянутых функций, приведены на сопроводительном компакт-диске книги.
204
Гпава в
Рис. 6.27. Лист Отчет 4
Лист Расчет
Электронная форма регистрации занятий предопределяет возможность подсчета количества проведенных занятий конкретным преподавателем за прошедший (или какой-нибудь другой) месяц. Понятно, что подобный отчет важен для руководства любой организации, т. к. оплата связана с количеством проведенных занятий.
Лист книги с названием Расчет (рис. 6.28) позволяет автоматически получить подобную информацию исходя из заявок, хранящихся на первом листе. Заметим, что в этом случае учитываются праздничные дни и просто нерабочие дни, которые руководством организации могут устанавливаться произвольно.
Прокомментируем элементы управления, а также информацию в ячейках этого листа. В левом верхнем списке (элемент "поле со списком") выбирается месяц, за который мы хотим получить отчет по отработанной нагрузке. В ячейках столбца Н можно указать список выходных и праздничных дней, когда учебное заведение не работает (в эти дни занятий точно нет). Программная процедура, выполняемая по щелчку на кнопке Расчет, просматривает информацию в столбце Н. В этом случае занятия, попавшие на указанные дни, автоматически исключаются при подсчете учебной нагрузки преподавателя за месяц.
Задача управления ресурсами
205
Рис. 6.28. Лист книги Расчет
Условие, налагаемое на перечисление нерабочих дней в столбце Н, заключается в необходимости отсутствия пустых ячеек (список дней должен быть заполнен плотно). Понятно, что для данного расчета требуется связать учебные недели с конкретной календарной датой. И на листе ячейка D1 отведена для того, чтобы указать понедельник нулевой недели. В этом случае можно легко вычислить календарную дату на произвольной неделе. После этого процедура, выполняемая по щелчку на кнопке Расчет, обладает полной информацией для проведения расчетов. Из примера на рис. 6.28 видно, что после щелчка на кнопке Расчет в первых двух столбцах листа мы получили список преподавателей с указанием количества проведенных занятий.
Процедуры, связанные с данным листом, приведены в приложении 7.
Отчет Нагрузка
Рассмотренный выше лист Расписание позволяет получить в удобном виде информацию о расписании занятий для интересующих нас групп и потоков. Однако при этом мы в какой-то степени пока не подумали о преподавателях. Ни один отчет до этого не был связан с нагрузкой преподавателей. И рассматриваемый в этом разделе лист предназначен для устранения такой "несправедливости".
Форма отчета понятна из рис. 6.29: видно, что на этом листе можно получить информацию о нагрузке одного конкретного преподавателя в целом на пред
гое
Глава 6
стоящий семестр. Интересующего преподавателя предварительно следует указать с помощью поля со списком Выбрать преподавателя.
После выбора преподавателя осталось только щелкнуть на кнопке Заполнить расписание. В этом случае выполняется обработка, позволяющая, начиная с седьмой строки листа, получить информацию по занятиям преподавателя (либо преподавателей).
Рис. 6.29. Лист Нагрузка
Рис. 6.30. Пример отчета
Задача управления ресурсами 207
Теперь рассмотрим эти и другие возможности отчета на примере.
На рис. 6.30 показано заполнение листа для преподавателя Чикова НД. Большинство столбцов отчета не вызывают каких-либо вопросов, но о последнем стоит немного сказать. В нем указываются конкретные даты проведения занятий. Фактически преподаватель в этом случае получает отчет, где указаны все даты, когда по расписанию он должен проводить занятия.
Интересная возможность заложена в кнопку Компоновка. Так, в расписании у преподавателя может быть одно занятие в разных группах или несколько последовательных по времени занятий в одной и той же группе. При заполнении расписания они займут несколько строк. Удобнее в этом случае скомпоновать подобные разрозненные заявки в одну строку. На рис. 6.30 показано, что у преподавателя Чикова НД четыре занятия — во-первых, они групповые (для двух групп), а во-вторых, последовательные по времени. В этом случае щелчок на кнопке Компоновка приводит к компоновке четырех строк этого отчета в одну (рис. 6.31).
Рис. 6.31. Результат компоновки
Видно, что при компоновке в отчете устанавливаются временные интервалы при проведении каждого занятия. Вспомним теперь, что мы рассматривали на втором листе занесение информации об окончании занятий, но до настоящего отчета эта информация нигде не использовалась. Фактически окончание занятий требуется только при выполнении подобной компоновки. Как видно из рис. 6.31, в отчете после компоновки все занятия перечисляются в формате время начала занятня:время окончания занятия.
208
Гпава 6
До этого мы ничего не говорили о подразделениях, где работают сотрудники. Однако преподаватели относятся к определенной кафедре (или какому-то другому подразделению). И если есть практическая необходимость в получении отчета по всем преподавателям определенной кафедры, то рассматриваемую книгу Microsoft Excel необходимо немного доработать.
В этом случае на листе с начальной информацией (второй лист книги) понадобится еще один столбец для названий кафедр.
Программные процедуры, связанные с этим листом, приведены в приложении 8.
Примечание
Автоматизированная книга по разработке расписания, приведенная на сопроводительном компакт-диске книги, включает в себя получение отчета только по каждому преподавателю. Это связано с тем, что, как показала практика, отчеты по всей кафедре не требуются.
Лист Передача
До этого момента мы не говорили о работе по составлению расписания несколькими сотрудниками. Реально же работа по составлению расписания часто начинается с подразделений, где разрабатываются блоки расписания по дисциплинам. Например, деканаты работают по составлению факультетских расписаний занятий без указания аудиторий. При этом выбирается удобная расстановка занятий для преподавателей и учебных групп. Далее, некий координирующий отдел (например, он может называться учебным отделом) соединяет все заявки в одной электронной книге и затем расставляет аудитории для проведения занятий.
В рассматриваемой книге Microsoft Excel заложен ресурс для подобной интеграции информации, — он находится на листе под названием Передача. Этот лист (рис. 6.32) служит для корректного переноса заявок извне (скажем, если они созданы в других аналогичных книгах Microsoft Excel). В этом случае заявки, которые необходимо добавить на первый лист данной книги, предварительно помещаются на лист Передача. Далее щелчком на кнопке Копирование заявок на 1-й лист они последовательно анализируются и перемещаются с текущего на первый лист книги. При копировании происходит разбор корректности заявок. Так, если информация в переносимой заявке противоречит уже имеющимся, то она не переносится, а в левом верхнем окне выводится поясняющая информация. При этом если пользователь все равно (независимо от информационного сообщения) принимает решение о переносе заявки, то для этого следует использовать кнопку Перенести строку.
Задача управления ресурсами
209
Рис. 6.32. Лист Передача
Из рис. 6.32 видно, что заявка, указанная в четвертой строке листа Передача, не перенесена, и в текстовом окне сообщений появилась соответствующая информация.
Отчет по конкретному дню
Еще один полезный отчет (расположен в книге Microsoft Excel на листе с названием Отчет 1) показан на рис. 6.33. Его назначение связано с получением подробной информации по конкретному учебному дню. В этом случае в списках (элементы управления "поле со списком"), расположенных в верхней части листа, выбираются: учебная неделя, время начало занятия, день недели. Здесь мы не будем указывать значения свойств элементов управления и пояснять программный код. В нескольких предшествующих разделах мы поступили так же. Этому несколько причин.
Во-первых, сам отчет достаточно прост, и его программная реализация полностью описана в приложении 3. Во-вторых, большинство читателей могут реализовать подобный отчет самостоятельно (может быть, даже улучшив). А в-третьих, формальное описание программного кода, возможно, уже несколько утомило, и в этом разделе мы рассмотрим только функциональные возможности элементов управления.
После некоторого отступления вернемся к нашему отчету. С помощью списков мы определили конкретный учебный день. Далее, если щелкнуть на кнопке Сформировать отчет, то, начиная с восьмой строки, мы получим
210
Гпава 6
на листе заполненный отчет об аудиториях (кем они заняты). В нем кроме рассмотренной ранее информации о заявках указывается номер строки первого листа, где данная заявка расположена. Другие поля отчета достаточно очевидны — день, время, группа (с указанием количества учащихся) и т. д.
Одно из удобств подобного отчета заключается в том, что из него сразу видны занятость аудиторий в определенное время и резерв фонда аудиторий.
При необходимости с помощью флажка Только лекционные можно получить отчет только по большим аудиториям (большой вместимости). Кнопка Удаление пустых строк позволяет удалить пустые строки из сформированного отчета, что часто требуется на практике.
Рис. 6.33. Лист Отчет 1
Заключение
Рассмотренная в этой главе автоматизированная рабочая книга Microsoft Excel находится на сопроводительном компакт-диске книги. Открыв файл raspisanie.xls из папки Glava6, вы можете поработать с расписанием и как пользователь (вводя заявки на проведение занятий, подбирая для них аудитории, формируя разнообразные отчеты), и как разработчик (изменяя существующие сервисные функции и добавляя новые).
Многие наверняка скажут, что с этой главой все понятно, но у нас несколько иные задачи. Понадобятся другие электронные формы, другие алгоритмы, другие отчеты и т. д. На практике все именно так — любая конкретная
Задача управления ресурсами 211
ситуация часто приводит к индивидуальности разработки. Даже такая популярная информационная система, как 1С:Предприятие, имеет на сегодняшний день множество различных конфигураций — разработок для определенных предметных областей деятельности. Однако при этом практически всегда требуется настройка готовой конфигурации и, достаточно часто, ее небольшая доработка. Это не недостаток, а, наоборот, следствие правильного стратегического курса разработчиков. В результате информационная система 1С:Предприятие легко адаптируется практически к любой встречающейся ситуации даже на этапе ее использования.
В этой главе мы попробовали построить информационную систему для эффективного управления фондом аудиторий, необходимого для организации учебного процесса. В понятие управления вкладывалось создание разнообразных сервисных функций для пользователя, полезных при составлении расписания учебных занятий. Важную роль играет создание интеллектуальных форм при заполнении входных данных и разработка разнообразных отчетов. Если попытаться сформулировать основное направление всех функциональных компонентов, то можно сказать, что это создание максимально удобного сервиса для пользователя. При разработке интерфейса всех листов книги мы всегда старались смотреть на результат работы в первую очередь глазами пользователя (те ли элементы управления присутствуют и те ли функциональные возможности реализованы, которые требуются пользователю). При разработке форм мы заложили ряд ресурсов, позволяющих пользователю исключать возможные ошибки и принимать правильные решения при составлении расписания и использовании фонда аудиторий.
В результате мы получили автоматизированную книгу Microsoft Excel, достаточно открытую в плане ее доработки со стороны пользователя. С другой стороны, она может явиться неплохой основой для решения вашей собственной офисной задачи.
ПРИЛОЖЕНИЯ
Приложение 1
Процедуры формы ввода заявок
В главе 6 рассматривается автоматизированная книга Microsoft Excel для управления аудиторным фондом учебного заведения. В связи с большим количеством сервисных возможностей разработки, а также большим объемом программных процедур для их реализации, ряд листингов вынесен в приложения. В этом разделе приведены процедуры, связанные с обработкой событий формы ввода заявок. Подробное описание самой формы и размещенных в ней элементов приведено в главе 6.
Основная функциональность, связанная с рассматриваемой формой (см. рис. 6.4), относится к записи введенной пользователем информации на первый лист книги Microsoft Excel. В листинге П1.1 приведена процедура обработки щелчка на кнопке Зафиксировать и ввести следующую.
I	—*• "V"'" ""	.....j
Листинг П11, Обработка щелчка на кнопке Зафиксировать и ввести следующую
Private Sub Com_Next_Click()
' Массивы для отслеживания накладок по группам и преподавателям Dim mass(50) As Integer
Dim mass2 (50) As Integer
' Поле номера заявки должно быть заполнено
If Num_Z.Text = Then
MsgBox ("Введите номер заявки") Exit Sub
End If
’ Поле заявителя должно быть заполнено
If Boss.Listindex = -1 Then
MsgBox ("Выберите заявителя") Exit Sub
216 Приложено
End If
’ Поле преподавателя должно быть заполнено
If Prepod.Listindex = -1 Then MsgBox ("Выберите преподавателя") Exit Sub
End If
' Поле для указания дня должно быть заполнено
If Day.Listindex = -1 Then MsgBox ("Выберите день") Exit Sub
End If
' Поле для указания начала занятия должно быть заполнено If Times.ListIndex = -1 Then
MsgBox ("Выберите время") Exit Sub
End If
' Поле для указания группы должно быть заполнено
If Group.Listindex = -1 Then MsgBox ("Выберите группу") Exit Sub
End If
' Поле для указания дисциплины должно быть заполнено
If Disp.Listlndex = -1 Then MsgBox ("Выберите дисциплину") Exit Sub
End If
' Необходимо ввести число студентов
If IsNumeric(Col_Stud.Text) = False Then MsgBox ("Введите число студентов") Exit Sub
End If
' Подсчет числа заявок на первом листе N = О
While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1
Wend	*
' Снятие защиты с первого листа
Worksheets(1).Unprotect ' Запись информации на первый лист
Приложение 1. Процедуры формы ввода заявок
217
1)	.Value = Nun\_Z.Text
2)	.Value = Boss.Text
3)	.Value = Prepod.Text
4)	.Value = Day.Text
5)	.Value = Times.Text
6)	.Value = Col_Stud.Text
9).Value = Group.Text
10).Value = Disp.Text
4, 11).Value =
4, 12).Value =
4, 13).Value =
4, 14).Value =
4, 15).Value =
4, 16).Value = "*"
4, 17).value =
4, 18).Value =
4, 19).Value =
4, 20).Value =
Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, Worksheets(1).Cells(N + 4, worksheets(1).Cells(N + 4, If ChO.Value = True Then
Worksheets(1).Cells(N + End If If Chi.value = True Then
Worksheets(1).Cells(N + End If
If Ch2.Value = True Then
Worksheets(1).Cells(N + End If
If Ch3.Value = True Then
Worksheets(1).Cells(N + End If
If Ch4.Value = True Then Worksheets(1).Cells(N + End If
If Ch5.Value = True Then Worksheets(1).Cells(N + End If
If Ch6.Value = True Then
Worksheets(1).Cells(N + End If
If Ch7.Value = True Then Worksheets(1).Cells(N + End If
If Ch8.Value = True Then
Worksheets(1).Cells(N + End If If Ch9.Value = True Then Worksheets(1).Cells(N + End If
If Chi0.Value = True Then
218
Приложения
Worksheets(1).Cells(N + 4, 21).Value = End If If Chi1.Value = True Then
Worksheets(1).Cells(N + 4, 22).Value = End If If Chl2.value = True Then
Worksheets(1).Cells(N + 4, 23).Value = End If If Chl3.Value = True Then
Worksheets(1).Cells(N + 4, 24).Value = End If If Chl4.Value = True Then
Worksheets(1).Cells(N + 4, 25).Value = "*" End If If Chl5.Value = True Then
Worksheets(1).Cells(N + 4, 26).Value = "*" End If If Chl6.Value = True Then
Worksheets(1).Cells(N + 4, 27).value = "*" End If If Chl7.Value = True Then
Worksheets(1).Cells(N + 4, 28).Value =
End If
Переменная-индикатор для проверки отсутствия накладок в заявке key = О Счетчик накладок по преподавателю Chjnass = О Счетчик накладок по группе учащихся Chjnass2 = О Цикл по количеству записей на листе For it = 4 То 4 + N - 1 qw = CStr(Worksheets(1).Cells(it, 1).Value) ' Считывание номера уже имеющейся заявки If Ch_Nom.Value = False And _ qw = CStr(Worksheets(1).Cells(N + 4, 1).Value) Then MsgBox ("Предупреждение.Заявка с таким номером уже" + _ "была в строке" + Str(it))
' Отмечается факт противоречия имеющихся и введенных данных key = 1
Приложение 1. Процедуры формы ввода заявок
219
End If 1 Блок проверки возможных накладок в расписании преподавателя ql = Worksheets(1).Cells(it, 3).Value q2 = Worksheets(1).Cells(it, 4).Value q3 = Worksheets(1).Cells(it, 5).Value Zan_Pr = 0 ' Индикатор занятости преподавателя в это время If ql = Worksheets(1).Cells(N +4, 3).Value And _ q2 = Worksheets(1).Cells(N + 4, 4).Value And _ q3 = Worksheets(1).Cells(N +4, 5).Value And _ Ch_Pr.Value = False Then For Ned = 11 To 28
If Worksheets(1).Cells(N + 4, Ned).Value <> "" _
And Worksheets(1).Cells(it, Ned).value <> "" Then Zan_Pr = 1 ’ Преподаватель занят Exit For End If Next If Zan_Pr = 1 Then ' Информацию о найденном занятии преподавателя записываем 1 в массив и увеличиваем счетчик элементов этого массива mass {Ch_jmass) = it Clxjnass = Chumass + 1 key = 1 ' Отмечается факт противоречия данных End If
End If ' Завершение блока проверки преподавателя ' Блок проверки возможных накладок в расписании группы ql = Worksheets(1).Cells(it, 9).Value q2 = Worksheets(1).Cells(it, 4).Value q3 = Worksheets(1).Cells(it, 5).Value Zan_Gr = 0 1 Индикатор занятости группы в это время If ql = Worksheets(1).Cells(N + 4, 9).Value And _ q2 = Worksheets(1).Cells(N + 4, 4).Value And _ q3 = Worksheets(1).Cells(N + 4, 5).Value Then For Ned = 11 To 28
If Worksheets(1).Cells(N + 4, Ned).Value <> "" And _ Worksheets(1).Cells(it, Ned).Value <> "" Then Zan_Gr = 1 Exit For End If
220
Приложения
Next
If Zarv.Gr » 1 Then
* Информацию о найденном занятии в группе записываем
1 в массив и увеличиваем счетчик элементов этого массива mass2 (Clkjnass2) = it Chjmass2 » CKjnass2 + 1 key = 1 'Отмечается факт противоречия данных
End If
End If ' Завершение блока проверки накладок по группе Next ' Завершение просмотра заявок на первом листе • If key » 1 Then ' Обработка накладок в заявке
If Chunass > 0 Then 1 Если есть противоречия по преподавателю informjBtr я "• ' Формирование информационной строки For i я о То Chjnass - 1
If infornustr о "" Then infornustr = inform_str + ","
End If
infonrustr « inform_str + CStr(mass(i))
Next
informjBtr = "Преподаватель занят. Заявка в стр " + infornc.Btr MsgBox (inform_str)
End If
If Chjmass2 > 0 Then ' Если есть противоречия по группе студентов inform_str я "" • Формирование информационной строки •For i = 0 То Ch_jnass2 - 1
If infornijBtr <> "" Then inform_str = inforn\_str + ","
End If
inforrtvstr = infornL_str + CStr (mass2 (i))
Next
infontL_str = "У группы есть занятие. Заявка в стр. " + infornustr MsgBox (inform_str)
End If
' Выбор варианта действий пользователем
Inform = MsgBox("Если все равно записать заявку, то нажмите - Да " Если продолжить редактировать, то нажмите — Отмена. " + " Если удалить заявку , то нажмите — Нет. ", _ vbYesNoCancel)
If Inform = vbNo Or Inform = vbCancel Then
Приложение 1. Процедуры формы ввода заявок 221
 Удаление только что введенных данных
For i = 1 То 28
Worksheets(1).Cells(N + 4, i).Value = ""
Next
End If
End If
End Sub
В форме ввода, кроме рассмотренной кнопки Зафиксировать и ввести еле* дующую, есть кнопка Зафиксировать и выйти. Процедура обработки щелчка на ней отличается от рассмотренной в листинге П 1.1 только завершающей частью, поэтому далее (в листинге П1.2) приводится только последний фрагмент процедуры.
I Листинг ГН .2. Фрагмент процедуры обработки щелчка на кнопке Зафиксировать и выйти
* До этого момента текст аналогичен процедуре из листинга П1.1
If key = 1 Then
If CHjnass > 0 Then * Если есть противоречия no преподавателю infornt-Str я "n 1 Формирование информационной строки
For i = 0 То Chjnass - 1
If inforn\_str о "" Then
inform_str я infornustr + ","
End If
inforni_str = infornL_str + CStr (mass (i))
Next
inforn\_str = "Преподаватель занят. Заявка в стр " + inforiRjstr
MsgBox (infornu.str)
End If
If Ch_mass2 > 0 Then ' Если есть противоречия по группе студентов infonn_str = "" ' Формирование информационной строки For i = 0 То Ch_jnass2 - 1
If inforrrL_str о "" Then
inforrri_str = inform_str + End If
inform_str = inform_str + CStr (mass2 (i))
222
Приложения
Next
inform_str = "У группы есть занятие. Заявка в стр. ” + inform_str MsgBox (inforrrL_str)
End If
' Выбор варианта действий пользователем
Inform = MsgBox("Если все равно записать заявку, то нажмите — Да. ' " Если продолжить редактировать, то нажмите — Отмена. " + _ " Если удалить заявку , то нажмите — Нет. ",vbYesNoCancel) If Inform = vbNo Or Inform = vbCancel Then
* Удаление только что введенных данных
For i = 1 То 28
Worksheets(1).Cells(N + 4, i).Value = "
Next
End If
Else
F_Add.Hide 1 Скрытие формы
End If
End Sub
В главе 6 мы рассматривали автоматическое заполнение формы ввода данными из ближайшей (к началу листа) заявки с подобным номером. Для этого используется предопределенная процедура, которая автоматически выполняется при изменении информации в текстовом окне, предназначенном для указания номера заявки (Name + Num_z). Полностью текст процедуры Num_Z_Change приведен в листинге П1.3. Она приводит к автоматическому заполнению полей формы, когда пользователь начинает вводить с клавиатуры информацию о номере заявки.
Листинг П1.3. Процедура обработки изменении в поле для указания номера заявки
Private Sub Nun\_Z_Change {)
N = 0 ' Подсчет числа заявок на первом листе
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
N_Boss = 0 ' Подсчет числа заявителей на втором листе
While Worksheets(2).Cells(N_Boss + 2, 6).Value о ""
N_Boss = N_Boss
Приложение 1. Процедуры формы ввода заявок
223
Wend
N_Prepod = 0 ' Подсчет числа преподавателей на втором листе
While Worksheets(2).Cells(N_Prepod + 2, 7).Value <> ""
N_Prepod = N_Prepod + 1
Wend
N_pay = 0 ’ Подсчет числа учебных дней на втором листе
While Worksheets(2).Cells(N_Day + 2, 4).Value <>
N_Day = N_Day + 1
Wend
N_Times = 0 ' Подсчет числа занятий в течение дня
While Worksheets(2).Cells(N_Times + 2, 5).value <> ""
N_Times = N_Times + 1
Wend
N_Group = 0 ' Подсчет числа учебных групп
While Worksheets(2).Cells(N_Group + 2, 8).Value <> ""
N_Group = NjGroup + 1
Wend
N_Disp = 0 ' Подсчет числа дисциплин
While Worksheets(2).Cells(N_pisp + 2, 10).Value <> ""
N_Disp » N_pisp + 1
Wend
N_text = Len(NUn\_Z.Text) ' Вычисление длины введенного текста
For i = 1 То N ’ Основной цикл по заявкам frame_text = Mid(Worksheets(1).Cells(i + 3, 1).value, 1, N_text) If Nun\_Z.Text = frame_text Then ’ Если найдена заявка с таким же ' номером, то заполнение Полей в соответствии с найденной заявкой
N_index = -1
For il = 1 То NJBoss
If Worksheets(1).Cells!i + 3, 2).value = _ Worksheets(2).Cells(il + 1, 6).Value Then N_index = il - 1 Exit For
End If
Next
Boss.Listindex = N_index ' Заполнение поля заявителя N_index = -1
For il = 1 To N_Prepod
If Worksheets(1).Cells(i + 3, 3).Value = _ Worksheets(2).Cells(il + 1, 7).Value Then
Приложения
224
N_index = il - 1 Exit For End If Next Frepod.ListIndex = N_index ' Заполнение поля преподавателя N_index = -1 For il = 1 To N_Day
If Worksheets(1).Cells(i + 3, 4).Value = _
Worksheets(2).Cells(il + 1, 4).Value Then N_index = il - 1 Exit For End If Next Day.Listlndex = N_index ' Заполнение поля дня N_index = -1 For il = 1 To N_Times
If Worksheets(1).Cells(i + 3, 5).Value = _
Worksheets(2).Cells(il + 1, 5).value Then N_index = il - 1 Exit For End If Next Times.ListIndex = N_index ' Заполнение поля времени N_index = -1 For il = 1 To NLGroup
If Worksheets(1).Cells(i + 3, 9).Value = _
Worksheets(2).Cells(il + 1, 8).Value Then N_index = il - 1 Exit For End If Next Group.Listlndex = N_index ' Заполнение поля группы N_index = -1 For il = 1 To N_pisp If Worksheets(1).Cells(i + 3, 10).Value = _ Worksheets(2).Cells(il + 1, 10).Value Then N_index = il - 1 Exit For End If
Приложение 1. Процедуры формы ввода заявок
225
Next
Disp.Listindex = N_index 1 Заполнение поля дисциплины Заполнение поля номера заявки numb_str = i + 3
NuncZ.Text = Worksheets(1).Cells(numb_str, 1).Value
Установка флажков учебных недель
If Worksheets(1).Cells(numb_str, 11).Value <> "" Then ChO.Value = "True"
Else
ChO.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 12).Value <> "" Then Chi.Value = "True"
Else
Chi.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 13).Value <> "" Then Ch2.Value = "True"
Else
Ch2.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 14).Value <> "" Then Ch3.Value = "True"
Else
Ch3.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 15).Value <> "" Then Ch4.Value = "True"
Else
Ch4.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 16).Value <> "" Then Ch5.Value = "True"
Else
Ch5.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 17).Value <> "" Then Ch6.Value = "True"
Else
226
Приложения
Ch6.Value » "False”
End If
If Worksheets(1).Cells(numb_str, 18).Value <> "" Then Ch7.Value = "True"
Else
Ch7.value = "False"
End If
If Worksheets(1) .Cells (nuxnb_str, 19) .Value <> "" Then Ch8.value = "True"
Else
Ch8.Value = "False"
End If
If Worksheets(1) .Cells (nuxnb_str, 20) .Value <> "" Then Ch9.Value = "True"
Else
Ch9.Value = "False"
End If
If Worksheets (1) .Cells (nuxnb_str, 21) .Value <> •’ Then ChlO.Value = "True"
Else
ChlO.Value = "False"
End If
If Worksheets(1).Cells(nuirib_str, 22).Value <> •" Then Chi1.Value = "True"
Else
Chll.Value = "False"
End If 
If Worksheets(1).Cells(numb_str, 23).Value <> "" Then Chl2.Value = "True"
Else
Chl2.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 24).Value <> "" Then Chl3.Value = "True"
Else
Chl3.Value = "False"
End If
If Worksheets(1).Cells(numb_str, 25).Value <> "" Then Chi4.Value = "True"
Приложение 1. Процедуры формы ввода заявок 227
Else Chl4.Value = "False" End If If Worksheets(1).Cells(numb_str, 26).Value <> "" Then Chi5.Value = "True"
Else Chl5.Value = "False" End If If Worksheets(1).Cells(numb_str, 27).Value <> "" Then Chl6.value = "True"
Else Chl6.Value = "False" End If If Worksheets(1).Cells(numb_str, 28).value <> "" Then Chl7. Value = "True"
Else Chl7.Value = "False" End If Exit For End If Next End Sub
В тексте главы б МЫ рассматривали процедуры Prepod^Change И Grcup_Change. С их помощью при вводе новой заявки на занятия автоматически заполняются списки Lis_Pr и Lis_Gr, информация в которых помогает пользователю принимать правильные решения. Понятно, что при смене дня в форме эти списки также должны автоматически заполняться заново. Предопределенная процедура Day_change, выполняемая в этом случае, компонуется из фрагментов процедур Prepod_Change и Group_Change; ее текст приведен в листинге П1.4.
| Листинг П1.4. Процедура, выполняемая при смене дня занятий
Private Sub Day_Change()
N = 0 ' Подсчет количества заявок на первом листе
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
Lis_Gr.Clear ' Очистка списка групп студентов
For i = 1 То N ' Цикл по заявкам
Приложения
228
It Worksheets(1).Cells(i + 3, 4).Value = Day.Text And _ Worksheets(1).Cells(i + 3, 9).Value = Group.Text Then ' Внесение в список занятия для данной группы
Lis_Gr.Additem Worksheets(1).cells(i + 3, 5).Value + " " + _ Worksheets(1).Cells(i + 3, 10).Value End If
Next
L_group.Caption = Group.Text ' Вывод информационного сообщения о группе If Group.ListIndex > -1 Then ' Указание количества учащихся в текстовом окне
Col_Stud.Text = Worksheets(2).Cells(Group.ListTndex + 2, 9).Value End If Lis_Pr.Clear ' Очистка списка преподавателей For i = 1 To N ' Цикл по заявкам
If Worksheets(1).Cells(i + 3, 4).Value = Day.Text And _ Worksheets(1).Cells(i + 3, 3).Value = Prepod.Text Then
1 Внесение в список занятия преподавателя Lis_Pr.AddItem Worksheets(1).Cells(i + 3, 5).Value + ’ " + _ Worksheets(1).Cells(i + 3, 10).Value + " " _ + Worksheets(1).Cells(i + 3, 9).Value End If
Next ' Вывод информационного сообщения о преподавателе L_prер.Caption = Prepod.Text
End Sub
Приложение 2
Процедуры формы для подбора аудитории
Форма для подбора наиболее подходящей аудитории при обслуживании заявки является наиболее сложной с точки зрения заложенных в нее алгоритмов обработки данных. С ее внешним видом вы знакомы по рис. 6.6. В листинге П2.1 приведена процедура обработки щелчка на списке Номер строки (Nunustr). Фактически это действие приводит к выбору из списка одной заявки для дальнейшего обслуживания.
Листинг П2.1 Обработка щелчка на списке имеющихся заявок на обслуживание
Private Sub NunuStr_Click()
Dim TimeNext As String ' Описание переменной строкового типа ' Список, открываемый нажатием кнопки "Отчет", убирается с экрана L_otchet.Visible = False inf_ayd.Caption = ""	' Очистка информационных окон
Inf_vmestl.Caption = "" inf_z.Caption = ""
' Перенос информации о заявке на форму select_vibor = CInt(Num_Str.List(Num_Str.Listindex)) Num_Z.Caption = Worksheets(1).Cells(select_vibor, 1).Value Boss.Caption = Worksheets(1).Cells(select_vibor, 2).Value Prepod.Caption = worksheets(1).Cells(select_vibor, 3).Value Day.Caption = Worksheets(1).Cells(select_vibor), 4).Value Times.Caption » Worksheets(1).Cells(select_vibor, 5).Value Col_Stud.Caption = Worksheets(1).Cells(select_vibor, 6).Value Group.Caption = Worksheets(1).Cells(select_vibor), 9).Value Disp.Caption = worksheets(1).Cells(select_vibor, 10).Value Ned.Caption = ""
230
Приложения
' Вывод информации о неделях занятий For i « 11 То 28 If Worksheets(1).Cells(CInt(NumjStr.Text), i).Value <> "" Then Ned.Caption = Ned.Caption + CStr(i - 11) + End If Next N_Group = 0 ' Индикатор одной лекции у нескольких групп N_Posl = 0	' Индикатор последовательных по времени занятий
' Подсчет количества строк на первом листе N = О While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1 Wend If Ch_Group.Value = False Then 1 Анализ занятия у нескольких групп For i = 1 То N num = i + 3 If num <> select_vibor Then ' Пропускаем рассматриваемую заявку Prepl = Worksheets(1).Cells(num, 3).Value Dayl = Worksheets(1).Cells(num, 4).Value Timesl = Worksheets(1).Cells(num, 5).Value Displ = Worksheets(1).Cells(num, 10).Value Obi = Worksheets(1).Cells(num, 7).Value
' Если совпадают день, время, преподаватель необслуженной заявки If Prepl = Prepod.Caption And Dayl = Day.Caption And _
Timesl = Times.Caption And Displ = Disp.Caption And Obi = "" Then zan = 0 For j = 11 To 28 Ned_Y = Worksheets(1).Cells(num, j).Value Ned_Z = Worksheets(1).Cells(CInt(Num_Str.Text), j).Value If Ned_Y = And Ned_Z = Then ' Если есть пересечение занятий, то отмечаем эту заявку zan = 1 Exit For End If Next If zan = 1 Then ' Если пересечение занятий есть, то отмечаем это ' в массиве Mass_Group
Приложение 2. Процедуры формы для подбора аудитории 231
N_Group = N_Group + 1 Mass_Group(N_Group) = num End If End If End If Next End If ' Завершение анализа занятий у нескольких групп ' Текущая заявка сохраняется в элементе с нулевым индексом Mass_Group(0) = CInt (Nun\_Str. Text) ' Вывод информации о наличии совместных (в одно время) занятий If N_Group > 0 Then inf_z.Caption = "Совместные заявки в строках " For i = 1 То N_Group ' Корректировка числа студентов Col_Stud.Caption = CInt(Col_Stud.Caption) + _ Worksheets(1).Cells(Mass_Group(i), 6).Value ' Перечисление строк групповых заявок на 1-м листе inf_z.Caption = inf_z.Caption + Str(Mass_Group(i)) + Next End If 1 Проверка наличия последовательных по времени занятий If N_Group = 0 Then ' Проверка производится при отсутствии одновременных занятий ' у нескольких групп N_Posl = 0 ' Счетчик количества соседних по времени пар у группы N_Times = 0 ' Подсчет количества занятий в течение дня While Worksheets(2).Cells(N_Times +2, 5) о "" N_Times = N_Times + 1 Wend flag = 0 ’ Проверка правильности указания времени начала занятий For i = 1 То N_Times
If Times.Caption = Worksheets(2).Cells(i + 1, 5).Value Then flag = 1 Exit For
End If Next If flag = 0 Then
MsgBox ("Ошибка в указании времени начала занятий в данной заявке") Exit Sub
232
Приложения
End If
' В переменной i сформирован номер занятия в списке второго листа v_vre_dop = i + 2 ' Строка, где указано следующее занятие TimeNext = Worksheets(2).Cells(v_vre_dop, 5).Value
While prov(TimeNext) <> 0	' Если найдено занятие по времени
v_vre_dop = v_vre_dop + 1 TimeNext = Worksheets(2).Cells(v_vre_dop, 5).value
Wend v_vre_dop = i If v_vre_dop > 1 Then
TimeNext « Worksheets(2).Cells(v_vre_dop, 5).Value
While v_vre_dop > 1 And prov( TimeNext) <> 0
v_vre_dop = v_vre_dop - 1
TimeNext * Worksheets(2).Cells(v_vre_dop, 5).Value Wend End If ' Если установлен флаг - не обрабатывать последовательные ' по времени заявки If Ch_Posl.Value = True Then N_Posl = 0 End If ' Вывод информации о наличии последовательных заявок If N_Posl > 0 Then
inf_z.Caption » _
"Последовательные по времени пары в заявках на строках " For i = 1 То NLPosl
inf_z.Caption = inf_z.Caption + Str(Mass_Posl(i)) + Next End If End If Mass_Posl(0) = select_vibor End Sub
В тексте процедуры Num_str_ciick используется вызов функции prov, предназначенной для поиска строки в списке заявок по указанному времени начала занятия (значение времени передается в процедуру как параметр). Другие необходимые параметры для поиска функция извлекает из полей формы. При этом в случае нахождения заявки с указанными параметрами функция возвращает значение 1, в противном случае 0.
Приложение 2. Процедуры формы для подбора аудитории 233
Текст функции prov приведен в листинге П2.2.
| Листинг П.2.2. Функция проверки наличия последовательной по времени заявки
Function prov(Vre_Next As String) As Integer
zan = 0 ' Индикатор нахождения последовательной заявки ' Подсчет заявок на первом листе
N = О
While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1
Wend
select_vibor = Nuni_Str.List (Nuni_Str.ListIndex)
For i = 1 To N ' Цикл по заявкам
al = Worksheets(1).Cells(i + 3, 9).Value ' Группа
a2	=	Worksheets(1).Cells(i	+	3,	4).Value	'	День
a3	=	Worksheets(1).Cells(i	+	3,	5).Value	'	Время
a4	=	Worksheets(1).Cells(i	+	3,	7).Value	'	Обслуживание
If	al = Group.Caption And a3	= VreJNext And	a2 =	Day.Caption And _
a4 <> "да" Then
' Если найдена последовательная заявка
For j = 11 То 28
Nedel = Worksheets(1).Cells(CInt(select_vibor), j).value
If Nedel = "*" And Worksheets(1) .Cells(i + 3, j).value = "** Then zan = 1 ’Есть хоть одно пересечение по заявкам Exit For
End If Next End If If zan = 1 Then Exit For
End If Next
If zan = 1 Then
N_Posl = N_Posl + 1 ' Увеличение счетчика занятий
Mass_Posl(N_Posl) = i + 3 ' Занесение номера заявки End If prov = zan End Function
234
Приложения
В листинге П2.3 приведена процедура, выполняемая по щелчку на кнопке Начать, которая запускает алгоритм поиска подходящих аудиторий для заявки, указанной в списке Номер строки формы.
| Ли	"	........
Private Sub Begir\_Poisk_Click()
Inf_vmestl.Caption = "" ’ Очистка информационных окон для сообщений inf_ayd. Caption = ""
If Nuni_Str. List Index = -1 Then
MsgBox ("He выбран номер строки заявки")
Exit Sub
End If
' Очистка списка аудиторий для его последующего заполнения
L_otbor.Clear
' Подсчет числа аудиторий
N_Rocxns = О
While Worksheets(2).Cells(N_Rooms + 2, 1).Value <> ""
NURocens = NJtooms + 1
Wend
' Подсчет количества строк на первом листе
N = О
While worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
shet = 0 ' Счетчик для числа подобранных аудиторий
For i = 1 То N_Rooms ' Цикл по аудиториям
Ayd = Worksheets(2).Cells(i + 1, 1).Value
If IsNumeric(Ayd) = True Then
ayd_Ch = Ayd
Else
' Если в названии аудитории есть буква, отбрасываем ее
aydjCh = CInt (Mid(Ayd, 1, 4))
End If
* Вычисляем номер корпуса по номеру аудитории
shif = ayduCh \ 1000
If All_Corpus.Value = False Then
' Если сделана установка на конкретный корпус
If shif = 1 And Corpusl.Value = False Then
Приложение 2. Процедуры формы для подбора аудитории
235
' Пропускаем заявку, если сделана установка на первый корпус, ' а в заявке указан другой
GoTo Nexti
End If
If shif = 2 And Corpus2.Value = False Then GoTo Nexti
End If
If shif = 3 And Corpus3.Value = False Then GoTo Nexti
End If
If shif = 4 And Corpus4.Value = False Then GoTo Nexti
End If
End If
' Вычисление вместимости аудитории
If Worksheets(2).Cells(i + 1, 2).Value < CInt(Col_Stud.Caption) Then
' Если вместимость меньше числа студентов, то пропускаем заявку GoTo Nexti
End If
zan = 0 ' Индикатор занятости аудитории
If Ch_Posl.Value = True Then
' Если установлен запрет на последовательные заявки, ' то принудительно сбрасываем их
N_Posl = О
End If
For j = 0 То N_Posl
' Проверка корректности аудитории для всех последовательных •
' заявок
For je = 1 То N ' Цикл по заявкам
If Worksheets(1).Cells(je + 3, 7).Value = "да" And _
CStr(Worksheets(1).Cells(je + 3, 8).Value) = _
CStr(Ayd) And Worksheets(1).Cells(je + 3, 5).Value = _
Worksheets(1).Cells(Mass_Posl(j), 5) And _
Worksheets(1).Cells(je + 3, 4).Value = Day.Caption Then
For jj = 11 To 28
Nedl = Worksheets(1).Cells(je + 3, jj).Value
Ned2 = Worksheets(1).Cells(Mass_Posl(j), jj).Value
If Nedl = "*n And Ned2 = Then zan = 1
236
Приложения
Exit For End If Next End If If zan = 1 Then Exit For End If Next * Завершение цикла по заявкам If zan = 1 Then Exit For End If Next If zan = 0 Then ' В этом случае аудитория свободна и мы включаем ее в список L_otbor.Additem Ayd shet = shet + 1 If Ch_LA.Value = True Then
If shet = 1 Then ' В случае ограничения поиска Exit Sub ' одной аудиторией End If End If If Ch_3A.Value = True Then ' В случае ограничения поиска If shet > 2 Then	' тремя аудиториями
Exit Sub End If End If End If Nexti: Next 'Цикл по аудиториям If shet = 0 Then inf_ayd.Caption = "Для данной заявки аудиторий нет" End If End Sub
В правой части формы (см. рис. 6.6) присутствует кнопка Проверить, которая служит для проверки аудитории, выбранной в верхнем списке vibor_room. В листинге П2.4 приведена процедура, которая осуществляет эту проверку и выводит диагностическое Сообщение — свободна или нет аудитория.
Приложение 2. Процедуры формы для подбора аудитории 237
| Листинг П.2.4. Процедура обработки щелчка по кнопке Проверить	|
Private Sub Ccm_Test_Click() ' Очистка окна, информирующего о занятости аудитории inf_zan2.Caption = "" L_otchet.Visible = False ' Убираем с экрана список и очищаем его L_otchet.Clear	1 от старой информации
If Vibor_room.ListIndex = -1 Then ' Требование выбора аудитории MsgBox ("Не выбрана аудитория !") Exit Sub End If
If Nun\_Str.Listindex « -1 Then ' Требование выбора заявки MsgBox ("He выбран номер строки заявки") Exit Sub
End If ' Подсчет количества строк на первом листе N = О
While Worksheets(1).Cells(N + 4, 1).Value <> nn N = N + 1
Wend
Ayd = Vibor_r oom. Text
If Ch_Posl.Value = True Then
* Если установлен запрет на последовательные заявки, то сбрасываем их N_Posl = О
End If
For i = 0 То N_Posl
For j = 1 To N 1 Цикл по заявкам
If Worksheets(1).Cells(j + 3, 7).Value = "да" And _ CStr(Worksheets(1).Cells(j + 3, 8).Value) = _ CStr(Ayd) And Worksheets(1).Cells(j + 3, 5).Value = _ Worksheets(1).Cells(Mass_Posl(i), 5) And _ Worksheets(1).Cells(j + 3, 4).Value = Day.Caption Then For jj = 11 To 28 Nedl = Worksheets(1).Cells(j + 3, jj).Value Ned2 = Worksheets(1).Cells(Mass_Posl(i), jj).Value If Nedl = And Ned2 = Then zan = 1 ' Индикатор того, что аудитория занята
Exit For
238
Приложения
End If
Next
End If
If zan = 1 Then
Exit For
End If
•Next ' Завершение цикла по заявкам на первом листе
If zan = 1 Then
Exit For
End If
Next ’ Завершение цикла по последовательным заявкам
If zan = 0 Then
inf_zan2.Caption = "Аудитория свободна "
’ Доступ к кнопке записи выбранной аудитории
Coni_Write2. Enabled = True
Else
inf_zan2.Caption = "Аудитория занята"
End If
End Sub
Предыдущая процедура позволяла нам выяснить, свободна аудитория или занята. В каких-то случаях требуется получить информацию о том, кто все-таки ее занял. Для этого в форме есть кнопка Отчет, позволяющая получить полную информацию о том, какими группами занята аудитория. В листинге П2.5 приведена процедура, выполняемая по щелчку на этой кнопке.
| Листинг П2.5. Процедура обработки щелчка на кнопке Отчет
Private Sub Can\_Result_Click()
If Vibor_room.Listindex = -1 Then ' Проверка выбора параметра
MsgBox ("He выбрана аудитория!")
Exit Sub
End If
If Num_Str.Listindex = -1 Then ' Проверка выбора параметра
MsgBox ("He выбран номер строки заявки") Exit Sub
End If
L_otchet.Visible = True ' Подготовка списка для отображения	t
Приложение 2. Процедуры формы для подбора аудитории 239
L_otchet.Clear
' Подсчет числа записей на первом листе N = О
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
For j = 0 To N_Posl ' Просмотр последовательных по времени заявок DenPos = CStr(Worksheets(1) .Cells(Mass_Posl(j), 4)) VrPos = CStr(Worksheets(1).Cells(Mass_Posl(j), 5)) For i = 4 To N + 3 'Цикл по заявкам
If CStr(Worksheets(1).Cells(i, 7).Value) = "да" Then
' Условие обслуживания
Dayl = CStr(Worksheets(1).Cells(i, 4).Value)
Timel = CStr(Worksheets(1).Cells(i, 5).Value)
Roctnl = CStr(Worksheets(1).Cells(i, 8).Value)
Groupl = CStr(Worksheets(1).Cells(i, 9).Value) Displ = CStr(Worksheets(1).Cells(i, 10).Value) Prepodl = CStr(Worksheets(1) .Celled, 3) .Value) If Dayl = DenPos And Timel = VrPos And _ Roctnl = Vibor_room.Text Then
1 Формирование информации о занятии
Liststring » "" For m = 0 To 17
If CStr(Worksheets(1).Cells(i, m + 11).Value) = Then Liststring = Liststring + " " + Str(m) + ","
End If
Next
' Добавление в список найденного занятия L_otchet.Additem Timel + " " + Groupl + " " _
+ Displ + " " + Prepodl + " " + Liststring End If
End If
Next
Next
End Sub
В главе 6 приведена процедура обработки щелчка на кнопке Записать аудиторию для рамки Поиск аудитории. Здесь, в листинге П2.6, приведена аналогичная процедура для рамки Выбор аудитории.
240	Приложения
I Листинг П2.6. Обработка щелчка на кнопке Записать аудиторию для рамки Выбор аудитории
Private Sub Com_Write2_Click()
If Vibor__room.ListIndex = -1 Then ' Требование установки параметров MsgBox ("He выбрана ни одна аудитория") Exit Sub
End If
If inf_zan2.Caption = "Аудитория занята" Then
vibor = MsgBox("Аудитория занята. Если записать в эту аудиторию " + _ "еще одну заявку, то нажмите - Да ", vbYesNo)
If vibor о vbYes Then
Exit Sub
End If
End If
Worksheets(1) .Unprotect 'Снятие защиты с листа
inf _vmest2.Caption = "" ' Очистка информационного окна о вместимости inf_zan2.’Caption = ""	' Очистка информационного окна о занятости
’ Если установлен флаг запрета групповых заявок If ChjGroup. Value = True Then
NjGroup = 0
End If
If NjGroup > 0 Then ' При групповых заявках
Worksheets(1) .Cells(CInt(NunuStr.Text), 7) = "да"
Worksheets(1).Cells(CInt(NunjStr.Text), 8) = Vibor_r oom. Text
For i « 1 To N_Group
Worksheets(1).Cells(MassjGroup(i), 7).Value = "да"
Worksheets(1) .Cells(MassjGroup(l), 8) .Value « Vibor_xoom.Text Next
Else
If Ch_Posl.Value = True Then
' Если установлен запрет на последовательные заявки N_Posl = О
End If
For i = 0 То N_Posl
Worksheets(1).Cells(Mass_Posl(i), 7).Value = "да"
Worksheets(1) .Cells(Mass_Posl(i), 8) .Value = Vibor_xocm.Text
Next	f
End If
Приложение 2. Процедуры формы для подбора аудитории 241
Num_Str. Clear ' Очистка списка заявок
L_otbor.Clear ' Очистка списка, открываемого нажатием кнопки "Отчет"
L_otchet,Visible = False
If Opti.Value = False And Opt2.Value = False And Opt3.Value = False Then ' Установка переключателя для заполнения списка заявок
Opti.Value = True
End If
vkl 1 Эта процедура приведена в главе б (листинг 6.10)
Cont_Write2 .Enabled = False
End Sub
Приложение 3
Процедуры листа Отчет 1
В заключительной части главы 6 описывается отчет, позволяющий получить информацию по фонду аудиторий для указанных времени и дня недели. Внешний вид этого отчета показан на рис. 6.33, а в самой книге Microsoft Excel он расположен на третьем листе с названием Отчет 1.
В листинге ПЗ. 1 приведена процедура, позволяющая заполнить его данными.
| гинг ПЗЛ. Процедура обработки щелчка по кнопке Сформировать отчет |
Private Sub Com_l_Click()
' Если не выбраны элементы в списках, то выход из процедуры
If Ll.Listlndex = -1 Or L2.Listindex = -1 Or L3.Listindex = -1 Then
MsgBox (" He выбраны параметры списков ")
Exit Sub
End If
' Подсчет аудиторий в переменной N_Rooms
NJRooms = О
While Worksheets(2).Cells(N_Rooms + 2, 1).Value <> ""
N_Rooms = N_Rooms + 1
Wend
' Подсчет числа заявок на первом листе
N = О
While Worksheets(1) .Cells(N + 4, 1) .Value о ""
N = N + 1
Wend
' Очистка области вывода от предыдущих данных
Range("Ь8:1200").Select	f
Selection.ClearContents
If Chi.Value = True Then
Приложение 3. Процедуры листа Отчет 1 243
1 Если флаг Chi установлен, то выводятся только лекционные аудитории Stroka = 1 ' В переменной Stroka организуем счетчик строк на листе For i = 1 То N_Rooms
' В переменной vmest фиксируется вместимость аудитории vmest = CInt(Worksheets(2).Cells(i + 1, 2).Value) If vmest >30 Then ' Если аудитория вмещает более 30 человек, то выводим ее
Cells(Stroka + 7, 2).Value = Worksheets(2).Cells(i + 1, 1).Value Stroka = Stroka + 1 End If Next
Else ' Заполнение листа информацией по всем аудиториям For i = 1 То N_Rooms
Cells(i + 7, 2).Value = Worksheets(2).Cells(i + 1, 1).Value Next End If For i = 4 To N + 3 ' Цикл по заявкам If Worksheets(1).Ce]Is(i, 7).Value = "да" Then * Если заявка обслужена, то далее рассматриваем ее Stroka = 0
’ В переменной NumAyd фиксируется номер аудитории NumAyd = Worksheets(1).Cells(i, 8).Value For j = 1 To N_Jtooms
If CStr(NumAyd) = CStr(Cells(X-* 7 > 2).Value) Then
Stroka = j + 7
Exit For End if Next
If Stroka = 0 Then ' Если^удитории в заявке и в списке ' не совпадают, то эту заявку не рассматриваем
Goto Nexti End If N_Day = CStr(Worksheets(1).Cells(i, 4).Value) N_Time = CStr(Worksheets(1).Cells(i, 5).Value) N_Ned = CStr(Worksheets(1).Cells(i, CInt(L3.Text) + 11)) If N_Day = CStr(LI.Text) And N_Time = CStr(L2.Text) And _
N_Ned = And CStr(NumAyd) = CStr(Cells(Stroka, 2).Value) Then Если параметры заявки соответствуют параметрам списков Cells(Stroka, 3).Value = N_Day Cells(Stroka, 4).Value = N_Time
244
Приложения
' Вывод информации о заявителе
Boss = Worksheets(1).Cells(i, 2).Value
Cells(Stroka, 5).Value = _
Cells(Stroka, 5).Value + Boss + Chr(10)
' Вывод информации о преподавателе
Prepod = Worksheets(1).Cells(i, 3).Value
Cells(Stroka, 6).Value = _
Cells(Stroka, 6).Value + Prepod + Chr(10) ' Вывод информации о номере строки заявки
Cells(Stroka, 7).Value = _
Cells(Stroka, 7).Value + CStr(i) + Chr(10)
' Вывод информации о группе
Group = Worksheets(1).Cells(i, 9).Value
Cells(Stroka, 8).Value = Cells(Stroka, 8).Value + Group + _ "(" + CStr(Worksheets(1).Cells(i, 6).Value) + ")" + Chr(10)
* Вывод информации о предмете
Disp » Worksheets(1).Cells(i, 10).Value
Cells(Stroka, 9).Value = _
Cells(Stroka, 9).Value + Disp + Chr(10)
End If
End If
Next!: Next • Завершение цикла по заявкам
Range("а5").Select
End Sub
На этом листе есть еще три процедуры. Одна из них выполняется по щелчку на кнопке Удаление пустых строк и приведена в листинге П3.2.
| Листинг П3.2. Процедура для удаления пустых строк в отчете
Private Sub Coin_2_Click()
1 Подсчет числа аудиторий, приведенных в этом отчете N = 0
While Cells(N + 8, 2).Value <> ""
N = N + 1
Wend counter = 1 1 Счетчик полного количества строк i = 1 ' Счетчик строк с учетом удаленных While counter <= N	*
If CStr(Cells(i + 7, 3).Value)
Then
Приложение 3. Процедуры листа Отчет 1
245
Rows(i + 7).Delete ' Удаляем пустую строку Else
i = i + 1
End If counter = counter + 1 Wend End Sub
Две другие процедуры связаны с рабочим листом как с объектом в целом. Это процедуры Worksheet_Activate (ЛИСТИНГ ПЗ.З) И Worksheet_Deactivate (листинг П3.4). В процедуре worksheet_Activate заполняются списки дней, времена начала занятий и учебных недель. Можно сказать, что все это можно выполнить и в процедуре workbook_open. Это действительно так и далее приводится текст этой процедуры. Однако здесь полезно заполнить списки при активизации листа. В этом случае оперативные изменения в начальной информации (на втором листе) будут сразу отражаться на листе отчета.
Для сохранения установленных позиций в списках в общей области определим три переменные:
Dim Savl As Integer
Dim Sav2 As Integer
Dim Sav3 As Integer
При переходе с текущего листа на какой-либо другой автоматически выполняется предопределенная процедура Worksheet_Deactivate. В этой процедуре мы будем сохранять в указанных переменных индексы выделенных элементов списков. Соответственно затем при возврате на данный лист (Отчет 1) с помощью предопределенной процедуры worksheet_Activate установка списков восстанавливается сохраненными значениями.
| Листинг ПЗ.З. Процедура, выполняемая при активизации листа Отчет 7
Private Sub Worksheet-Activate ()
' Подсчет дней на втором листе
NJDays = О
While Worksheets(2).Cells(NJDays + 2, 4).Value <> ""
N_Days = N_Days + 1
Wend
' Заполнение списка LI на третьем листе
Worksheets(3).LI.Clear
For i = 1 To N_Days
Worksheets(3).LI.Additem Worksheets(2).Cells(i + 1, 4).Value
246	Приложения
Next
' Подсчет занятий в течение дня
N_Times = О
While Worksheets(2).Cells(N_Times + 2, 5).Value <> ""
N_Times = N_Times + 1
Wend
1 Заполнение списка L2 на третьем листе
Worksheets(3).L2.Clear
For i = 1 To NJTimes
Worksheets(3).L2.Additem CStr(Worksheets(2).Cells(i + 1, 5).Value) Next ’ Подсчет числа недель на втором листе N_Ned = О While Worksheets(2).Cells(N_Ned + 2, 3).Value <> ""
N_Ned = N_Ned + 1
Wend
‘ Заполнение третьего списка L3 на третьем листе
Worksheets(3).L3.Clear
For i = 1 То N_Ned
Worksheets(3).L3.Additem Worksheets(2).Cells(i + 1, 3).Value Next If LI.Listcount > 0 And Savl < Ll.ListCount Then
LI.Listindex = Savl ' Восстановление сохраненного значения End If
If L2.ListCount > 0 And Sav2 < L2.ListCount Then
L2.ListIndex = Sav2 ' Восстановление сохраненного значения End If If L3.ListCount > 0 And Savl < L3.Listcount Then
L3.Listindex = Sav3 1 Восстановление сохраненного значения End If End Sub
Листинг П3.4. Процедура worksheet .Deactivate
Private Sub Worksheet.Deactivate()
Savl = Ll.Listindex ' Сохранение значений
Sav2 = L2.ListIndex
Sav3 = L3.Listindex
End Sub
Приложение 4
Процедуры листа Расписание
В листинге П4.1 приведена процедура, выполняемая по щелчку на кнопке
Заполнить.
j Листинг П4.1. Процедура заполнения расписания
Private Sub Com_Start_Click()
Dim mass(50) As Integer ' Массив для подсчета числа групп, ' входящих в поток
Range("a5:Z200").Select ' Очистка предыдущего расписания Selection.ClearContents
Selection.Interior.ColorIndex = 0
' Расчет количества потоков
NP = 0
While Worksheets(5).Cells(NP + 2, 1).Value <> _
"" Or Worksheets(5).Cells(NP + 2, 2).Value <> ""
NP = NP + 1
Wend
' Подсчет количества групп, входящих в каждый поток
For i = 1 То NP mass(i) =0 3 = 0 While Worksheets(5).Cells(i + 1, j + 2).Value <> 3=3+1
Wend
mass(i) ’ = j
Next
' Подсчет количества аудиторий
Приложения
N_Roo<ns = О While Worksheets(2).Cells(N_Rooms + 2, 1).Value <> ""
N_Rooms = N_Rooms + 1 wend set = 0	' Счетчик столбцов
' Заполнение названий групп и потоков For i а 1 То NP
Potok = Worksheets(7).Cells(i + 1, 1).Value
For j « 1 To mass(i) Cells(5, set + 3).Value a Potok Cells(6, set + 3).Value = Worksheets(5).Cells(i + 1, j + 1).Value set = set + 1
Next Next ' Подсчет количества дней N_Days - 0
While Worksheets(2).Cells(N_Pays + 2, 4).Value <> ""
NJ-®ys = N_Days + 1 Wend ' Подсчет количества занятий N_Times = о
While Worksheets(2).Cells(N_Times + 2, 5) .Value <>
N_Times = N_Times + 1 Wend ' Количество строк в расписании DayTimes = N_Times * N_Days ' Заполнение первых двух столбцов расписания Stroka = 7 For i = 1 То NjDays
For j = 1 To N_Times Cells(Stroka, 1).Value = Worksheets(2).Cells(i + 1, 4).Value Cells(Stroka, 2).Value = Worksheets(2).Cells(j + 1, 5).Value Stroka = Stroka + 1
Next Next ' Вычисление количества записей на первом листе N = 0	f
While Worksheets(1).Cells(N + 4, 1).Value <>
N = N + 1
Приложение 4. Процедуры листа Расписание 249
Wend
' Цикл по строкам первого листа
For i = 1 То N
Dayl = CStr(Worksheets(1).Cells(i + 3, 4).Value)
Timel = CStr(Worksheets(1).Cells(i + 3, 5).Value)
Groupl = CStr(Worksheets(1).Cells(i + 3, 9).Value)
Prepodl = CStr(Worksheets(1).Cells(i + 3, 3).Value)
Displ = CStr(Worksheets(1).Cells(i + 3, 10).Value)
Audi = CStr(Worksheets(1).Cells(i + 3, 8).Value)
Obsl = CStr(Worksheets(1).Cells(i + 3, 7).Value)
1 Если заявка обслужена или установлен флажок отображения всех заявок If Obsl = "да" Or Ch5.Value = True Then indie « 0
1 Проверка попадания заявки в указанный интервал недель
For j = CInt(Cl.Text) To CInt(C2.Text)
If CStr(Wprksheets(l).Cells(i +3, 11 + j).Value) = Then indicator = 1 Exit For
End If
Next
1 Если интервал недель соответствует
If indicator = 1 Then
' Цикл по столбцам
For ixn = 1 То set
If Groupl = CStr(Cells(5, im + 2).Value) _
Or Groupl = CStr(Cells(6, im + 2).Value) Then stolbec = im + 2 For j = 1 To DayTimes
If CStr(Cells(6 + j, 1).Value) = Dayl _
And CStr(Cells(6 + j, 2).Value) = Timel Then
If Cells(6 + j, stolbec).Value <> "" Then
Cells(6 + j, stolbec).Value = _ Cells(6 + j, stolbec).Value + Chr(10) End If
Cells(6 + j, stolbec).Value = _
Cells(6 + j, stolbec).Value + Displ + " "
If Ch4.Value = False Then ' Только предметы
Cells(б + j, stolbec).Value = _
Cells(6 + j, stolbec).Value + Prepodl
250
Приложения
Cells(6 + j, stolbec).Value = _
Cells(6 + j, stolbec).Value + " Ауд." + Audi + Chr(10) If Chi.Value = False Then
For jj = CInt(Cl.Text) To CInt(C2.Text)
ask =CStr(Worksheets(1).Cells(i+3,jj+11).Value)
If ask = Then
Cells(6 + j, stolbec).Value = _
Cells(6 + j, stolbec).Value + " " + Str(jj) + End If
Next
End If
If Ch2.Value = True Then
Cells(6 + j, stolbec).Value = _
Cells(6 + j, stolbec).Value + Chr(10) + _ "Заявка в стр." + Str(i + 3)
End If
End If
End If
Next
End If
Next ' Цикл по столбцам
End If ' Если интервал недель соответствует
End If * Если заявка обслужена
Next ' Завершение цикла по строкам первого листа
If Ch3 = True Then
udale ' Процедура удаления пустых строк при установке флага Ch3 End If
cvetl =35 ' Установка кодов двух цветов для расписания cvet2 = 40
а_1 = Cells(7, 1).Value
For i = 7 To 150
a_2 = Cells(i, 1).Value
If a_l <> a_2 Then ' При смене дня в расписании смена цвета vr_cvet = cvetl cvetl = cvet2 cvet2 = vr_cvet
End If	f
a_l = a_2 Rows(i).Select
Приложение 4. Процедуры листа Расписание 251
Selection.Interior.ColorIndex = cvetl
Next
Range(na7").Select
End Sub
На этом листе реализована удобная возможность для создания новых заявок на базе уже имеющихся. В этом случае работа для пользователя происходит по принципу копирования и вставки. При этом выделенная заявка с помощью кнопки Сору сначала копируется во внутренний буфер, а затем вставляется в другую (указанную пользователем) клетку расписания. Для реализации подобного эффекта нужно сначала написать для кнопки Сору предопределенную процедуру, приведенную в листинге П4.2.
| Листинг П4 2. Процедура обработки щелчка на кнопке Со, у
Private Sub CoirrnandButton4_Click()
NumRow = ActiveCell.Row ’ Получение номера строки выделенной ячейки
NumCol = ActiveCell.Column ' Получение номера столбца ячейки
Group = CStr(Cells(б, NumCol)) ' Выбор названия группы
Days = CStr(Cells(NumRow, 1)) ' Выбор названия дня
Times = CStr(Cells(NumRow, 2)) ' Выбор времени начала занятия
ColZ =0 'В этой переменной подсчитываем количество
' заявок для копирования
N = 0	* Подсчет числа заявок на первом листе
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
For i = 1 To N ' Цикл по числу заявок на первом листе
Dayl = CStr(Worksheets(1).Cells(i + 3, 4).Value)
Timel = CStr(Worksheets(1).Cells(i + 3, 5).Value)
Groupl = CStr(Worksheets(1).Cells(i + 3, 9).Value)
If Timel = Times And Dayl = Days And Group = Groupl Then
' Сравнение параметров заявки и параметров выделенной ячейки
For j = CInt(Cl.Text) To CInt(C2.Text)
zan = Worksheets(1).Cells(i +3, 11 + j).Value
If zan = Then
ColZ = ColZ + 1	' Запоминание заявки
mZ(ColZ) = i + 3 ' в массиве
Exit For
252________________________________________________________ Приложения
End If Next End If Next TextBoxl.Text = "" ' Очистка окна сообщений If ColZ > 0 Then For i  1 To ColZ
1 Вывод информации о скопированных заявках TextBoxl.Text = TextBoxl.Text + Str(mZ(i)) +
Next
Else TextBoxl.Text = ""
End If End Sub
В листинге П4.3 приведена процедура обработки щелчка на кнопке Вставить. В этом случае на основе заявок, предварительно скопированных в массив mz, формируются новые.
| Листинг П4.3. Процедура обработки щелчка на кнопке Вставить
Private Sub CommandButton5_Click()
NewRow = ActiveCell.Row ' Получение номера строки выделенной ячейки NewCol = ActiveCell.Column ' Получение номера столбца ячейки
If TextBoxl.Text = "" Then ' Если заявка не была скопирована, то выход Exit Sub
End If
N_Ayd = 0 ' Подсчет числа аудиторий
While Worksheets(2).Cells(N_Ayd + 2, 1).Value <> ""
N_Ayd = N_Ayd + 1
Wend
Group = CStr(Cells(6, NewCol)) ' Формирование в переменных группы, Days = CStr(Cells(NewRow, 1))	' дня и времени проведения занятия
Times = CStr (Cells(NewRow, 2))
For ia = 1 To ColZ ' Цикл по количеству скопированных заявок
N = 0 ' Подсчет числа имеющихся заявок
While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1
Wend
Приложение 4. Процедуры листа Расписание
253
flagZ = 0 ' Индикатор возможности копирования заявки
For i = 4 То N + 3
g_i = CStr(Worksheets(1).Cells(i, 9).Value)
d_i = CStr(Worksheets(1).Cells(i, 4).Value)
v_i = CStr(Worksheets(1).Cells(i, 5).Value)
o_i « CStr(Worksheets(1).Cells(i, 7).Value)
If Days = d_i And Times = v_i And g_i = Group Then For m = 0 To 17
If Worksheets(1).Cells(i, 11 + m) .Value = "*" _
And Worksheets(1).Cells(mZ(ia), 11 + m).Value = Then flagZ = 1 Exit For
End If
Next
End If
If flagZ = 1 Then
Exit For
End If
Next
If flagZ <> 1 Then
1 Начало копирования заявки
Worksheets(1).Unprotect
Worksheets(1).Cells(N + 4, 1).Value = _
Worksheets(1).Cells(mZ(ia), 1).Value
Worksheets(1).Cells(N + 4, 2).Value = _
Worksheets(1).Cells(mZ(ia), 2).Value
Worksheets(1).Cells(N + 4, 10).Value = _
Worksheets(1).Cells(mZ(ia), 10).Value
Worksheets(1).Cells(N + 4, 3).Value = _
Worksheets(1).Cells(mZ(ia), 3).Value
Worksheets(1).Cells(N + 4, 4).Value = Days
Worksheets(1).Cells(N + 4, 5).Value = Times
Worksheets(1).Cells(N + 4, 9).Value = Group
N_Group = 0 ' Подсчет числа групп ng
While Worksheets(2).Cells(N_Group + 2, 8).Value <> ""
N_Group = NjGroup + 1
Wend
For ib = 1 To N_Group
If Worksheets(2).Cells(ib + 1, 8).Value = Group Then
254
Приложения
Exit For End If Next ' Подстановка количества студентов в указанной группе Worksheets(1).Cells(N + 4, б).Value = _ Worksheets(2).Cells(ib + 1, 9).Value
For ic = 11 To 28 ' Переносим недели в новую заявку Worksheets(1).Cells(N + 4, ic).Value = _
Worksheets(1).Cells(mZ (ia), ic).Value Next Prepod = CStr(Worksheets(1).Cells(N + 4, 3).Value) Disp = CStr(Worksheets(1).Cells(N + 4, 10).Value) Ayd = CStr(Worksheets(1).Cells(N + 4, 8).Value) Obs = CStr(Worksheets(1).Cells(N + 4, 7).Value) ' Если заявка обслужена
If Obs = "да" Or Ch5.Value = True Then indie = 0 For j = CInt(Cl.Text) To CInt(C2.Text) If CStr(Worksheets(1).Cells(N +4, 11 + j).Value} = Then , indicator = 1
Exit For End If Next * Если интервал недель соответствует If indicator = 1 Then
If Cells(NewRow, NewCol).Value <> "" Then Cells(NewRow, NewCol).Value = _ Cells(NewRow, NewCol).Value + Chr(10) End If Cells(NewRow, NewCol).Value = _ Cells(NewRow, NewCol)-Value + Disp + " " If Ch4.Value = False Then 'Только предметы Cells(NewRow, NewCol).Value = _ Cells(NewRow, NewCol).Value + Prepod Cells(NewRow, NewCol).Value = _
Cells(NewRow, NewCol).Value + " Ауд." + Ayd + Chr(10) If Chi.Value = False Then
For jh = CInt(Cl.Text) To CInt(C2.Text)	f
ask = CStr(Worksheets(1).Cells(N +4, jh + 11).Value)
Приложение 4. Процедуры листа Расписание
255
If ask = Then
Cells(NewRow, NewCol).Value = _
Cells(NewRow, NewCol).Value + " " + Str(jh) + ",* End If
Next
End If
If Ch2.Value = True Then
Cells (NewRow, NewCol).Value ₽ _
Cells(NewRow, NewCol).Value + Chr(10) + _ "Заявка в стр." + Str(N + 4) End If
End If 1 Условие по предметам
End If ' Если интервал недель соответствует End If ' Если заявка обслужена
End If
Next
End Sub
В начале главы 6 мы говорили об удобной возможности удаления заявок.
В листинге П4.4 приведена процедура обработки щелчка на кнопке Delete.
Листинг П4.4. Процедура удаления заявок
Private Sub ComnandButton6_Click()
NumRow = ActiveCell.Row ' Получение номера строки выделенной ячейки NumCol = ActiveCell.Column ' Получение номера столбца ячейки Group = CStr(Cells(б, NumCol)) ' Формирование в переменных группы, Days = CStr (Cells (NumRow, 1))	1 дня и времени проведения занятия
Times = CStr(Cells(NumRow, 2))
ColZ = 0 ' Подсчет количества удаляемых заявок
N = 0 ' Подсчет числа имеющихся заявок
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
For i = 1 To N ' Цикл по заявкам на первом листе
d_i = CStr(Worksheets(1).Cells(i + 3, 4).Value)
v_i = CStr(Worksheets(1).Cells(i + 3, 5).Value)
g_i = CStr(Worksheets(1).Cells(i + 3, 9).Value) If v_i = Times And Days = d_i And Group = g_i Then
2S6 Приложения
For j « CInt(Cl.Text) To CInt(C2.Text) zan » Worksheets(1).Cells(i +3, 11 + j).Value If zan = Then ColZ = ColZ + 1 mZ(ColZ) = i + 3 ' Отмечаем в массиве заявки, Exit For	' которые надо удалить
End If Next End If
Next
TextBoxl.Text = ""	' Очистка окна сообщений
Worksheets(1).Uhprotect 1 Снятие защиты с первого листа
For i  ColZ То 1 Step -1 ' Удаляем заявки, предварительно j = raZ(i)	' занесенные в массив mZ
Worksheets(1).Rows(j).Delete TextBoxl.Text = "Заявки удалены"
Next Cells(NumRow, NumCol).Value = ""	' Очистка ячейки
' Установка защиты
Worksheets(1).Protect DrawingObj ects:«True, _ Contents:“True, Scenarios:=True End Sub
Кнопка Печать позволяет напечатать расписание. В этом случае информация переносится на новый лист, который уже может быть напечатан.
В листинге П4.5 приведена процедура обработки щелчка на кнопке Печать.
| Листинг П4.5. Процедура обработки щелчка на кнопке Печать
Private Sub CommandButton2_Click()
' В книге для печати расписания седьмой лист - лист Worksheets(7).Range("al:Z100").Value = ""
' Переносим информацию с текущего листа на седьмой
Worksheets(7).Range("al:Z100").Value = Range("a5:Z105").Value Worksheets(7).Activate
End Sub	f
Мы говорили о возможности смены параметров заявки. Для этого двойным щелчком на ячейке расписания открывается форма (см. рис. 6.23), с помощью
Приложение 4. Процедуры листа Расписание 257
которой несложно изменить реквизиты заявки. В листинге П4.6 приведена предопределенная процедура, которая выполняется в этом случае. В процессе ее выполнения открывается форма смены параметров заявки (Name = uzam). Как видно из рис. 6.23, в форме два элемента типа "список": один — для смены преподавателя (Name = рр), а другой — для смены группы (Name = нн). Для флажков, присутствующих в форме, значения свойства Name выбраны традиционно: chi, ch2, ch3 и т. д.
| Листинг П4 6. Обработка двойного щелчка на ячейке расписания
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range,
Cancel As Boolean)
' Информация по выделенной ячейке
NumRow = ActiveCell.Row ' Номер строки
NumCol = ActiveCell.Column ' Номер столбца
Group = CStr(Cells(6, NumCol)) ' Группа
Days = CStr(Cells(NUmRow, 1)) ' День
Times = Cells(NumRow, 2)	' Начало занятия
' Переменная для подсчета количества заявок в ячейке
ColZ = О
' Подсчет числа заявок на первом листе
N = О
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
For i ж 1 To W ’ Цикл по заявкам
' Считывание дня, времени и группы очередной заявки с первого листа
Dayl “ CStr(Warkaheets(l).Cells(i + 3, 4).Value)
Tiraesl ж C$tjr(Worksheets(1) .Cells(i + 3, 5) .Value)
Groupl ® CStr(Worksheets(1).Cells(i + 3, 9).Value)
If Timesl ж Times And Days = Dayl And Group = Groupl Then
For j = CInt(Cl.Text) To CInt(C2.Text)
If Worksheets(1).Cells(i +3, 11 + j).Value = Then
ColZ = ColZ + i
mZ(ColZ) = i + 3 ' Записываем найденную заявку в массив Exit For
End If
Next
End If
Г Приложения
25S
Next ' Завершение цикла по заявкам
For i = 1 То ColZ 'Цикл по отобранным заявкам в ячейке
' Через ячейку Celled, 50)передаем номер строки заявки на первом листе kl = mZ(i) «forksheets(4).Cells(1, 50) = kl
If Worksheets(1).Cells(kl, 11).Value <> "* Then UZam.ChO.Value = “True"
Else
UZam.ChO.Value = "False"
End If
If Worksheets(1).Cells(kl, 12).Value <> "" Then UZam.Chi.Value = "True"
Else
UZam. Chi.Value = "False"
End If
If Worksheets(1).Cells(kl, 13).Value <> "" Then UZam.Ch2.Value = "True"
Else
UZam. Ch2.Value = "False"
End If
If Worksheets(1).Cells(kl, 14).Value <> "" Then UZam.Ch3.Value = "True"
Else
UZam. Ch3.Value = "False"
End If
If Worksheets(1).Cells(kl, 15).Value <> "" Then UZam. Ch4.Value = "True"
Else
UZam. Ch4.Value = "False"
End If
If Worksheets(1).Cells(kl, 16).Value <> "" Then UZam.Ch5.Value = "True"
Else
UZam. Ch5.Value = "False"
End If
If Worksheets(1).Cells(kl, 17).Value <> "" Then UZam. Ch6.Value = "True"
Else	f
UZam. Ch6.Value = "False"
Приложение 4. Процедуры листа Расписание
259
End If
If Worksheets(1).Cells(kl, 18).Value <> "" Then UZam. Ch7.Value = "True"
Else
UZam.Ch7.Value = "False"
End If
If Worksheets(1).Cells(kl, 19).Value <> "" Then UZam. Ch8.Value = "True"
Else
UZam.Ch8.Value = "False"
End If
If Worksheets(1).Cells(kl, 20).Value <> "" Then UZam.Ch9.Value = "True"
Else
UZam.Ch9.Value = "False"
End If
If Worksheets(1).Cells(kl, 21).Value <> "" Then UZam. Chi0.Value = "True"
Else
UZam. Chi0.Value = "False"
End If
If Worksheets(1).Cells(kl, 22).Value <> "" Then UZam. Chi1.Value = "True"
Else
UZam. Chi1.Value = "False"
End If
If Worksheets(1).Cells(kl, 23).Value <> "" Then UZam. Chi2.Value = "True"
Else
UZam. Chi2.Value = "False"
End If
If Worksheets(1).Cells(kl, 24).Value <> "" Then UZam. Chi3.Value = "True"
Else
UZam.Chl3.Value = "False"
End If
If Worksheets(1).Cells(kl, 25).Value <> "" Then UZam.Chl4.Value = "True"
Else
260
Приложения
UZam.Chl4.Value = "False" End If If Worksheets(1).Cells(kl, 26).Value <> "" Then UZam.Chl5.Value = "True"
Else UZam.Chl5.Value = "False" End If If Worksheets(1) .Cells(kl, 27) .Value <> Then UZam.Chl6.Value = "True"
Else UZam.Chl6.Value = "False" End If If Worksheets(1).Cells(kl, 28).Value <> "" Then UZam.Chl? .Value = "True"
Else UZam.Chl?.Value = "False" End If UZam.Show
Next 'Завершение цикла no отобранным заявкам ' Блок обновления информации в ячейке Cells (NumRow, NuinCol) .Value = ""
For i » 1 To ColZ 'Цикл числу заявок в выделенной ячейке ii - xnZ(i)
DayNew  CStr(Worksheets(1).Cells(ii, 4).Value)
TimesNew  CStr(Worksheets(1) .Celled!, 5).Value)
GroupNew  CStr(Worksheets(1).Cells(ii, 9).Value) PrepodNew = CStr(Worksheets(1).Cells(ii, 3).Value) DispNew  CStr(Worksheets(1).Cells(ii, 10).Value) AudNew  CStr(Worksheets(1).Cells(ii, 8).Value) ObsNew з CStr(Worksheets(1).Cells(ii, 7).Value) If ObsNew а "да" Or Ch5.Value  True Then ' Если заявка обслужена либо установлен соответствующий флаг indicator  0 For j - CInt(Cl.Text) To CInt(C2.Text)
If CStr(Worksheets(1).Cells(ii, 11 + j).Value) = Then indicator = 1 Exit For
End If
Next
If indicator = 1 Then 1 Если интервал недель соответствует
Приложение 4. Процедуры листа Расписание 261
If Cells (NumRow, NumCol) .Value <> "" Then Cells(NumRow, NUmCol).Value = Cells(NUmRow, NumCol).Value _ + Chr(10)
End If Cells(NumRow, NumCol).Value = _ Cells(NumRow, NumCol).Value + DispNew + " " If Ch4.Value = False Then ' Если флажок "Только предметы" сброшен
Cells(NumRow, NumCol).Value = Cells(NumRow, NumCol).Value _ + PrepodNew
Cells(NumRow, NumCol) .Value = Cells(NumRow, NumCol) .Value + _
" Ауд." + AudNew + Chr(10) ' Если флажок "He выводить недели" сброшен If Chi.Value = False Then
For jj « CInt(Cl.Text) To CInt(C2.Text) 'Цикл 1
ask = CStr(Worksheets(1).Cells(ii, jj + 11).Value) If ask = "*" Then
Cells(NumRow, NunCol) .Value = _
Cells(NumRow, NumCol).Value + " " + Str(jj) + End If
Next End If If Ch2.Value = True Then 1 Флажок указания номера заявки
Celle(NumRow, NumCol) .Value • _
Cells(NumRow, NumCol).Value + Chr(10) + "Заявка в стр.* _ + Str(ii)
End If
End If 1 Флажок "Только предметы"
End If	1 Интервал недель соответствует
End If	' Заявка обслужена
Next End Sub
В листинге П4.7 приведена процедура, которая выполняется при активизации формы, приведенной на рис. 6.23.
Г’“	.................
I Листинг П4.7. Процедура активизации формы для смены параметров заявки
Private Sub UserForm_Activate()
N_Prepod « 0 ' Подсчет числа преподавателей While Worksheets(2).Cells(N_Prepod + 2, 7).Value <> ""
Приложения
262
N_Prepod = N_Prepod + 1
Wend
PP.Clear ' Заполнение списка преподавателей в форме
For i = 1 То I<_Prepod
РР.Additem Worksheets(2).Cells(i + 1, 7).Value
Next
NJDisp = 0 ’ Подсчет числа предметов
While Worksheets(2).Cells(N_Disp + 2, 10).value <> ””
N_Disp = N_Disp + 1
Wend
HH.Clear 1 Заполнение списка предметов
For i = 1 To N_Disp
HH.Addltem Worksheets(2).Cells(i + 1, 10).Value
Next
HH.Listindex = -1
PP.Listlndex = -1
End Sub
В листинге П4.8 приведена процедура обработки щелчка На кнопке Записать в форме смены параметров заявки
Листинг П4.8. Обработка щелчка на кнопке Записать в форме смены параметров заявки
Private Sub Zap_Click()
Nom = Worksheets(4).Cells(1, 50) ' Считывание строки изменяемой заявки Worksheets(1).Unprotect ' Снятие защиты с листа If PP.Listlndex <> -1 Then 1 Установка преподавателя Worksheets(1).Cells(Nom, 3).Value = PP.Text End If If HH.Listindex <> -1 Then 1 Установка дисциплины
Worksheets(1).Cells(Nom, 10).Value = HH.Text End If If ChO .Value = True Then
Worksheets(1).Cells(Nom, 11).Value = "*"	. >
Else
Worksheets(1).Cells(Nom, 11).Value = "”
End If
Приложение 4. Процедуры листа Расписание
263
If Chi.Value = True Then Worksheets(1).Cells(Nom, 12).Value =
Else
Worksheets(1)-Cells(Nom, 12).Value = nn End If If Ch2.Value = True Then
Worksheets(1)-Cells(Nom, 13).Value = Else
Worksheets(1)-Cells(Nom, 13).Value = "" End If If Ch3.Value = True Then
Worksheets(1).Cells(Nom, 14).Value = "*" Else
Worksheets(1).Cells(Nom, 14).Value = "n End If If Ch4.Value = True Then
Worksheets (1) .Cells (Nom, 15).Value = Else
Worksheets(1).Cells(Nom, 15)-Value = "" End If If Ch5.Value = True Then
Worksheets(1).Cells(Nom, 16).Value = Else
Worksheets(1).Cells(Nom, 16).Value = "" End If If Ch6.Value = True Then
Worksheets(1).Cells(Nom, 17).Value = Else
Worksheets(1).Cells(Nom, 17).value = "" End If If Ch7.Value = True Then
Worksheets(1).Cells(Nom, 18).Value = Else
Worksheets(1).Cells(Nom, 18).Value = "" End If If Ch8.Value = True Then
Worksheets(1).Cells(Nom, 19).Value = "*n Else
Приложения
264 
Worksheets(1).Cells(Nom, 19).Value = "" End If If Ch9.Value = True Then
Worksheets(1).Cells(Nom, 20).Value = Else
Worksheets(1).Cells(Nom, 20).Value = "" End If If ChlO.Value = True Then
Worksheets(1).Cells(Nom, 21).Value = "*" Else
Worksheets(1).Cells(Nom, 21).Value = "" End If If Chll.Value = True Then
Worksheets(1).Cells(Nom, 22).Value = "*" Else
Worksheets(1).Cells(Nom, 22).Value = "" End If If Chl2.Value = True Then
Worksheets(1).Cells(Nom, 23).Value =
Else
Worksheets(1) .Cells(Nom, 23) .Value = "" End If If Chl3.Value = True Then
Worksheets(1).Cells(Nom, 24).value = Else
Worksheets(1).Cells(Nom, 24).Value = "" End If If Chl4.Value = True Then
Worksheets(1).Cells(Nom, 25).Value = Else
Worksheets(1).Cells(Nom, 25).Value = "n End If If Chi5.Value = True Then
Worksheets(1).Cells(Nom, 26).Value = Else
Worksheets(1).Cells(Nom, 26).Value = "" End If If Chl6.Value = True Then
Приложение 4. Процедуры листа Расписание
Worksheets(1).Cells(Nom, 27).Value = Else
Worksheets(1).Cells(Nom, 27).Value = nn End If If Chl7.Value = True Then
Worksheets(1).Cells(Nom, 28).Value = Else
Worksheets(1).Cells(Nom, 28).Value = "" End If UZam.Hide ' Скрытие формы End Sub
Приложение 5
Процедуры листа Отчет 2
В листинге П5.1 приведена процедура, выполняемая по щелчку на кнопке Заполнять. В этом случае мы получаем карту загрузки фонда аудиторий по факультетам (либо просто по подразделениям).
| Листинг П5.1. Процедура заполнения отчета по факультетам	|
Private Sub CommandButtonl_Click() Dim colors(10) As Integer colored) = 4 1 Установка цветов colors(2) = 22 ' для обозначения факультетов colors(3) = 19 colors(4) = 24 colors(5) = 26 colors(6) = 40 colors(7) = 43 colors(8) = 44 colors(9) = 6 colors(10) =28
If LI.Listindex = -1 Then ' Выход, если не выбрана неделя MsgBox (" Не выбрана неделя ") Exit Sub
End If
Range("a5:AZ100").Select ' Очистка области данных Selection.ClearContents 1 Подсчет количества учебных дней в неделе N_Day = 0
While Worksheets(2).Cells(N_Day + 2, 4).Value <> n"
Приложение 5. Процедуры листа Отчет 2 267
N_Day = N_Day + 1
Wend ' Подсчет количества занятий в течение дня N_Times = О
While Worksheets(2).Cells(N_Times + 2, 5).Value <> ""
N_Times = N_Times + 1
Wend ' Подсчет количества аудиторий N_Ayd = О
While Worksheets(2).Cells(N_Ayd + 2, 1).Value <> ""
N_Ayd = N_Ayd + 1
Wend
DaysTimes = N_Day * N_Times
N_Boss = 0 1 Подсчет заявителей
While Worksheets (2) .Cells(N_Boss + 2, 6) .Value <> ""
N_Boss = N_Boss + 1
Wend
Range("b7:AZ100").Select
With Selection.Interior ' Заливка белым цветом области вывода .ColorIndex = О .Pattern = xlSolid
End With
For i = 1 To N_Boss
Cells(2, 2 + i * 2).Select
With Selection.Interior ' Установка обозначений .ColorIndex = colors(i) ' цветов заявителей •Pattern = xlSolid
End With
' Установка подписей заявителей для соответствующих цветов
Cells(l, 2 + i * 2).Value = Worksheets(2).Cells(i + 1, 6).Value Next
' Подсчет количества строк с заявками на первом листе N = О
While Worksheets(1).Cells(N + 4, 1).Value <> "" N = N + 1
Wend
Stroka = 7 ' Данные на листе размещаются начиная с седьмой строки
For i = 1 То N_J\yd ' Установка подписей аудиторий Cells(Stroke, 1).Value = _
Гприложения
£68
Worksheets(2).Cells(i + 1, 1).Value Stroka = Stroka + 1 Next St = 1 For i = 1 To N_Day ' Установка подписей занятий For j = 1 To N_Times St = St + 1 Cells(5, St).Value = Worksheets(2).Cells(i + 1, 4).Value Cells(6, St).Value = Worksheets(2).Cells(j + 1, 5).Value Next Next For i = 1 To DaysTimes For j = 1 To N_Ayd
Cells(6 + j, i + 1) =0 'Инициализация ячеек Next Next
For i » 4 To N + 3 ' Цикл по строкам заявок
If CStr(Worksheets(1).Cells(i, 7).Value) = "да" Then ’ Выполнение условия по обслуживанию заявки Stroka = 0 For ia = 1 То N_Ayd
If CStr(Worksheets(1).Cells(i, 8).Value) = _ CStr(Cells(ia + 6, 1).Value) Then
Stroka = ia + 6 Exit For End If Next
If Stroka > 0 And _
CStr(Worksheets(1).Cells(i, CInt(Ll.Text) + 11).Value) = Then ' Если есть строка с указанной аудиторией
For m = 1 То DaysTimes ' Нахождение столбца на листе для помещения заявки
If CStr(Worksheets(1).Cells(i, 4).Value) = _ CStr(Cells(5, 1 + m).Value) Then
If CStr(Worksheets(1).Cells(i, 5).Value) =_ CStr(Cells(6, 1 + m).Value) Then stolbec = 1 + m Exit For
Приложение 5. Процедуры листа Отчет 2 269
End If End If Next nomer = 1 For iy = 1 To N_Boss 'Определение заявителя в заявке If CStr(Worksheets(1).Cells(i, 2).Value) = _
CStr(Worksheets(2).Cells(iy + 1, 6).Value) Then nomer = iy Exit For End If Next Cells(Stroka, stolbec).Value = _ Cells(Stroka, stolbec).Value + _ Worksheets(1).Cells(i, 6).Value Cells(Stroka, stolbec).Select With Selection.Interior .Colorindex = colors(nomer) ' Установка заливки .Pattern = xlSolid	' для ячейки
End With End If End If Next Range("a5").Select End Sub
Приложение 6
Процедуры листа Отчет 3
В листинге П6.1 приведена процедура, выполняемая по щелчку на кнопке Заполнить. В этом случае заполняется карта загрузки фонда аудиторий.
| Листинг П6.1. Процедура заполнения загрузки фонда аудиторий
Private Sub CommandButtonl_Click()
' Очистка области листа от старых данных
Range("a5:AZ100").Select
Selection.ClearContentp
Tl.Visible = False ' Убираем с экрана информационное окно
NJDays = 0 ' Подсчет количества учебных дней в неделе
While Worksheets(2).Cells(NJDays + 2, 4).Value <> ""
NJDays = NJDays + 1
Wend
' Подсчет количества занятий в течение дня
NJTimes = 0
While Worksheets(2) .Cells(NJTimes + 2, 5).Value <> ""
NJTimes = NJTimes + 1
Wend
1 Подсчет количества аудиторий
N_Rooms = 0
While Worksheets(2).Cells(N_Rooms + 2, 1).Value <> ""
N_Rooms = N_Rooms + 1
Wend
' Расчет количества занятий в течение недели
DaysTimes = N_Days * NJTimes
For i = 1 To DaysTimes
Приложение 6. Процедуры листа Отчет 3 271
For j = 1 То NJtooms Cells(б + j, i + 1) =0 ' Инициализация ячеек нулями
Next
Next
’ Подсчет числа заявителей
N_Boss = 0
While Worksheets(2).Cells(N_Boss + 2, 6).Value <> ""
NJBoss = N_Boss + 1
Wend
Range("b7:AZ100").Select ' Заливка белым цветом области вывода
With Selection.Interior
.ColorIndex = 0
.Pattern = xlSolid
End With
' Подсчет количества строк на первом листе
N = 0
While Worksheets(1).Cells(N + 4, 1).Value о ""
N = N + 1
Wend
Stroka = 7 ' Вывод информации начинаем с седьмой строки
For i = 1 То NJRooms ' Заполнение столбца аудиторий
Cells(Stroka, 1).Value = Worksheets(2).Cells(i + 1, 1).Value
Stroka = Stroka + 1
Next
St = 1 ' Заполнение дней и времени начала занятий
For i = 1 То NJDays
For j = 1 То NJTimes
St = St + 1
Cells(5, St).Value = Worksheets(2).Cells(i + 1, 4).Value
Cells(6, St).Value = Worksheets(2).Cells(j + 1, 5).Value
Next
Next
N^Ayd = 0 ' Подсчет аудиторий, занесенных на этот лист
While Cells (N_JVyd + 7, 1) .Value о ""
N^Ayd = N_Ayd + 1
Wend
For j = CInt(Ll.Text) To CInt(L2.Text) ' Цикл по указанным неделям
For i = 4 To N + 3 ' Цикл по строкам первого листа If CStr(Worksheets(1).Cells(i, 7).Value) = "да" Then
Приложения
ITS
’ Если заявка обслужена, то ищем ей место на листе Nayd » Worksheets(1) .Celled, 8) .Value Stroka = О For m = 1 To N
If CStr(Nayd) = CStr(Cells(m + 6, 1).Value) Then Stroka = m + 6 Exit For End If
Next
' Если не найдена аудитория, указанная в строке на первом листе If Stroka = 0 Then infornutext = "Ошибка в данных в строке” + CStr(i) MsgBox (infornutext) Range("Al").Select Exit Sub
End If
For m = 1 To DaysTimes
' Поиск столбца для отображения заявки
If CStr(Worksheets(1) .Celled, 4) .Value) = CStr(Celle(5, 1 + _ m).Value) And CStr(Workeheete(1).Cells(i, 5).Value) =_ CStr(Cells(6, 1 + m).Value) Then
Stolbec я 1 + m Exit For End If
Next
' Фрагмент для учета групповых занятий
If Worksheets(1) .Celled, j + 11) .Value = And _ Cells(Stroka, Stolbec).Value < 1000 Then Cells(Stroka, Stolbec) » Cells(Stroka, Stolbec) + 1 Cells(Stroka, Stolbec) = Cells(Stroka, Stolbec) * 1000
1 Добавляем 1000 для пометки внесенного занятия и исключения ' в дальнейшем повторного счета при групповом занятии End If
End If
Next
For ii в 1 To DaysTimes ' Корректировка чисел на 1000
For jj в 1 To NJRooms a = CInt(Cells(jj + 6, ii + 1).Value)	’
If a >« 1000 Then
Приложение 6. Процедуры листа Отчет 3 273
Cells(jj +6, ii + 1).Value = Cellstjj +6, ii + 1).Value - 1000 End If Next Next Next ' Расцвечивание занятий Maximum = CInt(L2.Text) - CInt(LI.Text) + 1 porog = CInt (Maximum / 2) ' Порог - половина занятых дней в указанном интервале For i = 1 То DaysTimes For j = 1 То NJRooms a = CInt(Cells(j + 6, i + 1).Value) ' Количество занятий If a = Maximum Then Cells(j + 6, i + 1).Select With Selection.Interior .Colorindex = 7 ' Расцвечивание при максимальной занятости .Pattern = xlSolid End With
Elself a <= porog And a > 0 Then Cells(j + 6, i + 1).Select With Selection.Interior
.ColorIndex = 8 ' Расцвечивание при занятости меньше средней .Pattern » xlSolid End With Elself a > porog And a < Maximum Then Cells(j + 6, i + 1).Select With Selection.Interior
.ColorIndex » 15 .Pattern = xlSolid End With End If Next Next Range("a5").Select TI. visible = True End Sub
Теперь, после заполнения суммарной информации о фонде аудиторий, можно просмотреть, какое занятие конкретно проводи гея в указанное время. Для этого
274
Приложения
нужно лишь выделить с помощью мыши интересующую нас ячейку на листе Excel.
В листинге П6.2 приведена процедура, реализующая это действие.
| Листинг П6.2. Процедура просмотра информации о занятии в аудитории
Private Sub Worksheet_SelectionChange(ByVal Target As Range) NumStr = ActiveCell.Row ' Получение номера строки и столбца NumCol = ActiveCell.Column	' активной ячейки
If NumCol <> 1 Then ' В первом столбце перечисляются аудитории If CSr(ActiveCell.Value) = "0" Then
Exit Sub ' Если в ячейке 0, то вывода информации не требуется End If Tl.Text = "" 1 Очистка окна сообщений N_Days = 0 ' Подсчет числа дней While Worksheets(2).Cells(N_Days + 2, 4).Value <> •"
N_Days = N_Days +1 Wend
N_Times = 0 1 Подсчет числа занятий в течение дня
While Worksheets(2).Cells(N_Times + 2i 5).Value <> •"
NJTimes = NJTimes + 1 Wend ' Количество строк DaysTimes = N_Days * NJTimes N = 0 While Worksheets(1).Cells(N + 4, 1).Value <> " N = N + 1 Wend ' Цикл по строкам первого листа For i = 1 To N
Dayl = CStr(Worksheets(1).Cells(i + 3, 4).Value)
Timel = CStr(Worksheets(1).Cells(i + 3, 5).Value)
Groupl = CStr(Worksheets(1)-Cells(i + 3, 9).Value)
Prepodl = CStr(Worksheets(1).Cells(i + 3, 3).Value)
Displ = CStr(Worksheets(1).Cells(i + 3, 10).Value)
Audi = CStr(Worksheets(1).Cells(i + 3, 8).Value) Obsl = CStr(Worksheets(1).Cells(i + 3, 7) .Value) If Obsl = "да" Then ' Если заявка обслужена
indicator = 0
Приложение 6. Процедуры листа Отчет 3 275
For j = CInt(LI.Text) To CInt(L2.Text) If CStr(Worksheets(1).Cells(i +3, 10 + j).Value) = Then indicator = 1 Exit For End If
Next 1 Если интервал недель соответствует указанному на листе If indicator = 1 Then
If Dayl = CStr(Cells(5, NumCol).Value) And _ Timel = CStr(Cells(6, NumCol).Value) _ And CStr(Cells(NumStr, 1).Value) = Audi Then If Tl.Text <> "" Then
Tl.Text = Tl.Text + Chr(10) End If Tl.Text = Tl.Text + Displ Tl.Text = Tl.Text + " " + Prepodl For j = CInt(Ll.Text) To CInt(L2.Text) 'Цикл 1 ask = CStt(Worksheets(1).Cells(i + 3, j + 11).Value) If ask = Then
Tl.Text = Tl.Text + " " + Str(j) + End If Next End If End If ' Условие интервала недель End If 1 Условие о том, что заявка обслужена Next 1 Завершение цикла по строкам первого листа ТЗ.Visible = False Elself NumStr > 6 Then ТЗ.Visible = True T3.Text = "Вместимость " + Str(Worksheets(2).Cells(NumStr - 5, 2)) _ + " чел " End If End Sub
Приложение 7
Процедуры, связанные с листом Расчет
Этот лист позволяет получить отчет о выполненной нагрузке с учетом нерабочих дней, которые пользователь может указать самостоятельно. Процедура, выполняемая по щелчку на кнопке Расчет, приведена в листинге П7.1. Перед этим, как уже говорилось в главе 6 книги, необходимо указать интересующий нас месяц в поле со списком.
| Листинг П7.1. Процедура заполнения отчета по выполненной нагрузке
Private Sub Согц_1_СИск() Dim Ned As Integer Dim Den As String
1 Установка номеров месяцев
If mesac.Listlndex > -1 And mesac.Listlndex < 4 Then narMes = 9 + mesac.Listlndex
Elself mesac.Listlndex > 3 Then nomMes = mesac.Listlndex - 3 Else
MsgBox ("Месяц не указан, либо месяц — не учебный") Exit Sub End If
N_Prepod = 0 ' Подсчет числа преподавателей
While Worksheets(2).Cells(N_Prepod + 2, 7).Value <> "" NJPrepod = N_Prepod + 1
Wend
Range ("A7 :B1000") ..Select ' Очистка листа Selection.ClearContents
Range("A5 *).Select	9
Приложение 7. Процедуры, связанные с листом Расчет 277
1 Заполняем текущий лист фамилиями преподавателей For i = 1 То N_Prepod Cells(i + б, 1) = Worksheets(2).Cells(i + 1, 7).Value Next N = 0 1 Подсчет числа заявок на первом листе While Worksheets(1).Cells(N + 4, 1).Value о "" N = N + 1 Wend ' Цикл по преподавателям For j = 1 To N_Prepod
Fan\_Prepod = Cells(j + 6, 1).Value ' Выбираем фамилию преподавателя Range("17:AZ1000").Select 1 Очистка служебной области Selection.ClearContents Range("A5").Select ' Перенос заявок по преподавателю в служебную область Stroka - 7 For i = 4 То N + 3 ' Цикл по строкам заявок
FanU?repodl = CStr(Worksheets(1).Cells(i, 3).Value) If Fan\_Prepodl = Fan\_Prepod Then 1 При нахождении преподавателя переносим информацию
Cells(Stroka, 9) = Worksheets(1).Cells(i, 4)	1 Устанавливаем день
Cells(Stroka, 10) = worksheets(1).Cells(i, 5) * Устанавливаем время For m = 0 To 17 ' Отмечаем недели
Cells(Stroka, 11 + m) = worksheets(1).Cells(i, 11 + in) Next Stroka = Stroka + 1 End If Next shet = 0	' Подсчитываем количество перенесенных заявок
While Cells(shet + 7, 9).Value <> "" shet = shet + 1 Wend ' Удаление лишних заявок при групповом занятии For 1 = shet То 2 Step *-1 For k = 1 - 1 То 1 Step -1
If Cells(1 + 6, 9).Value = Cells(k + 6, 9).Value And _ Cells(l + 6, 10).Value = Cells(k + 6, 10).Value Then For Ik = 1 To 18 If Cellsd + 6, Ik + 10) .Value = Then
Приложения
279 
Cells(k + 6, Ik + 10) .value = ,,*n End If Next ' Очистка одной из групповых заявок For ink = 1 То 20 Cells(l + б, mk + 8) .Value = ,,н Next End If Next Next ' Завершение блока удаления лишних заявок sym = 0 ' Подсчет числа проведенных занятий For i = 1 То shet ' Цикл по строкам Den = CStr(Cells(i + б, 9).Value) For ik = 11 To 28 Ned » ik - 11 ' Получение номера недели If Cells(i + 6, ik).Value = Then Da_Ta = PolData(Ned, Den) 1 Вычисление даты indicator = 0 ' Индикатор попадания занятия на праздник For ikl = 2 То 50 ' Цикл по фрагменту нерабочих дней DaJTa2 = CDate(Cells(ikl, 8)) ' Сравнение даты занятия с нерабочими днями If Da_Ta2 = Da_Ta Then indicator = 1 Exit For End If Next If indicator = 0 Then * Если занятие имело место (не попало на праздник) mes = DatePart("m", Da_Ta) ' Извлечение месяца из даты If mes = norriMes Then ' Если месяцы совпадают sym = sym + 1 End If End If End If Next Next
’ Установка количества отработанных часов для преподавателей Cells(j + б, 2) = sym
Next End Sub
Приложение 7. Процедуры, связанные с листом Расчет 279
При выполнении данной процедуры требуется вспомогательная функция (листинг П7.2), позволяющая получить дату по указанным номеру недели и дню недели.
| Листинг П7.2. Вспомогательная функция PolData	j
Function PolData(NumNed As Integer, Den As String) As Date
Dim BeginData As Date
BeginData = Range("DI").Value ' Считывание понедельника нулевой недели
N_Days = О
While Worksheets(2).Cells(N_Days + 2, 4).Value <> ""
NJDays = N_Days + 1
Wend
chDn = -1 ' Индикатор дня недели
For I =1 To N_Days
If Worksheets(2).Cells(i + 2, 4).Value = CStr(Den) Then chDn =1-1
End If
Next
If chDn = -1 Then
PolData = BeginData
MsgBox ("Ошибка в данных по указанию дня недели")
Exit Function
End If
ColDays = NumNed * 7 + chDn ' Вычисление количества дней начиная
PolData = BeginData + ColDays ' от понедельника нулевой недели
End Function
Приложение 8
Процедуры листа Нагрузка
В листинге П8.1 приведена процедура, выполняемая по щелчку на кнопке Заполнить расписание. Перед этим требуется указать фамилию преподавателя в списке, расположенном слева от кнопки.
р^С7инг П8.1п"Г:<цедура
Private Sub Соп\_1_С11ск ()
Rows("7:1000").Select ' Очистка информационной области на листе
Selection.ClearContents
Cells(5, 1).Select
' Если не выбран преподаватель, то выводится предупреждение
If Prepod.Listlndex = -1 Then
MsgBox (" He указан преподаватель ")
Exit Sub
End If
' Подсчет числа заявок на первом листе
N = 0
While Worksheets(1).Cells (N + 4, 1).Value о ""
N = N + 1
Wend
' Подсчет числа преподавателей
Prep = 0
While Worksheets(2).Cells(Prep + 2, 7).Value <> ""
Prep = Prep + 1
Wend
str_num = 7 ' Вывод на лист информации начинается с седьмой строки
For i = 4 То N + 3 'Цикл по заявкам
Приложение В. Процедуры листа Нагрузка
281
If CStr(Worksheets(1).Cells(i, 3).Value) = Prepod.Text Then
' Если в списке заявок найдена фамилия преподавателя
Cells (str_jnum, 2)	= Worksheets(1).Cells(i,	3).Value	
Преподаватель			
Cells(str_num, 3)	= Worksheets(1).Cells(i,	10).Value	
Предмет			
Cells(str_num, 4)	= Worksheets(1).Cells(i,	9).Value	'‘Группа
Cells (str_jium, 5)	« Worksheets(1).Cells(i,	4).Value	' День
Cells(strjnum, 6)	- worksheets(1).Cells(1,	5).Value	' Время
Cells (str_jnum, 7)	»= Worksheets (1). Cells (i,	8).Value	' Аудитория
Eor j » 0 To 17	* Цикл по учебным неделям		
ask »= CStr(Worksheets(1) .Celled, j + 11) .value)
If ask » й*и Then
If Calls (str_jiwn, 8).Value <> on Then
Cells(strjnum, 8).Value = CStr(Cells(str_num, 8).Value) +	_
* Chr(lO)
V ; -ЛМ 2t 1 В восьмом столбце указываются номера недель занятий
Cells(Str□num, 8).Value = Cells(str_num, 8).Value + Str(j) If Cells(str_num, 12).Value = "" Then ' В 12 столбце отмечается начальная неделя - для сортировки, ' выполняемой по нажатию кнопки "Компоновка" Cells(str_num, 12).Value = j End If Da_y = CStr(Worksheets(1).Cells(i, 4).Value) Da_Ta = PolData(CInt(j), Da_y) If Cells(str_num, 9).Value <> "" Then
Cells(str_num, 9).Value = CStr(Cells(str_num, 9).Value) +	_
+ Chr(10) End If ' Указываем конкретные дни занятий Cells(str_num, 9).Value = _
Cells(str_num, 9).Value + Str(Da_Ta) End If Next str_jium = str_num + 1 1 Переход к следующей строке отчета End If Next End Sub
Приложения
282
В листинге П8.2 приведена процедура обработки щелчка на кнопке Компо-
новка.
|Л.- ir П8 2. Процедура обработки щелчка на кнопке Компоновка
Private Sub Can\_2_Click()
' Подсчет заполненных строк на этом листе Nom - О While Cells(Nom + 7, 2).Value о «* Nom « Nom + 1
Wend
N-Tinves = 0 ' Подсчет числа занятий
While Worksheets (2) .Cells (N_Times + 2, 5).Value <> "" NJPimes ~ N_Times + 1
Wend
For i « 1 To Nom ' Цикл по строкам этого листа PoiskTime = 0	' Проверка соответствия времени, указанного, в заявке
' времени начала занятия на втором листе
For j = 1 То N_Times
If Worksheets(2).Cells(j + 1, 5).Value = _ CStr(Cells(i + 6, 6).Value) Then PoiskTime = j + 1 Exit For End If
Next
If PoiskTime > 0 Then ' Если указанное в заявке время соответствует ' времени начала занятия на втором листе
Cells(i + б, б) = Cells(i + б, 6) +	_
Worksheets(2).Cells(PoiskTime + 19, 5).Value ' Добавляем время ' завершения занятия End If
Next * Завершение цикла по строкам этого листа
For i = Nom То 2 Step -1 ’ Цикл компоновки одного занятия у разных групп For j = i - 1 То 1 Step -1 ' Сравнение текущей заявки с предыдущими
indicator = 0 ' Индикатор нахождения групповой заявки If Cells(i + б, 2).Value = Cells(j + б, 2).Value And _
Cells(i	+	6,	3).Value	=	Cells(j	+	6,	3).Value And	_	t
Cells(i	+	6,	5).Value	=	Cells(j	+	6,	5).Value And	_
Cells(i	+	6,	7).Value	=	Cells(j	+	6,	7).Value And
Приложение 8. Процедуры листа Нагрузка 283
Cellsd + б, 6) .Value = Cells(j + 6, 6) .Value And Cellsd + 6, 8) .Value = Cells(j + 6, 8) .Value Then indicator = 1 Exit For End If Next If indicator = 1 Then ' Добавляем новую группу к имеющимся
Cells(j + 6, 4).Value = Cells(j + 6, 4).Value +	+ Chr(10) + _
Cellsd + 6, 4) .Value Rows(i + 6).Delete End If Next Nom = 0 ' Подсчет заполненных строк на этом листе While Cells(Ncm + 7, 2).Value <> "" Nom = Nom + 1 Wend For i = Nom To 2 Step -1 ' Цикл компоновки нескольких занятий групп For j = i - 1 То 1 Step -1 ' Сравнение текущей заявки с предыдущими indicator = О If Cellsd + 6, 2) .Value = Cells(j + 6, 2) .Value And _ Cellsd +	6,	3) .Value	=	Cells (j	+	6,	3) .Value	And	_
Cellsd +	6,	5) .Value	=	Cells(j	+	6,	5) .Value	And	_
Cells(i + 6, 7).Value - Cells(j + 6, 7).Value And _ Cellsd +	6,	8) .Value	=	Cells(j	+	6,	8) .Value	And	_
Cellsd +	6,	4) .Value	=	Cells (j	+	6,	4) .Value	Then
indicator = 1 Exit For End If Next If indicator = 1 Then ' Добавляем новое занятие к имеющимся
Cellsfj + 6, 6).Value = Cells(j + б, 6).Value +	+ Chr(10) + _
Cellsd + 6, 6) .Value Rowsd + 6) .Delete End If
End Sub
284 Приложения
В листинге П8.3 приведена процедура обработки щелчка на кнопке Печать.
Листинг П8.3. Обработка щелчка на кнопке Печать
Private Sub Соп\_3—Click ()
Worksheets(13).Range("Al:1100").Value = ""
Worksheets(13).Range("Al:1100”).Value = Range("A6:1106").Value
Worksheets(13).Activate
End Sub
Приложение 9
Процедура, связанная с открытием книги
На рабочих листах расположено много списков, которые должны быть заполнены начальной информацией со второго листа книги. В листинге П9.1 приведена процедура workbook_0pen, автоматически выполняемая при открытии книги. В ней и выполняется необходимая инициализация списков.
j Листинг Л 9.1 Процедура workbook j3pen
Private Sub Workbook_Open()
' Подсчет дней на втором листе
N_pays = О
While Worksheets(2).Cells(N_Pays + 2, 4).Value <> ""
N_JDays = HJDays + 1
Wend
' Заполнение списка LI на третьем листе
Worksheets(3).LI.Clear
For i = 1 To M_Pays
Worksheets(3) .LI.AddItem Worksheets(2) .Cells(i + 1, 4) .Value
Next
' Подсчет занятий в течение дня
N_Timee а о
While Worksheets(2).Cells(N_Times + 2, 5).Value <> ""
NJTimes * W_Times + 1
Wend
' Заполнение списка L2 на третьем листе
Worksheets(3).L2.Clear
For i a 1 To N_Times
Worksheets(3).L2.AddItem CStr(Worksheets(2).Cells(i + 1, 5).Value)
286
Приложения
Next
’ Подсчет числа недель на втором листе
N_Ned = О
While Worksheets(2).Cells(N_Ned + 2, 3).Value <> ""
NJNed = N_Ned + 1
Wend
' Заполнение третьего списка L3 на третьем листе
Worksheets(3).L3.Clear
For i = 1 То N_Ned
Worksheets(3) .L3 .Addltem Worksheets(2) .Cellsd + 1, 3).Value Next ' Заполнение списков недель на четвертом листе Worksheets(4).Cl.Clear Worksheets(4).C2.Clear For i = 1 To N_Ned
Worksheets(4) .Cl.Addltem Worksheets(2) .Cellsd + 1, 3) .Value
Worksheets(4) .C2.Addltem Worksheets(2) .Cellsd + 1, 3).Value Next ' Заполнение списка недель на восьмом листе Worksheets(8).Ll.Clear For i = 1 To N_Ned
Worksheets(8).Ll.Addltem Worksheets(2).Cells(i + 1, 3).Value Next ' Заполнение списка недель на девятом листе Worksheets(9).Ll.Clear Worksheets(9).L2.Clear For i = 1 To NJNed
Worksheets(9) .Ll.Addltem Worksheets(2) .Cellsd + 1, 3) .Value
Worksheets(9).L2.Addltem Worksheets(2).Cells(i + 1, 3).Value Next 'Заполнение списка недель на десятом листе Worksheets(10).Ll.Clear Worksheets(10).L2.Clear For i = 1 To NJNed
Worksheets(10) .Ll.Addltem Worksheets(2) .Cellsd + 1, 3) .Value
Worksheets(10).L2.Addltem Worksheets(2).Cells(i + 1, 3).Value Next ' Подсчет числа преподавателей N_Prepod = 0
Приложение 9. Процедура, связанная с открытием книги 287
While Worksheets(2).Cells(N_Prepod + 2, 7).Value <> ""
N_Prepod = N_Prepod + 1
Wend
1 Заполнение списка преподавателей на листе "Нагрузка"
Worksheets(12).Prepod.Clear
For i = 1 To N_Prepod
Worksheets(12).Prepod.Additem Worksheets(2).Cells(i + 1, 7).Value Next ' Установка защиты на первый и второй листы
Worksheets(1).Protect DrawingObjects:=True, Contents:=True, _ Scenarios:=True
Worksheets(2).Protect Drawingobjects:=True, Contents:=True, _ Scenarios:=True End Sub
Приложение 10
Тесты по VBA
В этом приложении приведены тестовые вопросы по программированию в Microsoft Excel с использованием VBA. Читателю предлагается самостоятельно выбрать один из предлагаемых вариантов ответа. Правильные ответы приведены в приложении 11.
1. На рабочем листе Microsoft Excel расположен элемент управления "текстовое окно". Требуется обеспечить вывод большого объема информации в этом окне с переносом текста на следующие строки. Какое свойство следует для этого использовать?
А	Text
Б	MultiLine
В	TextAlign
Г	SpecialEffeet
2. Что означает Additem в языке программирования VBA?
A	Это метод для работы с командными кнопками.
Б	Это свойство элемента управления "текстовое окно".
В	Это метод работы с объектом workbook.
Г	Это метод для добавления строки в такие элементы управления, как "поле со списком" и "список".
3. В каком из вариантов имя переменной языка программирования VBA указано правильно?
А	Times_Now
Б	Times.1
В	Times 1
Г	Times Now
Приложение 10. Тесты по VBA
289
4.	Для чего предназначен тип данных Boolean в языке программирования VBA?
А	Этот тип данных позволяет хранить только одно из двух значений: 1 или 2.
Б	Этот тип данных позволяет хранить любой набор данных.
В	Такого типа данных не существует.
Г	Этот тип данных позволяет только одно из двух значений: True или False.
5.	Что означает оператор Option Explicit в языке программирования VBA?
А	Требует обязательного объявления всех переменных в программе.
Б	Позволяет задать двойную точность для вычислений.
В	Не требует обязательного объявления переменных в программе.
Г	Назначает режим отладки программы.
6.	Какие действия выполняет процедура DoEvents?
А	Это оператор цикла.
Б	Передает управление операционной системе для обработки всех событий.
В	Информирует Visual Basic о том, что управление передано другому приложению.
Г	Назначает режим отладки программы.
7.	С помощью какого свойства можно вставить на командную кнопку графическое изображение?
А	Caption
Б	Image
В	Picrure
Г	Graphic
8.	К какой категории относится термин ForeColor?
A	События
Б	Методы
В	Свойства
Г	Функции
290
Приложения
9.	Какой из вариантов процедуры является правильным с точки зрения синтаксиса?
А	Sub HelloOutO А = b + с End
Б	Sub HelloOut A = b + с; End Sub
В	Sub HelloOutO A = b + c End Sub
Г	Sub Hello Out() A = b + c End Sub
10.	Выберите правильный вариант процедуры подсчета количества заполненных ячеек в первом столбце (начиная с ячейки А1) второго листа книги Microsoft Excel, выполняемой по щелчку на кнопке.
A	Private Sub CommandButton2_ClickO N = 0 While Worksheets(2).Cells(N + 2, 1).Value <> •• N = N + 1 Wend End Sub
Б	Private Sub CammandButton2_Click() N = 0' While Worksheets(2).Cells(N + 1, 1).Value <> HH N = N + 1 Wend End Sub
В	Private Sub CommandButton2_Click() N = 0 While Worksheets(2).Cells(N + 1, 2).Value <> "" N = N + 1 Wend End Sub
Г	Private Sub CommandButton2_Click() N = 0 While Worksheets(2).Cells(N + 1, 2).Value != "" N = N + 1	f Wend End Sub
Приложение 10. Тесты по VBA
291
11.	В каком из вариантов правильно оформлена запись значения из элемента управления типа "текстовое окно" в ячейку СЗ второго листа книги?
А	Worksheets(2).Cells(3, 3) = TextBoxl.Text
Б	Worksheets(2).Cells(С, 3) = TextBoxl.Text
В	Worksheets(2).Cells<C3) = TextBoxl.Text
Г	Worksheets(2).Cells(3, 3) TextBoxl.Text
12.	В каком из вариантов приведена правильная команда записи значения из ячейки А1 первого рабочего листа в ячейку АЗ второго листа книги?
A	Worksheets(2).Cells(1, 3) = Worksheets(1).Cells(1, 3)
Б	Worksheets(2).Cells(3, 3) = Worksheets(1).Cells(1, 1)
В	Worksheets(2).Cells(3, 1) = Worksheets(1).Cells(1, 1)
Г	Worksheets(2).Cells(3, 3) Worksheets(1).Cells(1, 1)
13.	В каком из вариантов приведена процедура, которая по щелчку на первой кнопке (Name = Кнопка 1) запрещает доступ ко второй кнопке (Name = Кнопка2) и разрешает доступ к третьей кнопке (Name = КнопкаЗ)?
A	Private Sub Кнопка1_СИск() Кнопка2.Visible = False КнопкаЗ.Visible = True End
Б	Private Sub Кнопка1_СИск() Кнопка2.Enabled.False КнопкаЗ.Enabled.True End Sub
В	Private Sub Кнопка1_СИск() Кнопка2.Enabled = False КнопкаЗ.Enabled = True End Sub
Г	Private Sub Кнопка1_СИск() Кнопка2.NoEnabled КнопкаЗ.Enabled End Sub
292
Приложения
14. На листе книги расположен элемент управления типа "рисунок" (Name = image2). Какой из вариантов позволяет указать для этого элемента управления графический файл?
А	Image2.Picture = LoadPicture(с:\foto\Twrp.jpg)
Б	Image2.Picture	LoadPicture("c:\foto\TMrp.jpg")
В	Image2.Picture = LoadPicture("c:\foto\Twrp.jpg")
Г	Image2.Picture = LoadPicture(c:\foto\TMrp.jpg)
Приложение 11
Ответы на тесты по VBA (приложения 10)
Номер вопроса	Вариант правильного ответа
1	Б
2	Г
3	А
4	Г
5	А
6	Б
7	В
8	В
9	В
10	Б
11	А
12	В
13	В
14	В
Приложение 12
Описание компакт-диска
На сопроводительном компакт-диске книги вы найдете примеры, которые рассматриваются во всех шести главах, и видеокурс, иллюстрирующий разработку примеров, изложенных в главах 7 и 2. Для начинающих пользователей программного продукта Excel видеокурс содержит общие сведения о приемах работы в этом приложении.
Файлы сгруппированы в папки, имена которых соответствуют главам книги. Файлы описаны в табл. П12.1.
Таблица П12.1. Файлы сопроводительного компакт-диска
Файл	Глава	Описание
Glava1\ris1_4.xls	1	Иллюстрирует присвоение значений свойствам объектов (см. рис. 1.4)
Glava1\rls1_5.xls	1	Обработка щелчка на кнопке с выводом информации в текстовое окно (см. рис. 1.5)
Glava1\ris1_10.xls	1	Работа с элементом управления "поле со списком" (см. рис. 1.10)
Glava1\ris1_11.xls		Работа с элементом управления "список" (см. рис. 1.11)
Glava1\ris1_13.xls	1	Смена изображения в элементе управления "рисунок" при перемещении мыши (см. рис. 1.13). Вариант программы, соответствующий главе 1, приведен на втором листе данной книги Excel. Для работы программы требуется размещение графические файлов в определенной папке (об этом сказано в главе 1). На первом листе предложен аариант смены изображения в элементе “рисунок" без дополнительного размещения файлов
Glava1\ris1_15.xls	1	Программа вывода времени на рабочий лист Microsoft Excel (см. рис. 1.15)
Приложение 12. Описание компакт-диска
295
Таблица П12.1 (продолжение)
Файл	Глава	Описание
Glava1\ris1_18.xls	1	Перемещение текстового окна в соответствии с положением движка на полосе прокрутки (см. рис. 1.18)
Glava1\ris1_19.xls	1	Перемещение мыши при наведении курсора мыши (см. рис. 1.19)
Glava1\ris1_20.xls	1	Игра со случайным выбором картинок для элементов "рисунок" (см. рис. 1.20)
Glava1\ Listing1_14.xls	1	Изменение цвета кнопки при перемещении мыши (см. листинг 1.14)
Glava2\ris2_1 .xls	2	Электронный бланк заказа (см. рис. 2.1)
Glava2\ris2_7.xls	2	Книга для составления заказа на канцтовары (см. рис. 2.7)
Glava1\ris2_12.xls	2	Электронная анкета (см. рис. 2.12)
Glava3\ris3_3.xls	3	Передвижение коня по шахматной доске (см. рис. 3.3)
Glava3\ris3_5.xls	3	Пошаговое передвижение коня по шахматной доске (см. рис. 3.5)
Glava3\ris3_6.xls	3	Игра "Нимбы" на листе Microsoft Excel (см. рис. 3.6)
Glava3\ris3_8.xls	3	Игра на матрице (см. рис. 3.8)
Glava4\ris4_6.xls	4	Обработка отчета, созданного в программе 1С:Предприятие
Glava5\ primer_2pers.xls	5	Книга с примером для электронного документооборота с двумя полями для электронной подписи
Glava5\ clear_2pers.xls	5	Книга для электронного документооборота с двумя полями для электронной подписи
Glava5\ primer_4pers.xls	5	Книга с примером для электронного документооборота с четырьмя полями для электронной подписи
Glava5\ clear_4pers.xls	5	Книга для электронного документооборота с четырьмя полями для электронной подписи
Glava6\ raspisanie.xls	6	Управление фондом аудиторий учебного заведения
set		Папка, содержащая папки и файлы видеокурса
readme.doc		Файл с описанием компакт-диска
SAFIashPlayer.exe		Проигрыватель флэш-файлов
296	 Приложения
Таблица П12.1 (окончание)
Файл	Глава	Описание
start.exe		Исполняемый файл, запускающий видеокурс
start.ico		Служебный файл
AUTORUN.INF		Служебный файл
shell.swf		Файл — оболочка видеокурса
В рабочих книгах Microsoft Excel, связанных с документооборотом (папка Glava5), используется защита. Так, для первых двух листов книг и для входа в конструктор установлена защита с паролем "23". В качестве электронных подписей сотрудников выбраны значения, указанные в табл. П12.2.
Таблица П12.2. Электронные подписи
Фамилия	Подпись
Петров ГП	123456789
Иванов АН	234567891
Сидоров АА	345678912
Афанасьев ЛА	456789123
Логинов ЮВ	567891234
Литература
1.	Гарнаев А. Ю. Самоучитель VBA. — СПб.: БХВ-Петербург, 2001. — 512 с.
2.	Гарнаев А. Ю. Microsoft Excel 2002: разработка приложений. — СПб.: БХВ-Петербург, 2003. — 768 с.
3.	Гарнаев А. Ю. Самоучитель VBA, 2-е издание.— СПб.: БХВ-Петербург, 2003. — 560 с.
4.	Гарнаев А. Ю. VBA. Наиболее полное руководство. — СПб.: БХВ-Петербург, 2005. — 848 с.
5.	Кузьменко В. Г. Программирование на VBA 2003. — М.: Бином-Пресс, 2004. — 880 с.
Предметный указатель
1	E
1С:Предприятие 91	Enabled 11
А	F
Activate 46 ActiveDocument 140 ActiveX 139 Add 141 Addltem 18 Array 75 Automation 139, 140 AutoSize 11	Font 11 Format 31 G General 37 GroupName 65 H
C	Height 9
Caption 11 Cells 46 CInt 38,43 Clear 18 Click 15 Count 141 CreateObject 140	Hide 156 1 If 23 InputBox 42 InsertAfter 141 InsertBefore 141 Integer 30
D	IsNumeric 104
Date 40 DateDiff 113 DbIClick 22 Dim 29 Documents 140 DoEvents 31	L LargeChange 34 Len 104 List 18 ListCount 18
300
Предметный указатель
Listindex 18 LoadPicture 26 Loop 75	S Select 82 Selection 82
M	Show 152 SmallChange 34
Max 34 Mid 104 Min 34 Module 131 MouseMove 25 MsgBox 41	Str 35 Style 141 T Top 34
N	U
Name 10 Now 31	Unprotect 46 UserForm 152
0	V
Object 39	Vai 43 Value 34
P	Variant 40 Visible 9
Paragraphs 141 Password 46 Paste 138 Picture 11	W Wend 31 While 31
R	Width 9 Workbook 45
Randomize 39 Range 46, 141 Removeitem 18 RGB 28 Rnd 36	Workbook_Open 46 Worksheet-Activate 62 Worksheet- BeforeDoubleClick 86 Worksheets 45
A	В
Автоматизированная книга 147 Активизация формы 156	Вид субконто 94 Выделение 82 д
Б	Дебет 93	#
Бухгалтерский учет 91	Диапазон 46, 141 Документы 92
Предметный указатель
301
Ж
Журнал операций 96
3
Защита 121
с паролем 46
снятие 46
И
Индекс 74
Интенсивность цвета 28
К
Карточка счета 92
Клиенты 139
Коллекция объектов 45
Константы 92
Конфигурирование 91
Кредит 93
М
Массив 40
Н
Надпись 13
"Нимбы"79
Нулевая неделя 151
О
Общая область 29
Оператор условия 23
Оптимизация 147
Отчеты 92
П
Пары 149
Переключатель 64
Переменная 39
Перечисления 92
Поле со списком 17
Полоса прокрутки 33
Р
Рабочая книга 45
Рабочие листы 45
Режим:
выполнения 8
конструктора 7 работы 8
Рисунок 24
С
Свойства элементов 9
Серверы 139
Снятие защиты 46
Список 20
Справочники 92
Субконто 94
Счет 92
Т
Текстовое окно 12
Типы данных 39
Ф
Флаг 104
Форма, создание 152
Ш
Шаблон 146
Э
Элементы управления 7
Я
Ячейки 46
Microsoft-
GOLD CERTIFIED
Partner
sdftline
Лицензирование
Softlin* работает иа рынка программного обеспеченна с 1993 года а обдадаат векшами етатусама паргнерства таках компаний, как Microsoft, Oracle, SAP, Symantec, Citrix, Adobe и многих других.
Обучение
Учебный центр 8oftline, лидируюций иа рынка 1Т-образова-нна, предоставляет профессиональные услуги по обучению, тестированию и сертификации ГГ-с пе цикл истов.
SMUirttf | ownwKine ae<vic«a «tfWne'j adwato» Stfftiine I и 9«л«<»м
gittftline j acaOams;
4$ allsoft.ru
A^OFT
Консалтинг
Консалтинговое подразделение Softiine Solution» обладает уникальным опытом по внедрению и развертыванию инфраструктурных решений и систем управления бизнесом для компаний любого масштаба.
Компани* SofUlna
1НИ<Мескеа,у*.Гу««ицлЛ
Тм./*алс +7 (ОМ) 31700-13 Ы«е»оП№мл
Книги издательства "БХВ-Петербург' в продаже:
www.bhv.ru
Магазин "Новая техническая книга": СПб., Измайловский пр., д. 29, тел.: (812) 251-41-10 Отдел оптовых поставок: e-mail: opt@bhv.spb.su
Серия «Мастер»
Microsoft. Visual Basic 6.0	992 с.
Microsoft. Ресурсы Microsoft Windows NT Server 4.0. Книга 1 (+CD-ROM)	752 c.
Microsoft. Создание intranet. Официальное руководство Microsoft	672 c.
Microsoft. Электронная коммерция. В2В-программирование (+CD-R0M)	368 с.
Айзекс С. Dynamic HTML (+CD-ROM)	496 с.
Алямовский А., Собачкин А„ Одинцов Е., Пономарев Н., Харитонович А. 800 с. SolidWorks. Компьютерное моделирование в инженерной практике
Андерсен В., Нортон П. Разработка приложений в Access 97 (+CD-ROM) 656 с.
Анин Б. Защита компьютерной информации	384 с.
Асбари С. Корпоративные решения на базе Linux (+CD-ROM)	496 с.
Березин С. Факсимильная связь в Windows	304 с.
Березин С. Факс-модемы: выбор, подключение, выход в Интернет	256 с.
Борн Г. Реестр Windows 98 (+дискета)	496 с.
Бухвалов А., Бухвалова В., Идельсон А. Финансовые вычисления для	320 с.
профессионалов (+CD-ROM)
Валиков А. Технология XSLT	544 с.
Габбасов Ю. Internet 2000	448 с.
Гарбар П. Novell GroupWise 5.5: система электронной почты	480 с.
и коллективной работы
Гарнаев A. Excel, VBA, Internet в экономике и финансах	816 с.
Гарнаев А., Гарнаев С. Web-программирование на Java и JavaScript	1040 с.
Гарнаев A. Visual Basic .NET: разработка приложений	624 с.
Гарригус С. Sound Forge. Музыкальные композиции и эффекты	384 с.
Гевенян В. Adobe Photoshop CS: волшебные фильтры и спецэффекты	544 с.
Гордеев О. Программирование звука в Windows (^дискета)	384 с.
Гофман В., Хомоненко А. Работа с базами данных в Delphi, 2-е изд.	624 с.
Делла-Росса Р. Adobe Photoshop CS2 для художников	608 с.
Дронов В. Macromedia Dreamweaver 4: разработка Web-сайтов	608 с.
Дронов В. JavaScript в Web-дизайне	880 с.
Дубаков М. Веб-мастеринг средствами CSS	544 с.
Дубина А. и др. MS Excel в электротехнике и электронике (+дискета)	304 с.
Дунаев С. Технологии интернет-программирования	480 с.
Елманова Н., Федоров A. ADO в Delphi (+CD-ROM)	816 с.
Жарков С. Shareware: профессиональная разработка и продвижение	320 с.
программ
Зуев С. САПР на базе AutoCAD - как это делается (+CD-ROM)	1168 с.
Зима В. и др. Безопасность глобальных сетевых технологий	320 с.
Катков А., Кетков Ю., Шульц М. MATLAB 7. Программирование, численные 752 с. методы
Кожедуб О. и др. Разработка интернет-приложений в Delphi (+дискета)	432 с.
Кокорева О. Реестр Windows 2000	640 с.
Кокорева О. Реестр Windows ХР	560 с.
Костельцев A. GTK+. Разработка переносимых графических интерфейсов 368 с. (+CD-ROM)
Краснов М. DirectX. Графика в проектах Delphi (+CD-ROM)	416 с.
Краснов М. OpenGL. Г рафика в проектах Delphi (^дискета)	352 с.
Кубанский А. Создание и обработка структур данных в примерах на Java 336 с. Кулагин Б. Актуальное моделирование, визуализация	496 с.
и анимация в 3ds Мах 7.5
Кулагин Б. 3ds Мах 8: от моделирования до анимации	432 с.
Куприянов М. И. др. Коммуникационные контроллеры фирмы Motorola	560 с.
Куриленко И. Видео "по-домашнему". Это просто	352 с.
Лавров С. Программирование. Математические основы, средства, теория 320 с. Леоненков А. Решение задач оптимизации в среде MS Excel	704 с.
Матросов A. Maple 6. Решение задач высшей математики и механики	528 с.
Мешков А., Тихомиров Ю. Visual C++ и MFC, 2-е изд. (+дискета)	1040 с.
Мещеряков М., Хомоненко А. Публикация баз данных в Интернете	560 с.
Миловская О. Дизайн архитектуры и интерьеров в 3ds Мах 8	320 с.
Миронов Д. Создание Web-страниц в Microsoft Office 2000	320 с.
Михеева В., Харитонова И. Microsoft Access 2000: разработка приложений	832 с.
Новиков Ф. Microsoft Office 2000: разработка приложений	680 с.
Одинцов И. Профессиональное программирование. Системный подход, 624 с. 2-е изд.
Одинцов И. Профессиональное программирование. Системный подход 512*с. Олифер В., Олифер Н. Новые технологии и оборудование IP-сетей	512 с.
Петелин Р., Петелин Ю. Fruity Loops Studio: музыкальная фабрика на PC	3fe8 с.
(+CD-ROM)
Петелин Р., Петелин Ю. Музыкальный компьютер для гитариста	496 с.
Петелин Р. Ю., Петелин IQ. В. Cakewalk Sonar 4 Producer Edition. Секреты 600 с. мастерства
Петелин Р. Ю., Петелин Ю. В. Cubase SX 3: запись и редактирование музыки 752 с. (+CD-ROM)
Петелин Р. Ю., Петелин Ю. В. Propellerhead Reason - музыкальная студия 224 с.
Погорелов В. AutoCAD 2006. Моделирование в пространстве для инженеров 368 с. и дизайнеров
Полещук Н. Visual LISP и секреты адаптации AutoCAD	576 с.
Поляков А. Методы и алгоритмы компьютерной графики в примерах	416 с.
на Visual C++ (+CD-ROM)
Понамарев В. А. СОМ и ActiveX в Delphi	320	с.
Пономаренко С. Adobe InDesign: дизайн и верстка	544	с.
Попов А Командные файлы и сценарии в Windows Script Host ’	320	с.
Приписное Д. Моделирование в 3D Studio МАХ 3.0 (+CD-ROM)	352	с.
Раскин Д. Microsoft Office 2000: разработка приложений. Компакт-диб^у.. -с примерами
Роббинс Д. Отладка приложений (+CD-ROM)	512 с.
Романычева Э., Яцюк О. Компьютерные технологии в дизайне. Эффективная 432 с. реклама (+CD-ROM)
Русеев Д. Технологии беспроводного доступа. Справочник	352 с.
Рязанцева Н., Рязанцев Д. 1 С:Предприятие. Комплексная конфигурация.	524 с.
Секреты работы
Рязанцева Н., Рязанцев Д. 1С:Предприятие. Бухгалтерский учет.	320 с.
Секреты работы
Рязанцева Н., Рязанцев Д. 1С:Предприятие. Зарплата и кадры.	304 с.
Секреты работы
Рманцева Н., Рязанцев Д. 1 С:Предприятие. Торговля и склад.	368 с.
Секреты работы
Рязанцева Н., Рязанцев Д. 1С:Предприятие. Секреты программирования 352 с.
Рязанцев Д., Рязанцева Н. 1 С: Предприятие. Секреты конструирования	368 с.
Рязанцев Д., Рязанцева Н. 1С: Бухгалтерия 8.0. Секреты работы	528 с.
Смит К. Photoshop для цифровой фотографии. Полноцветное издание	370 с.
Соколенко П. Программирование SVGA-графики для IBM PC	432 с.
Сысойкина М. Borland Kyllx: разработка приложений (+CD-ROM)	544 с.
Тихомиров Ю. Open GL. Программирование трехмерной графики, 2-е изд. 304 с. (+дискета)
Тихомиров Ю. SQL Server 7.0: разработка приложений	370 с.
Трасковский А. Секреты BIOS	400 с
Трельсен Э. Модель СОМ и библиотека ATL 3.0 (+дискета)	928 с
Тяпичев Г. Компьютер на любительской радиостанции (-^дискета)	448 с.
Хабибуллин И. Создание распределенных приложений на Java 2	704 с.
Чебыкин Р. Разработка и оформление текстового содержания сайтов	528 с.
Чекмарев A. Windows 2000 Active Directory	400 с.
Чекмарев А. Средства визуального проектирования на Java (+CD-ROM) 400 с. Шапошников И. Web-сайт своими руками 5	224 с.
Шапошников И. Web-сервисы Microsoft .NET	336 с.
Шапошников И. Интернет-программирование, 2-е изд.	224 с.
Шапошников 14. Справочник Web-мастера. XML	304 с.
Шилдт Г. Теория и практика C++	416 с.
Шинкарев О. SOFTIMAGEIXSI: от моделирования до анимации (+CD-ROM) 432 с. Яцюк О. Компьютерные технологии в дизайне. Логотипы, упакрвка, буклеты 464 с. (+CD-ROM)
Серия «Мастер Медиа»
Бурлаков М. В. Macromedia Flash MX 2004: сборка видеоклипов	720 с.
Делла-Росса Р., Делла-Росса A. Adobe Photoshop для художников	592 с.
Кулагин Б. 3ds Мах 5: от фантазии к реальности	480 с.
Медведев Е., Трусова В. Cubase SX для музыкантов (+CD-ROM)	640 с.
Медведев Е., Трусова В. Steinberg Nuendo 2. Секреты виртуального звука 432 с. (+CD-ROM)
Медведев Е., Трусова В. Реальность виртуального звука (+CD-ROM)	496 с.
Петелин Р., Петелин Ю. Adobe Audition. Обработка звука для цифрового 400 с. видео (+CD-ROM)
Петелин Р., Петелин Ю. Cubase SX 2. Секреты мастерства (+CD-ROM)	656	с.
Петелин Р., Петелин Ю. Cubase SX. Секреты мастерства (+CD-ROM)	640	с.
Петелин Р., Петелин Ю. Профессиональные плагины для Cubase и Sonar	592 с.
(+CD-ROM)
Погорелов В. AutoCAD: трехмерное моделирование и дизайн	288 с.
Пономаренко С. Пиксел и вектор. Принципы цифровой графики	496 с.
Цоллер С. Создание музыки на ПК: от простого к сложному	320 с.
Серия «Мастер программ»
Агуров П. Последовательные интерфейсы ПК. Практика программирования 496 с. (+CD-ROM)
Боровский А. C++ и Pascal в Kylix 3. Разработка интернет-приложений	544,с.
и СУБД
Будилов В. Интернет-программирование на Java	7JD4 с.
Вершинин М., Иванова Е. Java 2, Enterprise Edition. Технологии	1038 с.
проектирования и разработки
Веселов Е., Голованов М. Создание компонентов в среде Delphi. Руководство 320 с. разработчика (+CD-ROM)
Гарнаев A. Microsoft Excel 2002: разработка приложений	768	с.
Дарахвелидзе П., Марков Е. Программирование в Delphi 7 (+дискета)	784	с.
Дарахвелидзе П., Марков Е. Разработка Web-служб средствами Delphi	672	с.
(+дискета)
Касперски К. Техника защиты компакт-дисков от копирования (+CD-RQM)	464 с.
Касперски К. Техника оптимизации программ. Эффективное использование	464 с.
памяти
Магда Ю. Ассемблер. Разработка и оптимизация Windows-приложений	544 с.
(+CD-ROM)
Матросов А. и др. MS Office ХР: разработка приложений	944 с.
Мэлхотра С. и др. Microsoft ADO.NET: разработка профессиональных	768 с.
проектов
Немнюгин С., Стесик О. Параллельное программирование для	400 с.
многопроцессорных вычислительных систем
Несвижский В. Программирование устройств SCSI и IDE	592 с.
Пирогов В. Ассемблер для Windows, 2-е изд.	656 с.
Пирогов В. Программирование на Visual C++ .NET	800 с.
Поляков А., Брусенцев В. Методы и алгоритмы компьютерной графики	560 с.
в примерах на Visual C++, 2-е изд. (+CD-ROM)
Понамарев В. Программирование на C++/C# в Visual Studio .NET 2003	352 с.
Постолит A. Visual Studio. NET: разработка приложений баз данных	544 с.
Рафалович В., Карнаухов С. Программирование для карманных компьютеров 352 с. Palm и Pocket PC
Секунов Н. Программирование на C++ в Linux	368 с.
Старыгин A. XML: разработка Web-приложений (+CD-ROM)	592 с.
Тихомиров Ю. Open GL. Программирование трехмерной графики, 2-е изд. 304 с. (+дискета)
Хабибуллин И. Разработка Web-служб средствами Java	400 с.
Чакраборти А. и др. Microsoft .NET Framework: разработка профессиональных 896 с. проектов
Чекалов А. Базы данных: от проектирования до разработки приложений 384 с. (+дискета)
Шорт С. Разработка XML Web-сервисов средствами Microsoft .NET	480 с.
(+CD-ROM)
Серия «Мастер решений»
Агапонов С. и др. Средства дистанционного обучения. Методика, технология, 336 с. инструментарий (+CD-ROM)
Гайдышев И. Решение научных и инженерных задач средствами Excel, VBA 512 с. и C++ (+CD-ROM)
Елисеев Д. Аппаратно-программные средства карманных компьютеров	368 с.
(+CD-ROM)
Касперски К. ПК: решение проблем	560 с.
Кетков Ю. Matlab 6.x: программирование численных методов	672 с.
Куперштейн В. Microsoft Project в делопроизводстве и управлении	480 с.
Леоненков А. Нечеткое моделирование в среде MATLAB и fuzzyTECH	736 с.
Маклаков С., Матвеев Д. Анализ данных. Генератор отчетов Crystal Reports	496 с.
Масленников М. Практическая криптография (+CD-ROM)	464 с.
Потемкин А. Твердотельное моделирование в системе КОМПАС-SD	512 с.
(+CD-ROM)
Рудометов В., Рудометов Е. PC: настройка, оптимизация и разгон, 3-е изд.	496 с.
Рудометов В., Рудометов Е. Форсирование аппаратных средств PC	542 с.
Салманов О. Математическая экономика с применением Mathcad и Excel 464 с. Свет В. AutoCAD: кнопки и язык макрокоманд	320 с.
Серия «Мастер систем»
Галичский К. Компьютерные системы в телефонии	400 с.
Гаскин Дж. Администрирование Novell Netware 6/6.5 (+CD-ROM)	1056 с.
Зима В. и др. Безопасность глобальных сетевых технологий, 2-е изд.	368 с.
Кокорева О. Реестр Microsoft Windows Server 2003	640 с.
Конеев И., Беляев А. Информационная безопасность предприятия	752 с.
Лукацкий А. Обнаружение атак, 2-е изд.	608 с.
Попов A. Windows ScriptHost для Windows 2000/ХР (+дискета)	640 с.
Попов А., Шишкин Е. Администрирование Windows с помощью WMI WMIC 752 с. (+CD-ROM)
Федорчук А., Торн A. FreeBSD: установка, настройка, использование	640 с.
Филимонов А. Протоколы Интернета	528 с.
Серия «Профессиональное программирование»
Агуров П. Практика программирования USB	624 с.
Боресков А. Расширения Open GL	688 с.
Боровский А. Программирование в Delphi 2005	450 с.
Буторин Д. MS Agent и Speech API в Delphi	^48 с.
Гайдуков С. OpenGL. Профессиональное программирование трехмерной 736 с. графики на C++ (+CD-ROM)
Горнаков С. DirectX 9. Уроки программирования на C++ (+CD-ROM)	400 с.
Климов A. MS Agent. Графические персонажи для интерфейсов (+CD-ROM) 352 с.
Магда Ю. Использование ассемблера для оптимизации программ на C++	496 с.
(+CD-ROM)
Мержевич Е. Ускорение работы сайта	384 с.
Несвижский В. Программирование аппаратных средств в Windows	880 с.
(+CD-ROM)
Петюшкин A. HTML в Web-дизайне	400 с.
Пирогов В. MS SQL Server 2000: управление и программирование	608 с.
Плаугер П. STL - стандартная библиотека шаблонов C++	656 с.
Серия «Учебное пособие»/«Учебник»
Барсегян А. Методы и модели анализа данных: OLAP и Data Mining	336 с.
(+CD-ROM)
Белов Д. и др. Разработка экспертных систем. Среда CLIPS	608 с.
Бенькович Е. Практическое моделирование динамических систем (+CD-ROM) 464 с.
Бенькович Е. и др. Практическое моделирование динамических систем 464 с. (+CD-ROM)
Боев В. Моделирование систем. Инструментальные средства GPSS World 368 с. Бойко В. Схемотехника электронных систем. Микропроцессоры и	464 с.
микроконтроллеры
Бойко В. Схемотехника электронных систем. Цифровые устройства	512 с.
Бойко В. Схемотехника электронных систем. Аналоговые и импульсные	450 с.
устройства
Большаков В. Инженерная и компьютерная графика. Практикум	592 с.
Вуль В. Электронные издания (+дискета)	560 с.
Гомоюнов К. Транзисторные цепи	240 с.
Грушвицкий Р. и др. Проектирование систем на микросхемах	608 с.
программируемой логики
Доманова Ю. и др. Высшая математика на базе Mathcad. Общий курс	608 с.
Ирвин Дж., Харль Д. Передача данных в сетях: инженерный подход	448 с.
Иртегов Д. Введение в сетевые технологии	560 с.
Кубенский А. Структуры и алгоритмы обработки данных:	464 с.
объектно-ориентированный подход и реализация на C++ (+CD-ROM)
Кузнецов А. и др. Математика для экономистов на базе Mathcad	496 с.
Культин Н. Delphi в задачах и примерах (+CD-ROM)	288	с.
Культин Н. C/C++ в задачах и примерах	288	с.
Культин Н. Turbo Pascal в задачах и примерах	256 с.
Лурье Б., Энрайт П. Классические методы автоматического управления	640 с.
Макаров Е. Сопротивление материалов на базе Mathcad (+CD-ROM)	512	с.
Никулин Е. Основы теории автоматического управления. Частотные методы 640 с. анализа и синтеза систем
Никулин Е. Компьютерная геометрия и алгоритмы машинной графики	560 с.
Порее В. Компьютерная графика	432 с.
Поршнев С. Вычислительная математика. Курс лекций	320 с.
Рапаков Г., Ржеуцкая С. Программирование на языке Pascal	480 с.
Робачевский Г. Операционная система Unix	528 с.
Романов Е. Практикум по программированию на C++	432 с.
Сафронов И. Бейсик в задачах и примерах	224 с.
Сеннов А. Курс практической работы на ПК	576 с.
Солонина А. и др. Цифровые процессоры обработки сигналов фирмы MOTOROLA	512 с.
Солонина А. Основы цифровой обработки сигналов. Курс лекций	608 с.
Солонина А., Улахович Д., Яковлев Л. Алгоритмы и процессоры цифровой 464 с. обработки сигналов
Сорокина С. и др. Программирование драйверов и систем безопасности - 256 с.
Стешенко В. Р-CAD. Технология проектирования печатных плат	720 с.
Суворова Е., Шейнин Ю. Проектирование цифровых систем на VHDL	576 с.
Угрюмое Е. Цифровая схемотехника, 2-е изд.	800 с.
Ускова О. и др. Программирование алгоритмов обработки данных	192 с.
Хрящев В., Шипова Г. Моделирование и создание чертежей в системе	224 с.
AutoCAD
Чемоданова Т. Pro/Engineer: деталь, сборка, чертеж	560 с.
Шелест В. Программирование	592 с.
Юревич Е. Основы робототехники, 2-е изд. (+CD-ROM)	416 с.
Серия «Научное издание»
Воеводин В., Воеводин Вл. Параллельные вычисления	608	с.
Касьянов В., Евстигнеев В. Графы в программировании: обработка,	1104 с.
визуализация и применение
Молдовян А. и др. Криптография: от примитивов к синтезу алгоритмов	448	с.
Молдовян А. и др. Криптография: скоростные шифры	496	с.
Серия «Компьютер и творчество»
Людиновсков С. Музыкальный видеоклип своими руками	320 с.
Петелин Р. Cakewalk. "Примочки" и плагины	272 с.
Петелин Р. Cool Edit Pro. Секреты мастерства (+CD-ROM)	432 с.
Петелин Р. Sonar. Секреты мастерства (+CD-ROM)	656 с.
Петелин Р. Аранжировка музыки на PC	272 с.
Петелин Р. Звуковая студия в PC	256 с.
Петелин Р. Музыкальный компьютер. Секреты мастерства, 2-е изд.	688 с.
Внесерийные книги
Mandrakesoft. Установка и использование Mandrakelinux 10.0 (+CD-ROM)	144 с.
Андрианов В., Соколов А. Автомобильные охранные системы.	272 с.
Справочное пособие
Богданов-Катьков Н. Струйные принтеры для дома и офиса	224 с.
Боков В. Физика магнетиков Учебное пособие для вузов	-	129 с.
Бутиков Е Оптика Учебное пособие для студентов физических	480 с.
специальностей вузов, 2-е изд
Быков А и др ADEM CAD/CAM,rTDM Черчение, модернизация,	320 с.
механообработка (+CD-ROM)
Гасфилд Д. Строки, деревья и последовательности в алгоритмах	854 с.
Гласс Г., Эйблс К. Unix для программистов и пользователей, 3-е изд.	848 с.
Гольдштейн Б. Стек протоколов ОКС7. Подсистема ISUP. Справочник	480 с.
Гольдштейн Б. Интерфейсы V5 1 и V5.2 Справочник	288 с.
Гольдштейн Б Системы коммутации, 2-е изд.	318 с.
Гольдштейн Б. Call-центры и компьютерная телефония	372 с.
Гурова А. Герои меча и магии. По мотивам одноименной компьютерной игры 320 с. Дорот В., Новиков Ф Толковый словарь современной компьютерной лексики, 608 с. 3-е изд.
Зыль С. QNX Momentics: основы применения (+CD-ROM)	256 с.
Зыль С. Операционная система реального времени QNX:	192 с.
от теории к практике, 2-е изд. (+CD-ROM)
Иванов К. Сборник задач по элементарной математике для абитуриентов, 352 с. 4-е изд.
Канторович Л., Акилов Г. Функциональный анализ, 4-е изд.	818 с.
Карпюк В. MS Windows ХР Professional. Опыт сдачи сертификационного	528 с.
экзамена 70-270
Корнеев В., Киселев А. Современные микропроцессоры, 3-е изд.	448 с.
Кохась К. Задачи Санкт-Петербургской олимпиады школьников по	224 с.
математике 2003 года
Кохась К. Задачи Санкт-Петербургской олимпиады школьников по	224 с.
математике 2004 года
Культин Н. Visual Basic. Освой на примерах (+CD-ROM)	288 с.
Макаров Б. и др. Избранные задачи по вещественному анализу, 2-е изд.	624 с.
Малыхина М. Базы данных: основы, проектирование, использование	512 с.
Палмер М., Синклер Р. Проектирование и внедрение компьютерных сетей. 240 с. Учебный курс, 2-е изд.
Петров Ю. Новые главы теории управления и компьютерных вычислений 192 с. Пирогов В. Ассемблер. Учебный курс, 2-е изд.	1056 с
Пог Д. MS Windows ХР Home Edition: недокументированные возможности	768 с
Погорелов В. AutoCAD 2005 для начинающих	400 с.
Половко А. Интерполяция. Методы и компьютерные технологии их реализации 320 с. Попов А. Администрирование Windows с помощью WMI и WMIC (+CD-ROM)	752 с.
Попов С. Аппаратные средства мультимедиа. Видеосистема PC	400 с.
Правин О. Правильный самоучитель работы на компьютере, 2-е изд.	496 с.
Прохоров А. Интернет: как это работает	280 с.
Роб П. Системы баз данных: проектирование, реализация и управление, 5-е изд. 299 с. Роб П. Системы баз данных: проектирование, разработка и использование	1200 с.
Робачевский А. Операционная система UNIX	528	с.
Романовский И. Дискретный анализ, 3-е изд.	320	с.
Скляров Д. Искусство защиты и взлома информации	288 с.
Соколов А., Андрианов В. Альтернатива сотовой связи:	448 с.
транкинговые системы
Соколов А., Степанюк О. Защита от компьютерного терроризма	126 с.
Соломенчук В., Соломенчук П. Железо ПК 2004	368 с.
Суворов К., Черемных М. Справочник Delphi. Базовые классы	576 с.
Титтел Э., Чеппел Л. TCP/IP. Учебный курс (+CD-ROM)	976	с.
Феличи Д. Типографика: шрифт, верстка, дизайн	360	с.
Фленов М. Библия Delphi (+CD-ROM)	880	с.
Фленов М. Программирование в Delphi глазами хакера	(+CD-ROM)	368	с.
Фленов М. Программирование на C++ глазами хакера (+CD-ROM)	336	с.
Фрей Д. AutoCAD и AutoCAD LT для начинающих	680 с.
Частиков А. Архитекторы компьютерного мира	384 с.
Яцюк О. Основы графического дизайна на базе компьютерных технологий 270 с. (+CD-ROM)
ВЕСЬ МИР
компьютерных книг
Уважаемые господа!
Издательство “БХВ-Петербург” приглашает специалистов в области компьютерных систем и информационных технологий для сотрудничества в качестве авторов книг по компьютерной тематике.
Если Вы знаете и умеете то, что не знают другие, если у Вас много идей и творческих планов, если Вам не нравится то, что уже написано...
напишите книгу вместе с “БХВ-Петербург”
Ждем в нашем издательстве как опытных, так и начинающих авторов и надеемся на плодотворную совместную работу.
С предложениями обращайтесь к главному редактору Екатерине Кондуковой
Тел.: (812)331-6465,331-6469
E-mail: kat@bhv.ru
Россия, 199397, Санкт-Петербург, а/я 194, www.bhv.ru
Магазин-салон «НОВАЯ ТЕХНИЧЕСКАЯ КНИГА»
190005, Санкт-Петербург, Измайловский пр., 29
В МАГАЗИНЕ ПРЕДСТАВЛЕНА ЛИТЕРАТУРА
ПО
компьютерным технологиям радиотехнике и электронике физике и математике строительству и архитектуре
покупателям
Тел.: (812) 251-41-10, e-mail: trade@techkniga.com