VBA. Практическое программирование
.pdf
Моделирование физического процесса
стенками объема, где движутся шарики равно 10 метрам, и, кроме того, шар 1 располагается левее шара 2, поэтому мы предлагаем выбрать значение начальных координат соответственно 2 и 6. В ячейке G2 находим разность координат второго и первого, и следим за тем, чтобы она была больше единицы. Мы закончили создание области ввода и ввели исходные данные. Эту область можно «украсить» различными методами форматирования, снабдить примечаниями и т. д.
Под вычисления займем область — A5:D5. Вписываем формулы — в A5 пишем =mmm1, в C5 — =mmm2. В 4 строке поместим комментарии — «1 шар», «2 шар». В ячейках B5 и D5 в дальнейшем будут отображаться координаты движущихся шариков. Пока туда можно записать те же значения, что содержатся в E2 и F2. Теперь все готово для построения диаграммы.
Построение диаграммы
Диаграмму будем строить таким образом, чтобы получить на ней изображение обоих шариков, положение которых будет зависеть от координат X, находящихся в ячейках B5 и D5; Y, равных 2, а размеры от массы (A5 и C5). В этом случае необходимо выбрать пузырьковую диаграмму, содержащую два ряда. Используя возможности контекстного меню для диаграмм (области диаграммы, области построения, и так далее) создаем внешний вид диаграммы по своему вкусу, но обязательно нужно для оси Х минимальное и максимальное значение шкалы установить соответственно 0 и 10, отказавшись от режима «Авто» для этих параметров. Кроме того, необходимо убрать легенду и ось Y. Также можно на диаграмму поместить объект «Надпись» с соответствующим текстом. Другими словами, на данном этапе мы имеем богатые возможности для графического оформления задуманного проекта.
Теперь нужно написать программу, для того чтобы заставить шарики двигаться. Уже сейчас, меняя вручную значения координат шариков или их массы в расчетном блоке (строка 5 таблицы), можно заставить шарики перемещаться по диаграмме или графику или рисунку... (все зависит от оформления).
Шарики должны двигаться
Код будем писать под событие Click. Создаем управляющую (командную) кнопку. Заменим стандартное CommanButton1 íà
111
3. Проекты на VBA
Рис. 3.1. Фрагмент оформления таблицы
слово «Старт», также можно изменить стиль и цвет фона (BackStyle и BackColor), тип, размеры и цвет шрифта (Font и ForeColor).
При написании кода в первую очередь позаботимся о том, чтобы данные из ячеек ЭТ попали в переменные программы. Нам нужны начальные координаты шариков. Это ячейки E2 и F2 (строка 2, столбцы 5 и 6), поэтому две первые строчки будут выглядеть так
xxn1 = Cells(2, 5) xxn2 = Cells(2, 6)
Теперь определимся со скоростями. Начальные скорости расположены в ячейках B2 и D2. В программе мы их обозначим через переменные dx1 è dx2. Координату шарика через промежуток времени t мы будем вычислять в соответствии с известной формулой физики X=Xo+V*t. Полагаем t=1/10, и тогда dx = V/10. Получаем следующие две строчки
dx1 = Cells(2, 2) / 10 dx2 = Cells(2, 4) / 10
Очередные две строчки — это передача начальных координат в текущие координаты —переменные x1 è x2, которые будут использованы в цикле. Возможен вариант и более короткого кода, но мы для доступности сокращать не будем.
112
Моделирование физического процесса
x1 = xxn1
x2 = xxn2
Также нам в программе понадобятся и массы. Они располагаются в ячейках A2 и C2, поэтому
m1 = Cells(2, 1)
m2 = Cells(2, 3)
Теперь начинаем расчет в цикле до 100 раз. Принимаем, что увеличение счетчика на 1 — это увеличение времени на 1/10 с, то есть наблюдаем в течение 10 условных секунд, и при выбранных скоростях и расстояниях такое значение можно считать оптимальным.
For i = 1 To 100
Позаботимся, чтобы шарики не вылетали за стенки. Первый шарик не должен улететь налево и если он приблизился к левой стенке (ее координата равна 0), то его скорость должна поменяться по знаку. Кроме того, чтобы зрительно шарик не «влипал» в стенку, запретим ему приближаться к ней ближе, чем на 0,5. Поэтому
If x1 <= 0.5 Then dx1 = Abs(dx1)
Для второго шарика «опасна» правая стенка с координатой 10 и с учетом «влипания» получаем 9,5
If x2 >= 9.5 Then dx2 = –1 * Abs(dx2)
Следующий шаг — процесс соударения. Это когда первый шарик (левый) приблизился ко второму менее чем на 1(размеры шариков), то скорости шариков меняются в соответствии с формулами (1) и (2). Попутно заметим, что если мы работаем в системе метры — секунды, то шарики у нас — метровые гиганты. Такой вот бильярд или боулинг!!!
If x1 >= x2 – 1 Then
a = dx1 ' — это скорость V1 перед ударом,
dx1 = (dx1 * (m1 – m2) + 2 * dx2 * m2) / (m1 + m2) ' — ýòî óæå U1 dx2 = a + dx1 – dx2 ' — à ýòî óæå U2
End If
Итак, значения скорости тел в случае соударении со стенками или друг с другом определены, теперь находим новые координаты,
113
3. Проекты на VBA
а если таких событий не было, то тем более пора определить, где же будут шарики через очередные 1/10 с.
x1 = x1 + dx1
x2 = x2 + dx2
Теперь эти значения отправим в ЭТ, чтобы диаграмму изменить. А положение шариков в диаграмме определяется ячейками B и D в пятой строке.
Cells(5, 2) = x1
Cells(5, 4) = x2
Следующая строка кода очень важна. Эта строка дает возможность электронной таблице произвести перерасчет в соответствии с новыми данными, а также перестроить диаграмму (перевод команды — «делай события»)
DoEvents
Завершем цикл
Next i
И вообще
End Sub.
Полностью код выглядит следующим образом Private Sub CommandButton1_Click()
xxn1 = Cells(2, 5) xxn2 = Cells(2, 6) dx1 = Cells(2, 2) / 10 dx2 = Cells(2, 4) / 10 x1 = xxn1
x2 = xxn2
m1 = Cells(2, 1)
m2 = Cells(2, 3)
For i = 1 To 100
If x1 <= 0.5 Then dx1 = Abs(dx1)
If x2 >= 9.5 Then dx2 = –1 * Abs(dx2) If x1 >= x2 – 1# Then
a = dx1
dx1 = (dx1 * (m1 – m2) + 2 * dx2 * m2) / (m1 + m2) dx2 = a + dx1 – dx2
End If
114
Создание оригинальных тестов
x1 = x1 + dx1
x2 = x2 + dx2 Cells(5, 2) = x1 Cells(5, 4) = x2 DoEvents Next i
End Sub
Проверка программы
Проверить работу программы мы можем следующим образом — если массы тел равны, а скорости равны и противоположны по направлению, то получится симметричная картинка. Задаем нача- льные значения — массы по 5, скорости 5 и –5, начальные значе- ния — 2,5 и 7,5. Получаем достаточно знакомую картину соударения двух одинаковых шаров с одинаковыми скоростями.
Кроме того, во время работы программы можно заметить, что в ячейках пятой строки меняются значения. Это изменяются координаты шариков. Также можно вывести в какие-нибудь ячейки и значения скоростей. Таким образом, ячейки таблицы играют роль ячеек памяти и можно наблюдать за изменением значений переменных, что полезно для анализа работы программ или ее отладки.
Создание оригинальных тестов
Цель проекта
Следующий небольшой пример, предлагаемый Вашему вниманию — проект, в котором пользователю предлагается собрать нужное предложение. Подобный тест может найти эффективное применение при изучении иностранного языка, когда необходимо правильно построить какую-нибудь грамматическую конструкцию, или когда необходимо выучить определение, стихотворение и т. д. Понятно, что область применения подобных форм тестирования достаточно широка. Кроме того, познакомившись с работой этого проекта, Вы увидите, что при работе с этой программой происходит тренировка наблюдательности и внимания.
Итак, предполагается, что пользователь в ответ на вопрос программы должен из предлагаемых ему слов составить предложение в определенной последовательности, причем часть предлагаемых
115
3. Проекты на VBA
слов не используется. В качестве предложения берем строку из одной песни, а проект так и назовем «Любимая песня»
План проекта
В нашем проекте будем использовать два рабочих листа — на одном будет происходить тестирование, работа, а другой лист — «Для служебного пользования», поэтому и дадим этим листам имена Worka и DSPA. На втором листе расположим сам вопрос, нужные и «мешающие» слова, вспомогательные сведения, иначе говоря, то, что нужно нам, но не пользователю.
Вывод вопроса по нажатию кнопки в элемент управления Надпись не представляет труда, а вот где разместить слова для выбора, и каким образом человек будет указывать на свой выбор — это необходимо продумать. Здесь целесообразно заметить, что мы проект делаем для кого-то и надо позаботиться о том, что тот, кто будет работать, не испытывал дискомфорта.
Если каждое из предлагаемых слов размещать в каком-нибудь элементе управления, то тогда придется создавать достаточно большое, и к тому же еще заведомо неопределенное количество этих элементов, мало того, каждому элементу нужно свое имя и, следовательно, придется это разнообразие имен учитывать при написании кодов.
Лучше всего, если слова будут размещены в ячейках, а действия с этими словами будут производиться, если пользователь просто щелкнет по нему. Например, при щелчке по «правильному» слову, оно попадет в предложение, а если «кликнули» по «неправильному» слову, то в предложении появляются знаки вопросов. Для реализации подобного сценария необходимо использовать процедуру для события рабочего листа Private Sub Worksheet_ Selection Change(ByVal Target As Range), которая запускается, если пользователь изменил выделенную область ячеек. И оказывается, что эта процедура предполагает использовать переменную с именем Target, причем под этим именем как раз и будет прятаться выделенный диапазон ячеек
Работаем с ячейками
Сначала мы должны позаботимся о том, чтобы процедура срабатывала только в том случае, если число выделенных ячеек равно одному, и затем эта одна ячейка не должна быть пустой. Действительно, пользователь от волнения (или по другим причинам) мо-
116
Создание оригинальных тестов
жет выделить не одну ячейку, в которой содержится слово, а несколько, или пустую ячейку.
Эти два условия, первое из которых более значимо и проверяется отдельно в коде, записаны следующим образом
If Target.Count = 1 And flag Then
If Not Target = Empty Then
Напомним, что вместо привычного Range или Cells мы можем писать Target, потому что это и есть имя выделенного диапазона ячеек. По поводу переменной flag мы поговорим позже.
Еще одной особенностью проекта является составление кода правильного ответа. Для данного теста нам важно, чтобы слова в предложении располагались в определенной последовательности, а лишние слова вообще не признавались. В таком случае имеет смысл каждому слову в предложении присвоить свой номер по порядку, указать число правильных слов, а все лишние слова будут иметь номера, большие, это число. На втором листе мы расположим правильное предложение в ячейках одного столбца, и туда же добавим какие-нибудь «лишние» слова, общее число слов со- считаем с помощью формулы, а число правильных укажем сами. Да, еще и не забудем пронумеровать все слова.
И чтобы окончательно разобраться с рабочим листом DSPA, там же напечатаем сам вопрос и текст небольшой справки.
Особенности программы
Еще одна задача, требующая решения — при нажатии на кнопку «Старт» разместить слова случайным образом в ячейках листа Worka. Тогда мы организуем цикл, в котором поочередно берется слово со служебного листа и помещается в ячейку, расположенную в y строке и x колонке. Значения x è y выбираются случайным образом, но так, чтобы они попали в заранее определенную нами область рабочего листа (a6:k17). Но такое размещение возможно, если эта ячейка не занята ранее, поэтому в коде должны быть строки, проверяющие занятость ячейки (If Cells(y, x) = Empty Then...). Если ячейка оказалась занятой, то размещения очередного слова не происходит, а счетчик цикла уменьшается на единицу, и мы опять ищем свободную ячейку для этого же слова.
После размещения слова в ячейке в код добавлено несколько строчек для украшения этой ячейки, и кроме того, в ячейке, рас-
117
3. Проекты на VBA
положенной на 100 строчек ниже размещаем порядковый номер этого слова (это необходимо для проверки ответа).
После размещения всех слов необходимо позаботиться о том, чтобы длинные слова, случайно оказавшиеся в соседних по горизонтали ячейках не наезжали друг на друга. С этой целью используется метод автовыравнивания столбцов — Columns(«a:k»).AutoFit.
Итак, тест начался. Человек нажал на кнопку «Старт», вопрос появился в одном месте экрана, другая область чиста, там со временем появится предложение. Выбрали нужное слово и щелкнули по нему. Процедура ...SelectionChange... проверила и убедилась, что выделена одна не пустая ячейка. В таком случае переменная list1 (порядковый номер слова в предложении) увеличивается на единицу и сравнивается с номером выбранного слова. Если выбор неверен, то в предложение добавляются знаки вопроса, а list1 уменьшается на единицу. В случае правильного выбора очередное слово добавляется к предложению и производится проверка на длину предложения. Если предложение завершено, то логическая переменная flag принимает значение false, а так как эта переменная проверяется в начале процедуры на истинность, то теперь указанная процедура работать не будет.
Если человек не понял, что надо делать, то достаточно нажать на кнопку в правой части листа и получить небольшую справку.
Полный код программы выглядит так
Public list1 As Integer, flag As |
Объявление переменных |
Boolean |
|
|
|
Public a As String |
|
|
|
Private Sub |
|
CommandButton1_Click() |
|
|
|
Range("a6:k17").Clear |
Очищаем области от данных |
|
|
Range("a99:k117").Clear |
|
|
|
Lblvop.Caption = |
Помещаем вопрос в Lblvop |
Worksheets("dspa").Cells(1, 6) |
|
|
|
list1 = 0 |
Подготовка переменных |
|
|
flag = True |
|
|
|
a = "" |
|
|
|
|
|
118
|
Создание оригинальных тестов |
|
|
|
|
|
|
|
Lblotv.Caption = "" |
Готовим элемент управления для |
|
|
ввода предложения |
|
Lblotv.BorderColor = 0 |
||
|
||
DoEvents |
Реализуем события рабочего листа |
|
|
|
|
psl = Worksheets("dspa").Cells(1, 3) |
Считываем количество слов |
|
|
в предложении |
|
For i = 1 To psl |
Начинаем цикл для заполнения |
|
|
рабочего листа словами |
|
|
|
|
x = Int(Rnd * 10) + 1 |
Выбираем случайную ячейку |
|
y = Int(Rnd * 10) + 7 |
|
|
If Cells(y, x) = Empty Then |
Если она пуста |
|
|
|
|
Cells(y, x) = |
То помещаем туда очередное слово, |
|
Worksheets("dspa").Cells(i, 2) |
меняем шрифт, цвет фона |
|
Cells(y, x).Interior.Color = vbYellow |
и границы |
|
|
||
|
|
|
Cells(y, x).Font.Size = 12 |
|
|
|
|
|
Cells(y, x).Font.Bold = True |
|
|
Cells(y, x).Borders.Color = vbRed |
|
|
|
|
|
Cells(y + 100, x) = i |
Порядковый номер слова прячем |
|
|
на100 строчек ниже |
|
Else |
А если ячейка не пуста |
|
|
|
|
i = I — 1 |
Счетчик уменьшим на 1 и опяь |
|
|
ищем ячейку |
|
End If |
|
|
Next |
Переход к очередному слову |
|
|
|
|
Columns("a:k").AutoFit |
Автоподбор ширины столбца |
|
End Sub |
|
|
|
|
|
Private Sub |
Процедура для вывод справки — |
|
CommandButton2_Click() |
сообщения |
|
|
|
|
MsgBox |
|
|
(Worksheets("dspa").Cells(3, 6)) |
|
|
|
|
|
End Sub |
|
|
|
|
|
|
|
|
Private Sub |
Процедура, запускаемая при |
|
Worksheet_SelectionChange(ByVal |
изменении выделенной области |
|
Target As Range) |
на рабочем листе |
|
|
|
|
|
|
119
3. Проекты на VBA
If Target.Count = 1 And flag Then |
Должна быть выделена только одна |
|
If Not Target = Empty Then |
и не пустая ячейка (при этом |
|
flag=true) |
||
|
||
list1 = list1 + 1 |
Порядковый номер слова в |
|
|
предложении возрос на 1 |
|
x = Target.Column |
Адрес выбранной ячейки в формате |
|
y = Target.Row |
строка—столбец |
|
|
||
nom = Cells(y + 100, x) |
Считывается номер выбранного |
|
|
слова |
|
If list1 nom Then |
Если номера не совпадают |
|
a = a + " " + "???" |
То в предложение добавляем |
|
|
вопросы |
|
list1 = list1 — 1 |
И возвращаемся на исходные |
|
|
позиции |
|
Else |
Иначе |
|
a = a + " " + Target |
В предложение добавляем |
|
|
угаданное слово |
|
Target = "" |
Выделенную ячейку делаем пустой |
|
If list1 = Worksheets("dspa").Cells(1, |
И проверяем: не достигнут ли |
|
4) Then |
конец предложения |
|
flag = False |
Åñëè "äà" òî flag = False |
|
Lblotv.BorderColor = vbBlue |
Завершенное предложение |
|
|
помещается в рамку |
|
Range("a6:k17").Clear |
А все лишние слова удаляются |
|
End If |
|
|
End If |
|
|
Lblotv.Caption = a |
В элемент Надпись помещается |
|
|
предложение |
|
End If |
|
|
End If |
|
|
End Sub |
|
|
|
|
Развитие проекта
Если Вы попробовали поработать с этим проектом, то наверняка Вам захочется вставить свое предложение, а может быть и предложить кому-нибудь из ближайшего окружения пройти тест.
120
