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

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

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

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

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

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

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

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

Занятие 11. Проектирование новой версии приложения

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

Цикл 2

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

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

Требования

Выдвинем требования к новой версии.

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

Взаимосвязано с этим другое требование.

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

Отсюда вытекает третье требование.

Следует воспретить пропуск неотвеченных вопросов при продвижении вперед.

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

Анализ

Выделим виды деятельности, которые приложение должно осуществлять соответственно этим требованиям.

  • восстановление значения ответа при перемещении по списку вопросов
  • запрещение пропуска вопроса, на который не дан ответ

Явно не указаны, но подразумеваются такие виды деятельности:

  • сохранение значений ответов, данных на вопросы
  • определение вопроса, на который не дан ответ
  • Составим схему видов деятельности:

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

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

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

Не совсем наглядные рассуждения, не правда ли?

Моделирование нового объекта – временного хранилища

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

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

  • Вообразите, как вы будете учитывать ответы на вопросы тестируемого ученика.

Правильно, будете  составлять таблицу примерно такого вида:

номер вопроса правильный ответ полученный ответ вопрос отвечен?
1 3 3 да
2 2 1 да
3 3 3 да
4 1 1 да
5 1 2 нет
6 3 3 нет
7 1 1 нет

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

Несколько слов о порядке заполнения хранилища данными.

Столбец правильных ответов, очевидно, заполняется данными из основного хранилища приложения, которым является таблицы Excel. Целесообразно делать это при запуске приложения. Для экономии ресурсов компьютера это можно делать и в процессе теста, но потом вы увидите, что это временное хранилище очень компактно, реализация заполнения в процессе работы принесет гораздо больше неудобств, нежели преимуществ. Только в случае очень больших – десятки тысяч и более, – вопросов, следует обращаться к динамическому считыванию данных из основного хранилища.

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

Последний столбец содержит флаги. Он заполняется только при работе приложения.

Первый (крайний левый) столбец фиктивный, эти данные не существуют, а помещены в таблицу лишь для наглядности. Далее вы увидите, что имеется в виду.

Теперь определимся с объектами, нужными для выполнения требований к приложению.

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

  • при обычной работе:

  • при переходе по списку вопросов (без тестирования):

  • Теперь следует схематично изобразить взаимодействие этих объектов при работе приложения.

Схема взаимодействия

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

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

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

  • Самостоятельно составьте схемы взаимодействия объектов так, чтобы они охватывали три момента деятельности – создание приложения, процесс тестирования и переход по списку вопросов. Должны быть использованы все объекты, найденные нами ранее.

Вот что, например, может у вас получиться:

Схема взаимодействия объектов при запуске приложения:

Схема взаимодействия объектов в процессе работы (тестирования):

При изображении «множественного» объекта или набора допустимо использовать «двойной» значок. На данной схеме так выглядит объект Переключатели.

Схема взаимодействия объектов при переходе по списку вопросов:

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

следует читать так: «Ограничитель пропуска неотвеченного вопроса ограничивает функциональность кнопок перехода путем изменения их состояния».

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

Не следует излишне детализировать – точность будет достигнута позже.

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

  • Внесите коррективы в схемы объектов.
Реализация

Теперь займемся реализацией временного хранилища.

Проектирование структуры временного хранилища

Вспомните примерную структуру хранилища, определенную нами ранее. Как видите, оно состоит из повторяющихся строк, несущих несколько единиц информации.

  • Это можно представить так:

Подобные конструкции нам уже знакомы. Это – наборы VBA. Вы уже работали со встроенными наборами MS Office.

Недостаток большинства встроенных наборов MS Office – их низкое быстродействие. В случае больших наборов, содержащих несколько сотен элементов и более, падение скорости приложений бывает значительным.

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

Но не спешите.

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

  • Строение «строки» хранилища представим так:

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

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

Пользовательский тип

Пользовательский тип – разновидность переменной особого типа, определяемого пользователем (как следует из названия).

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

Синтаксис пользовательского типа таков:

Type <имя_типа>
<элемент_1> As <тип>
<элемент_2> As <тип>
.
.
.
End Type

<имя_типа> будет использоваться при объявлении переменной – обычным способом.

<элемент_N> – имя ячейки пользовательского типа. Это имя будет в дальнейшем использоваться программой.

Определение пользовательского типа помещается в разделе глобальных объявлений модуля. Могут применяться квалификаторы Public- Private.

Подробности вы найдете в справке VBA по запросу Type Statement.

Давайте определимся с нашим типом, предназначенным для хранения «строки» хранилища.

Пусть новый тип называется tStore – сокращенно от Type–Store (Тип–Хранилище).

Тогда описание типа будет таким:

Type tStore
.
.
.
End Type

В «строке» нашего хранилища три ячейки. Первая содержит числовое значение правильного ответа, вторая – полученного ответа, третья – флага.

Пусть ячейки носят имена:

Well – от Верный, Правильный,

Answ – от AnswerОтвет,

FlagФлаг.

  • Дополним описание типа:

Type tStore
Well
Answ
Flag
End Type

Необходимо в каждую строку включить явное объявление типа.

Тип третьей строки очевиден – логический:

Type tStore
Well
Answ
Flag As Boolean
End Type

Остальные строки будут нести целое числовое значение. Можно использовать уже знакомый нам Integer, но, так как следует заранее заботиться о размерах хранилища – ведь заранее неизвестно, сколько вопросов будет в тесте, – примем тип Byte. Этот целочисленный тип может принимать значения от 0 до 255. В нашем случае значения будут от 1 до 3 – хватит с запасом. А экономия памяти при работе приложения может быть значительной, особенно при больших размерах теста.

Итак, вновь созданный тип будет определен так:

Type tStore
Well As Byte
Answ As Byte
Flag As Boolean
End Type

  • Внесите этот код в область глобальных объявлений модуля basShell.

Это – заготовка «ячейки» временного хранилища.

Массив

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

Оказывается, VBA имеет набор, полностью удовлетворяющий этим требованиям. Такие наборы называются массивами.

Массив – набор некоторого числа элементов одинакового типа. Элементы набора нумеруются по порядку.

Максимальное число элементов массива – 32768 (при нумерации с 0 до 32767). В справке VBA это явно не указано, подразумевается, что нумерация элементов производится при помощи числа типа Integer, максимально допустимое значение которого и есть 32767.

Массив объявляется подобно обычной переменной:

Dim <имя_массива>(<нижняя_граница> To <верхняя_граница>) As <тип_элемента>

Например:

Dim arSample (0 To 15) As Integer

Объявленный здесь массив arSample содержит 16 (от 0 до 15) элементов типа Integer. Обратиться, к примеру, к элементу номер 5 можно так:

arSample(5)

Работа с элементом массива происходит точно так же, как и с обычной переменной. Например, так назначается значение 24 элементу номер 10:

arSample(10) = 24

<тип_элемента> при объявлении массива может быть любым из допустимых для переменных, в том числе и вновь созданным пользовательским типом.

Значит, для нашего теста из четырех вопросов можно объявить хранилище так:

Dim arStore (1 To 4) As tStore

Тогда прочитать из хранилища значение правильного ответа на вопрос номер 3 можно так:

<значение> = arStore(3).Well

Как видно, применение пользовательских типов схоже с обращением к свойствам объектов.

Но, как мы условились, число вопросов теста заранее не определено. Подобное объявление массива не удовлетворяет условиям.

И для такого случая VBA имеет готовое решение.

Можно объявить массив без указания нижней и верхней границы, а потом, в начале работы программы, присвоить ему требуемые размеры.

Объявление так называемого динамического массива будет выглядеть так:

Dim arStore() As tStore

А где-то в начале выполнения приложения (но уже после подсчета числа вопросов) понадобится сделать так:

ReDim arStore (<нижняя_граница> To <верхняя_граница>)

Подобное переопределение может изменить только границы массива. Тип элементов переопределить невозможно.

Решим, когда же следует производить переопределение.

Очевидно, после подсчета числа вопросов теста. Этот подсчет производится в процедуре StartTest.

Реализация временного хранилища

  • Внесите определение массива-хранилища в область глобальных объявлений модуля basShell:

Dim arStore() As tStore

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

Public Sub StartTest()
Set shtCurrent = ActiveWorkbook.Worksheets("Лист1")
intCurrentRecord = 1
fEnd = False
intQuestions = shtCurrent.Range("A1").CurrentRegion.Rows.Count / LineCount
ReDim arStore(1 To intQuestions)
Load frmTest
RecordRead intCurrentRecord
frmTest.Show vbModeless
End Sub

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

Все должно пройти без ошибок.

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

Мы нечувствительно реализовали найденный ранее объект создатель хранилища и произвели первый подцикл второго цикла создания приложения.

Итог занятия

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

Основная же тема занятия – массивы, пользовательские типы и работа с ними. Для повторения и закрепления материала сделайте конспект:

  • Массив, определение, синтаксис. Назначение массива. Доступ к элементам массива (на примере).
  • Динамический массив, его отличие от обычного массива. Синтаксис объявления и использования.
  • Пользовательский тип, понятие, синтаксис, назначение. Доступ к значениям (на примере).

Весь материал доступен в этом занятии, искать в справке VBA вам не придется.

Hosted by uCoz