Введение в программирование на примере VBA
Часть II. Создание макроса-приложения
Занятие 7. Вывод данныхЦель настоящего занятия – создать код, обеспечивающий отображение данных на элементах визуального интерфейса приложения. Подцикл 3. Чтение и вывод данныхЗадача следующего подцикла – сделать так, чтобы данные из хранилища считывались в контролы на форме при ее запуске. Опишем произвольно действия, которые следует совершить для этого. При запуске формы следует считать данные из ячеек таблицы Excel (которая содержит тестовые материалы). Данные из ячейки, содержащей текст вопроса, помещаются в текстовое поле на форме. Данные из ячеек, содержащих текст ответов, помещаются в переключатели. Как видите, мы пока не касаемся чтения правильных ответов. Проектирование последовательности действийСледующий вид схем-диаграмм, с которым вам следует познакомиться – схемы последовательности действий. Как следует из названия, эти схемы иллюстрируют порядок выполнения какого-то сложного действия. Именно подобные схемы изображают то, что называют «алгоритмом». Эти схемы немного сложнее применявшихся раньше. Начало последовательности обычно обозначается «кружочком»:
Начало на схеме одно. Каждый шаг, проходимый при работе программы, изображается «овалом»:
Порядок перехода от шага к шагу последовательности соответствует «стрелочкам». Следует размещать овалы-шаги так, чтобы цепочка не «петляла». Обычно схема читается сверху-вниз. Конец последовательности – «кружок с ободком»:
Проанализируйте ход действий согласно схеме Оказывается, так можно делать, если мы имеем один ответ. В нашем случае ответов несколько. Для каждого из них последовательность действий будет повторяться, а именно эти действия:
Ответов у нас несколько. Конкретно – три, но в общем случае – может быть другое число. Конечно, допустимо решение, когда пишется отдельный код для каждого ответа. Это – самое негибкое и неудобное решение. При этом пишется большой объем повторяющегося кода, изменения в одной части кода должны будут дублироваться в других, при желании увеличить число ответов придется делать значительные модификации кода. Преимущество данного способа – небольшое увеличение быстродействия, что ввиду некоторых особенностей VBA незаметно. Однако у нас существует одно решающее ограничение VBA. Оказывается, к контролам нельзя обращаться как к членам набора – то есть, «переключатель первый», «второй» и так далее. Поэтому придется писать код для каждого ответа. Изменим схему:
Теперь перейдем к реализации. Реализация чтения данных таблицы ExcelОсновной вопрос, который следует решить для получения возможности выполнения требуемых действий – как получить доступ к данным в хранилище? Доступ к данным таблицы Excel Взгляните на созданную нами таблицу Excel, в которую занесены тестовые данные. Как видите, логической единицей данных является ячейка таблицы. Ячейки сгруппированы в ряды и колонки. Освежим наши знания о дереве объектов MS Excel. Как помните, основной единицей хранения данных выступает объект Range, который может составлять наборы Cells, Rows и Columns. Обратимся к справке по объектной модели Excel.
Перед вами описание объекта Range. Один из подразделов этой страницы справки называется Cells Property – Свойство Cells. Из описания видим синтаксис применения этого свойства: Cells(<ряд>,<колонка>) Видимо, это и есть искомый объект, дающий нам возможность работы с данными. Взгляните еще раз на таблицу с данными. Данные вопроса находятся в первой колонке, данные ответов – в четвертой. Теперь попробуем записать все, что мы узнали.
Все три повторения изображать не будем. Обратите внимание, что комментарии на «листочках» схемы очень похожи на код VBA. Своеобразный прием, используемый при разработке приложений – псевдокод. Как следует из названия, это – «как-бы код», при написании которого используются как слова языка программирования (VBA или другого, хорошо известного разработчику), так и произвольные слова «обычного» языка. При написании псевдокода следует стремиться, чтобы результат как можно больше имитировал «настоящую» программу. Хороший псевдокод потребует минимальных изменений для того, чтобы превратиться в обычный код.
<Текст> = Cells(1,1).Text Чтобы не вводить дополнительную и ненужную более нигде сущность <Текст>, изменим строки: txtQuestion.Text =
Cells(1,1).Text Добавим строки, соответствующие другим переключателям: txtQuestion.Text =
Cells(1,1).Text Уже лучше. А к какому объекту относится свойство Cells? Следует дополнить код указанием на «родительский» объект. Согласно схеме дерева объектов Excel объект Range (составляющий набор Cells) есть «потомок» объекта Worksheet. Объекты Worksheet (рабочие листы) адресуются как члены набора Worksheets по имени. Имя вы можете прочитать на ярлычке внизу окна Excel:
Здесь открыт лист по имени « Лист1». Если в вашем случае имя листа другое –переименуйте лист (это делается при помощи контекстного меню, возникающего при правом щелчке на ярлычке листа). Обращение к ячейке изменится: Worksheets(“Лист1”).Cells(1,1).Text Теперь следует обозначить, к какому объекту относится лист. Еще раз взглянем на дерево объектов. «Родительский» объект для листа – книга Workbook. Книга может обозначаться как член набора Workbooks, обращение – по имени файла книги. А можно и по-другому. Если помните, есть специальное название для книги, активной в данный момент – ActiveWorkbook. Тогда при работе с тестовым приложением вам придется воздержаться от открывания других документов Excel – для учебного приложения данный способ вполне применим. Тогда полное обращение будет такое: ActiveWorkbook.Worksheets(“Лист1”).Cells(1,1).Text Код станет таким: txtQuestion.Text =
ActiveWorkbook.Worksheets(“Лист1”).Cells(1,1).Text Этот код уже будет работать. Но он громоздок и медленен – VBA каждый раз будет анализировать эти громадные строки заново. Прежде чем пытаться улучшить код, следует проверить его работоспособность. Реализация чтения данныхСоздадим процедуру, отвечающую за чтение данных из хранилища. Решим, как мы будем оформлять процедуру чтения данных. Для этого следует определить, в какой момент будет происходить обращение к хранилищу. Напрашивается ответ – при создании формы. Но вспомните, что повторные обращения будут происходить также при переходе по списку вопросов. Если обращения к коду предполагается производить из разных участков программы, этот код следует оформить в виде отдельной процедуры. Где же расположить эту процедуру? Очевидный ответ – внутри самой формы. Это неплохое решение, во многом упрощающее задачу. Другой вариант – вынести эту процедуру в отдельный модуль. Такое решение более правильно с точки зрения построения кода. Тогда эту процедуру в перспективе можно будет использовать в других проектах (как – вы узнаете в конце учебника). Кроме того, один из принципов построения приложений предостерегает от размещения лишнего кода в компонентах, отображаемых визуально. Недостаток второго способа – необходимость явно указывать форму, содержащую контролы, к которым происходит обращение. Но это не должно составить затруднений. Поместим код в модуле. Назовем процедуру RecordRead – ЧтениеЗаписи.
Public Sub RecordRead()
Код процедуры приобретет вид: Public Sub RecordRead() Теперь следует выполнить обращение к процедуре. В этом модуле уже имеется процедура, отвечающая за запуск приложения – StartTest.
Public Sub StartTest() То есть чтение данных будет проводиться после загрузки формы (строка Load), но до ее показа (строка Show).
Если вы были внимательны – все получится. Сокращение кодаТеперь подумаем об упрощении и сокращении кода. Повторимся – это не только сделает текст программы короче и удобочитаемее, сокращение кода, как правило, ускоряет работу приложений, написанных на VBA. Первая идея, приходящая на ум – использование конструкции With. Но в данном случае требуется одновременно две такие конструкции, используемые одновременно – для обращения к форме и для обращения к рабочему листу-хранилищу. Если мы сделаем двойную конструкцию With, то VBA не будет знать, к какому объекту мы обращаемся, выполнение будет невозможным. Поэтому одно из обращений придется оставить «как есть», занявшись сокращением второго. Очевидно, что код, обращающийся к ячейкам хранилища, требует большего внимания ввиду своей громоздкости. Можно его вынести в строку With. Код приобретет вид: Public Sub RecordRead() Неплохое решение. Но можно сделать лучше. Форма как объект, обладающий визуальным представлением, довольно «громоздка» с точки зрения VBA. Перенести форму в строку With – хорошее решение. Что же тогда делать с обращением к ячейкам? Кэширование объекта Существует понятие «кэширования» объекта, этим мы сейчас и займемся. Сначала освежим в памяти понятие переменной, одно из фундаментальных в языках программирования вообще и в VBA в частности. Определение: Переменная есть именованное хранилище данных (имеется в виду – в памяти компьютера), содержимое которого можно читать и изменять. Переменная в VBA выступает в роли особого рода объекта. Этот объект «хранит» в себе другой объект и представляет его в процессе выполнения программы. Другими словами, любая переменная имеет имя. Принципы назначения имени такие же, как и в других случаях имен VBA. Но работа с переменной включает еще одно важное действие – объявление переменной. Иначе говоря, перед тем, как использовать переменную, ее надо создать. Синтаксис объявления переменной таков: Dim <имя_переменной> As <тип> Об <имени_переменной> уже сказано. <Тип> есть обозначение разновидности данных, которые могут содержаться в этой переменной. С понятием типа мы встречались при знакомстве с параметрами процедур. Как можно заметить, параметры есть частный случай переменных. Список встроенных типов VBA вы найдете в справке.
Перед вами – более правильный синтаксис объявления переменной. Но на нашем этапе подобные сложности не нужны, для успешной работы вполне достаточно упрощенного синтаксиса, приведенного выше. На этой странице справки вы найдете абзац с описанием типов переменных VBA:
Переходя по подчеркнутым гиперссылкам, вы можете ознакомиться с описанием этих типов. Кроме того, можно задавать название типа как критерий поиска справочной системы. Итак, вернемся к нашему коду.
Public shtCurrent As Worksheet
Имя shtCurrent – от словосочетания Sheet Current, Лист Текущий. Как и в других случаях, имя произвольно. Тип этой переменной – Worksheet – РабочийЛист Excel. Да-да, переменные также можно объявлять как публичные или приватные. Мы используем публичное объявление для того, чтобы эту переменную можно было использовать во всем проекте. Обратите внимание на надписи в верхних списках модуля: слева (General) – Общий, а справа – (Declarations) – Объявления. Для быстрого перехода в область объявлений публичных переменных достаточно выбрать эти пункты. После объявления переменную следует инициализировать. Это значит, что ей надо назначить значение до того, как использовать далее в программе. Если объявления допускается помещать в начале модуля, то инициализация должна происходить в тексте какой-то процедуры. Очевидное место для этого – процедура запуска приложения StartTest.
Public Sub StartTest() Обратите внимание на строку Set shtCurrent = ActiveWorkbook.Worksheets("Лист1") Именно здесь происходит присвоение значения переменной shtCurrent. Слово Set – Присвоить, Назначить, – в начале строки необходимо при изменении значения объектной переменной, а Worksheet – объект Excel, тогда как строка присвоения значения переменной другого типа выглядела бы так же, но без Set. Теперь переменную можно использовать.
Public Sub RecordRead() Как видите, код значительно сократился.
Применение With к коду Вот сейчас можно применить With. Рекомендуется делать это для формы. Казалось бы – не имеет значения, переносить в With слово frmTest или shtCurrent. На самом же деле обращение к форме всегда влечет за собою объемную работу VBA, скрытую от пользователя, обращение же к рабочему листу Excel уже произведено при назначении значения переменной. Выгоднее сделать так: Public Sub RecordRead()
Вы выполнили уже довольно большую работу, скорее всего, забыв при этом один из основных принципов аккуратного программирования – необходимость комментариев. Исправьте упущение.
Не забывайте делать это и в дальнейшем. Следующее занятие будет посвящено взаимодействию пользователя с создаваемым приложением. Итог занятияВ ходе занятия, помимо практических навыков, вы получили некоторую теоретическую информацию, важную для работы. В самом начале занятия вы познакомились с новым видом схем, применяемых при проектировании приложений. Схема последовательности действий очень важна, правильно составленная, она естественно преобразуется в код, не требуя дополнительных размышлений. Как и в случае других схем, следует стремиться к простоте и наглядности. Не допускайте запутанных построений, связей-стрелок, идущих через всю схему и неоднократно пересекающихся. Если схема занимает более одной страницы – подумайте, все ли вы правильно сделали, скорее всего, придется повторить проектирование. Рассмотрение концепции сокращения кода привела нас к потребности изучения понятия переменной. Вот тут – ваш конспект:
Теперь не поленитесь поработать со справочной системой, и самостоятельно найдите информацию к следующим разделам конспекта:
Другие типы вам пока что не особенно нужны. Обратите внимание на то, что типы данных, перечисленные выше, можно сгруппировать, согласно разновидности данных, которые можно помещать в них.
Подсказка – должно получиться четыре группы, одна из которых делится на две подгруппы. Ответы на некоторые из этих вопросов вы сможете найти в этой книге, и тогда – проверите, правильно ли справились с заданием. Наконец, дайте примеры объявления переменной для каждой группы и напишите пример присвоения значения этим переменным, используя данные, соответствующие типу переменной. Опишите особенности объявления и использования переменных объектного типа. Конструкция With встречалась вам раньше, но обратите внимание, как производился выбор объекта для помещения в эту конструкцию. Сложно сказать, какой объект «тяжелее» для VBA – форма или лист Excel. Но лист Excel мы легко смогли кэшировать в переменной – для формы это было бы сложнее, поэтому кэшируем лист. |