В начало
Статьи
Библиотека
Разное

Вот здесь - новый сайт, заходите немедленно!

kift - Коллекция Интересных Фактов и Теорий

А тут можно поболтать и побухтеть, милости просим:

kift - неизданное

Введение в программирование на примере VBA

Часть II. Создание макроса-приложения

Аннотация
Предисловие
Часть I. Макрос Word
     1. Проектирование и запись макроса
     2. Разбор макроса
     3. Внесение исправлений
     Итоги
Часть II. Макрос-приложение
     4. Проектирование
     5. Визуальное редактирование
     6. Запуск и остановка
    7. Вывод данных
     8. Выбор ответа
     9. Перемещение по списку
     10. Обратное перемещение
     11. Новая версия
     12. Реализация новой версии
     13. Завершение работы
     Итоги
Часть III. Объект на основе класса
     14. "Основное" приложение
     15. Компонент-таймер
     Итоги
Послесловие

Занятие 7. Вывод данных

Цель настоящего занятия – создать код, обеспечивающий отображение данных на элементах визуального интерфейса приложения.

Подцикл 3. Чтение и вывод данных

Задача следующего подцикла – сделать так, чтобы данные из хранилища считывались в контролы на форме при ее запуске.

Опишем произвольно действия, которые следует совершить для этого.

При запуске формы следует считать данные из ячеек таблицы Excel (которая содержит тестовые материалы).

Данные из ячейки, содержащей текст вопроса, помещаются в текстовое поле на форме.

Данные из ячеек, содержащих текст ответов, помещаются в переключатели.

Как видите, мы пока не касаемся чтения правильных ответов.

Проектирование последовательности действий

Следующий вид схем-диаграмм, с которым вам следует познакомиться – схемы последовательности действий.

Как следует из названия, эти схемы иллюстрируют порядок выполнения какого-то сложного действия. Именно подобные схемы изображают то, что называют «алгоритмом».

Эти схемы немного сложнее применявшихся раньше.

Начало последовательности обычно обозначается «кружочком»:

Начало на схеме одно.

Каждый шаг, проходимый при работе программы, изображается «овалом»:

Порядок перехода от шага к шагу последовательности соответствует «стрелочкам». Следует размещать овалы-шаги так, чтобы цепочка не «петляла». Обычно схема читается сверху-вниз.

Конец последовательности – «кружок с ободком»:

  • Составим схему:

Проанализируйте ход действий согласно схеме

Оказывается, так можно делать, если мы имеем один ответ. В нашем случае ответов несколько. Для каждого из них последовательность действий будет повторяться, а именно эти действия:

Ответов у нас несколько. Конкретно – три, но в общем случае – может быть другое число.

Конечно, допустимо решение, когда пишется отдельный код для каждого ответа. Это – самое негибкое и неудобное решение. При этом пишется большой объем повторяющегося кода, изменения в одной части кода должны будут дублироваться в других, при желании увеличить число ответов придется делать значительные модификации кода. Преимущество данного способа – небольшое увеличение быстродействия, что ввиду некоторых особенностей VBA незаметно.

Однако у нас существует одно решающее ограничение VBA. Оказывается, к контролам нельзя обращаться как к членам набора – то есть, «переключатель первый», «второй» и так далее. Поэтому придется писать код для каждого ответа.

Изменим схему:

Теперь перейдем к реализации.

Реализация чтения данных таблицы Excel

Основной вопрос, который следует решить для получения возможности выполнения требуемых действий – как получить доступ к данным в хранилище?

Доступ к данным таблицы Excel

Взгляните на созданную нами таблицу Excel, в которую занесены тестовые данные. Как видите, логической единицей данных является ячейка таблицы. Ячейки сгруппированы в ряды и колонки.

Освежим наши знания о дереве объектов MS Excel.

Как помните, основной единицей хранения данных выступает объект Range, который может составлять наборы Cells, Rows и Columns.

Обратимся к справке по объектной модели Excel.

  • Откройте Excel.
  • Откройте тестовое приложение test.xls
  • Запустите IDE VBA.
  • Перейдите в IDE.
  • Нажмите [F1].
  • Перейдите на вкладку поиска.
  • Введите слово, согласно которому будет происходить поиск – range.
  • Нажмите [Enter].
  • В появившемся списке выберите строку Range Object.

Перед вами описание объекта Range. Один из подразделов этой страницы справки называется Cells PropertyСвойство Cells. Из описания видим синтаксис применения этого свойства:

Cells(<ряд>,<колонка>)

Видимо, это и есть искомый объект, дающий нам возможность работы с данными.

Взгляните еще раз на таблицу с данными. Данные вопроса находятся в первой колонке, данные ответов – в четвертой.

Теперь попробуем записать все, что мы узнали.

  • Сначала в схему:

Все три повторения изображать не будем.

Обратите внимание, что комментарии на «листочках» схемы очень похожи на код VBA.

Своеобразный прием, используемый при разработке приложений – псевдокод. Как следует из названия, это – «как-бы код», при написании которого используются как слова языка программирования (VBA или другого, хорошо известного разработчику), так и произвольные слова «обычного» языка. При написании псевдокода следует стремиться, чтобы результат как можно больше имитировал «настоящую» программу. Хороший псевдокод потребует минимальных изменений для того, чтобы превратиться в обычный код.

  • А теперь уйдем от схемы и напишем только строки «псевдокода», показывающие нам последовательность действий:

<Текст> = Cells(1,1).Text
txtQuestion.Text = <Текст>

<Текст> = Cells(1,4).Text
optAnswer1.Caption = <Текст>

Чтобы не вводить дополнительную и ненужную более нигде сущность <Текст>, изменим строки:

txtQuestion.Text = Cells(1,1).Text

optAnswer1.Caption = Cells(1,4).Text

Добавим строки, соответствующие другим переключателям:

txtQuestion.Text = Cells(1,1).Text

optAnswer1.Caption = Cells(1,4).Text

optAnswer2.Caption = Cells(2,4).Text

optAnswer3.Caption = Cells (3,4).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

optAnswer1.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(1,4).Text

optAnswer2.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(2,4).Text

optAnswer3.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(3,4).Text

Этот код уже будет работать. Но он громоздок и медленен – VBA каждый раз будет анализировать эти громадные строки заново.

Прежде чем пытаться улучшить код, следует проверить его работоспособность.

Реализация чтения данных

Создадим процедуру, отвечающую за чтение данных из хранилища.

Решим, как мы будем оформлять процедуру чтения данных.

Для этого следует определить, в какой момент будет происходить обращение к хранилищу.

Напрашивается ответ – при создании формы.

Но вспомните, что повторные обращения будут происходить также при переходе по списку вопросов.

Если обращения к коду предполагается производить из разных участков программы, этот код следует оформить в виде отдельной процедуры.

Где же расположить эту процедуру?

Очевидный ответ – внутри самой формы. Это неплохое решение, во многом упрощающее задачу.

Другой вариант – вынести эту процедуру в отдельный модуль. Такое решение более правильно с точки зрения построения кода. Тогда эту процедуру в перспективе можно будет использовать в других проектах (как – вы узнаете в конце учебника).

Кроме того, один из принципов построения приложений предостерегает от размещения лишнего кода в компонентах, отображаемых визуально.

Недостаток второго способа – необходимость явно указывать форму, содержащую контролы, к которым происходит обращение. Но это не должно составить затруднений.

Поместим код в модуле. Назовем процедуру RecordReadЧтениеЗаписи.

  • Откройте в IDE VBA созданный нами модуль basShell.
  • Создайте заготовку процедуры:

Public Sub RecordRead()

End Sub

  • Разместите в этой заготовке сконструированный нами код.

Код процедуры приобретет вид:

Public Sub RecordRead()

frmTest.txtQuestion.Text = ActiveWorkbook.Worksheets(“Лист1”).Cells(1,1).Text

frmTest.optAnswer1.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(1,4).Text

frmTest.optAnswer2.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(2,4).Text

frmTest.optAnswer3.Caption = ActiveWorkbook.Worksheets(“Лист1”).Cells(3,4).Text

End Sub

Теперь следует выполнить обращение к процедуре.

В этом модуле уже имеется процедура, отвечающая за запуск приложения – StartTest.

  • Измените ее код так:

Public Sub StartTest()

Load frmTest

RecordRead

frmTest.Show vbModeless

End Sub

То есть чтение данных будет проводиться после загрузки формы (строка Load), но до ее показа (строка Show).

  • Сохраните приложение и выполните пробный запуск.

Если вы были внимательны – все получится.

Сокращение кода

Теперь подумаем об упрощении и сокращении кода. Повторимся – это не только сделает текст программы короче и удобочитаемее, сокращение кода, как правило, ускоряет работу приложений, написанных на VBA.

Первая идея, приходящая на ум – использование конструкции With. Но в данном случае требуется одновременно две такие конструкции, используемые одновременно – для обращения к форме и для обращения к рабочему листу-хранилищу.

Если мы сделаем двойную конструкцию With, то VBA не будет знать, к какому объекту мы обращаемся, выполнение будет невозможным.

Поэтому одно из обращений придется оставить «как есть», занявшись сокращением второго. Очевидно, что код, обращающийся к ячейкам хранилища, требует большего внимания ввиду своей громоздкости. Можно его вынести в строку With.

Код приобретет вид:

Public Sub RecordRead()

With ActiveWorkbook.Worksheets("Лист1")

frmTest.txtQuestion.Text = .Cells(1, 1).Text

frmTest.optAnswer1.Caption = .Cells(1, 4).Text

frmTest.optAnswer2.Caption = .Cells(2, 4).Text

frmTest.optAnswer3.Caption = .Cells(3, 4).Text

End With

End Sub

Неплохое решение. Но можно сделать лучше.

Форма как объект, обладающий визуальным представлением, довольно «громоздка» с точки зрения VBA. Перенести форму в строку With – хорошее решение. Что же тогда делать с обращением к ячейкам?

Кэширование объекта

Существует понятие «кэширования» объекта, этим мы сейчас и займемся.

Сначала освежим в памяти понятие переменной, одно из фундаментальных в языках программирования вообще и в VBA в частности.

Определение:

Переменная есть именованное хранилище данных (имеется в виду – в памяти компьютера), содержимое которого можно читать и изменять.

Переменная в VBA выступает в роли особого рода объекта. Этот объект «хранит» в себе другой объект и представляет его в процессе выполнения программы.

Другими словами, любая переменная имеет имя. Принципы назначения имени такие же, как и в других случаях имен VBA.

Но работа с переменной включает еще одно важное действие – объявление переменной. Иначе говоря, перед тем, как использовать переменную, ее надо создать.

Синтаксис объявления переменной таков:

Dim <имя_переменной> As <тип>

Об <имени_переменной> уже сказано.

<Тип> есть обозначение разновидности данных, которые могут содержаться в этой переменной.

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

Как можно заметить, параметры есть частный случай переменных.

Список встроенных типов VBA вы найдете в справке.

  • Перейдите в IDE VBA.
  • Нажмите [F1] для вызова справки.
  • Произведите поиск по слову dim.
  • В списке результатов поиска выберите строку Dim StatementОператор Dim.

Перед вами – более правильный синтаксис объявления переменной. Но на нашем этапе подобные сложности не нужны, для успешной работы вполне достаточно упрощенного синтаксиса, приведенного выше.

На этой странице справки вы найдете абзац с описанием типов переменных VBA:

Переходя по подчеркнутым гиперссылкам, вы можете ознакомиться с описанием этих типов. Кроме того, можно задавать название типа как критерий поиска справочной системы.

Итак, вернемся к нашему коду.

  • Откройте код модуля basShell.
  • Перейдите в самое начало модуля, еще до начала первой процедуры.
  • Введите строку:

Public shtCurrent As Worksheet

Имя shtCurrent – от словосочетания Sheet Current, Лист Текущий. Как и в других случаях, имя произвольно. Тип этой переменной – WorksheetРабочийЛист Excel.

Да-да, переменные также можно объявлять как публичные или приватные. Мы используем публичное объявление для того, чтобы эту переменную можно было использовать во всем проекте.

Обратите внимание на надписи в верхних списках модуля: слева (General)Общий, а справа – (Declarations)Объявления. Для быстрого перехода в область объявлений публичных переменных достаточно выбрать эти пункты.

После объявления переменную следует инициализировать. Это значит, что ей надо назначить значение до того, как использовать далее в программе.

Если объявления допускается помещать в начале модуля, то инициализация должна происходить в тексте какой-то процедуры. Очевидное место для этого – процедура запуска приложения StartTest.

  • Измените код процедуры так:

Public Sub StartTest()

Set shtCurrent = ActiveWorkbook.Worksheets("Лист1")

Load frmTest

RecordRead

frmTest.Show vbModeless

End Sub

Обратите внимание на строку

Set shtCurrent = ActiveWorkbook.Worksheets("Лист1")

Именно здесь происходит присвоение значения переменной shtCurrent. Слово SetПрисвоить, Назначить, – в начале строки необходимо при изменении значения объектной переменной, а Worksheet – объект Excel, тогда как строка присвоения значения переменной другого типа выглядела бы так же, но без Set.

Теперь переменную можно использовать.

  • Перейдите в код процедуры RecordRead и измените ее код так:

Public Sub RecordRead()

frmTest.txtQuestion.Text = shtCurrent.Cells(1, 1).Text

frmTest.optAnswer1.Caption = shtCurrent.Cells(1, 4).Text

frmTest.optAnswer2.Caption = shtCurrent.Cells(2, 4).Text

frmTest.optAnswer3.Caption = shtCurrent.Cells(3, 4).Text

End Sub

Как видите, код значительно сократился.

  • Сохраните изменения и сделайте пробный запуск.

Применение With к коду

Вот сейчас можно применить With. Рекомендуется делать это для формы. Казалось бы – не имеет значения, переносить в With слово frmTest или shtCurrent. На самом же деле обращение к форме всегда влечет за собою объемную работу VBA, скрытую от пользователя, обращение же к рабочему листу Excel уже произведено при назначении значения переменной. Выгоднее сделать так:

Public Sub RecordRead()

With frmTest

.txtQuestion.Text = shtCurrent.Cells(1, 1).Text

.optAnswer1.Caption = shtCurrent.Cells(1, 4).Text

.optAnswer2.Caption = shtCurrent.Cells(2, 4).Text

.optAnswer3.Caption = shtCurrent.Cells(3, 4).Text

End With

End Sub

  • Внесите изменения, сохраните приложение и сделайте пробный запуск.

Вы выполнили уже довольно большую работу, скорее всего, забыв при этом один из основных принципов аккуратного программирования – необходимость комментариев.

Исправьте упущение.

  • Добавьте комментарии к каждой строке созданного кода. Опишите в них назначение кода своими словами, понятными для вас.

Не забывайте делать это и в дальнейшем.

Следующее занятие будет посвящено взаимодействию пользователя с создаваемым приложением.

Итог занятия

В ходе занятия, помимо практических навыков, вы получили некоторую теоретическую информацию, важную для работы.

В самом начале занятия вы познакомились с новым видом схем, применяемых при проектировании приложений. Схема последовательности действий очень важна, правильно составленная, она естественно преобразуется в код, не требуя дополнительных размышлений. Как и в случае других схем, следует стремиться к простоте и наглядности. Не допускайте запутанных построений, связей-стрелок, идущих через всю схему и неоднократно пересекающихся. Если схема занимает более одной страницы – подумайте, все ли вы правильно сделали, скорее всего, придется повторить проектирование.

Рассмотрение концепции сокращения кода привела нас к потребности изучения понятия переменной. Вот тут – ваш конспект:

  • Переменная, понятие, синтаксис.
  • Типы переменных – понятие.

Теперь не поленитесь поработать со справочной системой, и самостоятельно найдите информацию к следующим разделам конспекта:

  • Тип Byte – описание, допустимые величины.
  • Тип Integer – описание, допустимые величины.
  • Тип Long – описание, допустимые величины.
  • Тип Single – описание, допустимые величины.
  • Тип Double – описание, допустимые величины.
  • Тип String – описание, допустимые величины.
  • Тип Boolean – описание, допустимые величины.
  • Тип Variant – описание, допустимые величины.

Другие типы вам пока что не особенно нужны. Обратите внимание на то, что типы данных, перечисленные выше, можно сгруппировать, согласно разновидности данных, которые можно помещать в них.

  • Разбейте перечисленные выше типы на группы.

Подсказка – должно получиться четыре группы, одна из которых делится на две подгруппы.

Ответы на некоторые из этих вопросов вы сможете найти в этой книге, и тогда – проверите, правильно ли справились с заданием.

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

Опишите особенности объявления и использования переменных объектного типа.

Конструкция With встречалась вам раньше, но обратите внимание, как производился выбор объекта для помещения в эту конструкцию. Сложно сказать, какой объект «тяжелее» для VBA – форма или лист Excel. Но лист Excel мы легко смогли кэшировать в переменной – для формы это было бы сложнее, поэтому кэшируем лист.

Hosted by uCoz