Главная страница «Первого сентября»Главная страница журнала «Информатика»Содержание №21/2008


Предлагаю коллегам

Еще один Бейсик (три проекта на REALbasic)

Язык Бейсик в школе используется достаточно широко и в разных вариантах, начиная с QBasic и кончая Visual Basic.Net. И вообще платформа IBM PC является базой, на которой преподавать программирование легко — есть “море” компиляторов, выбирай, какой больше нравится. Но вот вам привезли Macintosh’и, и что с ними делать на уроках программирования? Есть, конечно, свободно распространяемые (не очень дружественные к начинающему) версии языка Паскаль, для работы которых необходимо установить комплект для разработчика — Xtools, требующий операционной системы не ниже Mac OS X 10.3. Вместе с тем для изучения Бейсика в среде Mac OS X прекрасно подходит объектно-ориентированная среда REALbasic компании Real Software, демоверсию которой можно загрузить с сайта компании (http://www.realsoftware.com). Имеются также версии для компьютеров IBM PC c операционной системой Windows.

Курс по основам объектно-ориентированного программирования в среде REALbasic преподавался автором ученикам 9-х классов московской школы № 1236 в течение четырех лет. В данной статье приводится ряд проектов из этого курса.

Рис. 1. Общий вид среды разработки REALbasic (вариант для компьютеров Macintosh)

Несколько слов о среде разработки

Поскольку у нас газетная статья, а не подробное руководство, многое придется опустить, но все-таки надо кратко сказать о том, как выглядит среда разработки REALbasic. Если запустить REALbasic, то на экране открываются несколько окон:

- окно проекта (Project Window), в котором значками изображены составляющие проект объекты — окна1, меню, модули (программы) и ресурсы, используемые в проекте (например, графические или текстовые файлы);

- панель инструментов — элементов управления (Control Palette); на ней размещены значки объектов, которые можно использовать в проектах, — кнопки, переключатели, линейки прокрутки, таймер и многие другие;

- окно свойств (Properties) показывает свойства выбранного объекта;

- пользовательское окно (форма) — объект класса Window, содержащий все стандартные элементы: заголовок, кнопки свертывания, закрытия и др. Имя объекта — Window1, заголовок в окне (по умолчанию Untitled) — это значение свойства Title. Если окна на экране нет, его можно открыть двойным щелчком на его значке в окне проекта.

Объекты размещаются на окне-форме перетаскиванием их с панели элементов управления. На рис. 1 показана форма с расположенными на ней объектами PushButton (кнопка), TextBox (текстовое поле), ComboBox (текстовое поле со списком выбора), ScrollBar (полоса прокрутки) и ImageWell (место для графического объекта).

Чтобы открыть Редактор Кода (Code Editor), достаточно выделить любой объект и дважды щелкнуть на нем. Окно редактора показано на рис. 2 и содержит 7 разделов:

- Constants (константы). Здесь описываются все константы, используемые в проекте;

- Controls (элементы управления). Содержит перечень всех размещенных на форме элементов управления со своими событиями и содержит подраздел для каждого элемента;

- Events (события) — этот раздел содержит код для событий, на которые может реагировать форма;

- Menu Handlers (обработчики меню). Главное меню проекта по умолчанию уже содержит некоторые пункты. Если вы добавили пункты меню (например, Save, Print, Open), к ним должен быть написан какой-то код, и именно он будет в этом разделе;

- Methods (методы). Здесь записываются свои собственные процедуры и функции;

- Notes (комментарии) — без комментариев :);

- Properties (свойства). В этом разделе описываются пользовательские переменные (в REALbasic переменные, связанные с объектом, также являются его свойствами).

 

Рис. 2. Окно редактора кода

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

 

Рис. 3. Окно редактора кода,
раскрытое в секции событий окна

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

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

Проект 1 “Тестер мыши”

Один из моих любимых проектов — тестер мыши. Вы рисуете на форме (а в REALbasic, напомню, это объект Window) схематическое изображение мыши, жмете на кнопочки “настоящей” мыши — изображение должно “моргать”, отображая щелчок. Если мышь двухкнопочная — проблем никаких нет. Но мы разработаем универсальный проект, который может быть реализован и с однокнопочной мышью (классическая “Мас'овская” мышь — именно такая!), и на компьютере iBook. Последний — это ноутбук с тачпадом (touchpad), щелчок по нижней части которого считается “щелчком мыши”.
В случае однокнопочной мыши и тачпада щелчок правой кнопкой мыши имитируется щелчком при нажатой клавише . Следовательно, нам придется отслеживать также событие клавиатуры.

Перед тем как рисовать, расcмотрим повнимательнее панель инструментов REALbasic. Первые две строки занимают простые элементы, выполняющие чаще всего декоративные функции — линии (Line), статический текст (StaticText), овал (Oval), прямоугольник (Rectangle) и прямоугольник со скругленными углами (RoundedRectangle). Третий ряд занимают объекты Placard, ImageWell и Canvas. Объект Placard чаще всего используется как объемный прямоугольник, который можно “утопить” в форму, или, наоборот, сделать выпуклым, объект ImageWell — всего лишь место для размещения картинки (на нем нельзя рисовать графическими методами), а объект Canvas может содержать и фоновую картинку, и воспринимать графические процедуры.

Итак, нарисуем схематическое изображение мыши:

 

Рис. 4. Форма (окно)
со схематическим изображением мыши

Для него использовали: прямоугольник со скругленными углами (RoundedRectangle) и два графических объекта Canvas (Холст). Также взяли стандартную кнопку PushButton1, значение свойства Caption (надпись) установили в “Тест”. При нажатии на кнопку должен закрашиваться объект Canvas1, при одновременном нажатии на кнопку и клавишу должен закрашиваться объект Canvas2.

Естественно, событие Action нам не подойдет, так как оно отслеживает только факт щелчка, а нам необходимо менять цвет холста как при нажатии (событие MouseDown), так и при отпускании кнопки мыши (событие MouseUp). В REALbasic методы, связанные с этими событиями, являются функциями. Напомню читателю, что в отличие от процедур функции возвращают некоторое значение. Функция, связанная с событием MouseDown, по умолчанию возвращает логическое значение false. В таком случае не будет возможности контролировать события мыши MouseUp (отпускание мыши) и MouseDrag (буксировка мыши); о последнем событии мы поговорим позже, когда будем делать простейший графический редактор. Поэтому надо вписать в функцию MouseDown оператор return true; если этого не сделать, то компилятор никакой ошибки не выдаст, но остальные события мыши (в том числе нужное нам событие MouseUp) отслеживаться не будут. Также замечу, что эта функция отслеживает координаты указателя мыши в момент события (это нам пригодится в следующем проекте), но номер кнопки не отслеживается, поскольку, как уже говорилось, у “классического Макинтоша” мышь однокнопочная.

Итак, для функции Window1.PushButton1.MouseDown запишем:

Function MouseDown(X as Integer, Y as Integer) As Boolean

if keyboard.controlKey then

canvas2.graphics.foreColor = rgb(0, 255, 0)

canvas2.graphics.fillrect(0, 0, canvas1.width, canvas1.height)

else

canvas1.graphics.foreColor = rgb(255, 255, 0)

canvas1.graphics.fillrect(0, 0, canvas1.width, canvas1.height)

end if

return true

End Function

Здесь мы применили ряд новых понятий. Во-первых, использовали объект Graphics. Для задания цвета использовали функцию RGB, позволяющую определять интенсивность красной, зеленой и синей составляющих. Холст, изображающий левую кнопку мышки (Canvas1), красим желтым, а холст для правой кнопки (Canvas2) — зеленым, для чего сначала задаем цвет переднего плана (Forecolor), а затем заливаем на холсте весь прямоугольник (метод FillRect).

Чтобы отличить левую кнопку от правой, используем, как уже было сказано, сочетание клавиши и “клика” по тачпаду. Проверяем также условие Keyboard.ControlKey — если клавиша нажата, значит, кнопка “правая”.

При отпускании кнопки цвет необходимо заменить на исходный — мышино-серенький.

Мы вернули из функции MouseDown значение true, следовательно, теперь система сможет “поймать” событие MouseUp. Записываем в редакторе кода для Window1.PushButton1.MouseUp:

Function MouseUp(X as Integer, Y as Integer) As Boolean

canvas1.graphics.foreColor = rgb(200, 200, 200)

canvas1.graphics.fillrect(0, 0, canvas1.width,

canvas1.height)

canvas2.graphics.foreColor = rgb(200, 200, 200)

canvas2.graphics.fillrect(0, 0, canvas1.width,

canvas1.height)

End Function

Проект готов.

Проект 2 “Простой графический редактор”

Если мы хотим сделать графический редактор, нам понадобится поле для рисования — объект Canvas, а также средства управления цветом и толщиной кисти. Различные значения толщины кисти занесем в объект ComboBox (Комбинированное поле), а для выбора цвета создадим специальную палитру. Для этого нам понадобится массив любых объектов, у которых есть свойство color (цвет). Можно взять обычный прямоугольник (Rectangle), для наглядности заменив его имя на, скажем, “col” (от color), и скопировать его. Вы получите сообщение “Do you want to create a control array?” (“Вы хотите создать массив элементов управления?”). Нужно ответить “yes”, и будет создан еще один экземпляр прямоугольника с таким же именем, но с новым индексом (“оригинал” получит индекс 0, копия —  индекс 1). Так можно получить 20 копий объекта col (c индексами 0–19). Раскрасим их в разные цвета, используя свойство color (см. рис. 5). Еще один такой объект с индексом 20 мы позже будем использовать для отображения выбранного цвета.

Обычно при работе в Visual Basic или в Borland Delphi с графикой мышь рисует при ее буксировке. Здесь же с событием MouseDown связана функция, в которую можно вписать возвращение логического значения true, если мышь должна рисовать при буксировке, и false — в противном случае.

Рис. 5. Как сделать палитру цветов

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

X1 as Integer

Y1 as Integer

В подраздел события нажатия мыши на холсте (выбираем Canvas1 в разделе Controls и далее для него — событие MouseDown) запишем, как и в проекте 1, return true и запомним в наших глобальных переменных X1 и Y1 координаты точки, в которой произошло нажатие мыши:

Window1.Canvas1.MouseDown

Function MouseDown(X as Integer,

Y as Integer) as boolean

X1 = x

Y1 = y

return true

End Function

Передача из функции MouseDown значения true обеспечивает возможность фиксации события MouseDrag, а именно при его наступлении происходит рисование. Обработка этого события осуществляется процедурой, а не функцией, так как ей нечего возвращать. Такая процедура Window1.Canvas1.MouseDrag имеет вид:

Sub MouseDrag(X as Integer, Y AS Integer)

canvas1.graphics.drawline x1,y1,x,y

x1 = x

y1 = y

End Sub

Толщину кисти будем выбирать в соответствии со значением, выбранным в списке Combobox1:

Window1.ComboBox1.TextChanged()

Sub TextChanged()

canvas1.graphics.penwidth = val(combobox1.text)

End Sub

— а цвет рисования — путем нажатия на одну из кнопок массива с именем col, при этом нас интересует только номер кнопки (индекс в массиве этих элементов):

Window1.col.MouseDown

Function MouseDown(Index as Integer,

X as Integer, Y as Integer) as Boolean

canvas1.graphics.foreColor = col(Index).fillColor

End Function

После этого уже можно рисовать

Рис. 6. Графический редактор
с фиксированным набором цветов готов

Усовершенствуем проект — предусмотрим возможность выбора любого цвета из палитры экрана при щелчке на кнопке с надписью “цвет” (см. рис. 7) — назначим на нее вызов стандартного диалога выбора цвета (в палитре CMYK), а отображать выбранный цвет будем на последнем отдельно стоящем прямоугольнике col с индексом 20:

Window1.Pushbutton1.Action

Sub Action()

Dim c as Color

Dim b as Boolean

c = CMY(.35, .9, .6)

b = SelectColor(c, "выберите цвет")

col(20).FillColor = c

End Sub

Рис. 7. Выбор произвольного цвета

Проект 3 “Анимация на спрайтах”

Прежде всего, что такое “спрайт”? Спрайтами обычно называются графические объекты, которые могут перемещаться по фону, не “смазывая” его.

Спрайты в REALbasic — это маленькие картинки, поведением которых управляет специальный объект SpriteSurface. В панели инструментов он выглядит как космическая ракета. Разместите его на форме вашего проекта, это сцена, на которой будет развиваться действие. Кто ходит в театр, знает, что у сцены бывает “задник”, т.е. декорации, размещенные на заднем плане. Роль задника у объекта SpriteSurface выполняет свойство backdrop. Для нашего спрайта для этого подойдут графические файлы с расширениями gif, jpeg, png и bmp. Как добавить графику в проект? Просто перетащите изображение файла в окно проекта (Project Window) — REALbasic сам даст этому объекту имя, похожее на имя перетаскиваемого файла. Следует только помнить, что это не сами файлы, а ссылки на них, поэтому файлы нельзя удалять, иначе проект работать не будет. После этого свойству backdrop присвойте соответствующее значение (в окне Property).

В нашем примере собака гонится за кошкой (не бойтесь — не догонит, скорость у кошки “из гуманных соображений” больше :), а чтобы показать, что происходит, когда спрайты сталкиваются, кто-нибудь из них периодически налетает на стол, стол переворачивается.

Необходимо создать объекты типа Sprite для стола, кошки и собаки, причем они должны быть видны во всех процедурах, т.е. быть глобальными. В REALbasic любой глобальный объект является свойством формы (окна), поэтому после размещения в проекте соответствующих изображений надо зайти в редактор кода формы Window1 и выполнить команды Edit | New | Property, после чего в появившемся окне набрать директиву Cat as Sprite и выбрать тип Public.

Аналогично для собаки и стола:

Dog as Sprite

Table as Sprite

Сделаем “лирическое”, точнее, “музыкальное” отступление. В отличие от программирования анимации с использованием элемента управления Timer (Таймер), когда последний берет на себя управление только тогда, когда возникает событие Timer, объект SpriteSurface полностью “захватывает процессор”, как только его запустят методом Run, и останавливается щелчком мыши (можно явно остановить методом Stop), поэтому сделать музыкальное сопровождение “фильма” трудно — ему не будет давать работать объект SpriteSurface, но мы попробуем. Создадим также глобальное свойство, отражающее высоту играемой ноты, разместим на форме объект NotePlayer и запишем для него:

Note as integer

Для запуска используем обычную кнопку — объект PushButton. Вот вид нашего проекта (см. рис. 8).

Рис. 8. Объект SpriteSurface, размещенный на главном окне проекта

В процедуре обработки события Action для кнопки запишем:

Sub Action()

Dim x0, y0 as integer

x0 = spriteSurface1.width - 10

y0 = rnd * (spriteSurface1.height - 50)

cat = new sprite

dog = new sprite

table = new sprite

table = spriteSurface1.newsprite(table1, 50, 200)

cat = spriteSurface1.newsprite(cat1, x0, y0)

dog = spriteSurface1.newsprite(dog1, x0 + 50, y0)

NotePlayer1.Instrument = 20

NotePlayer1.PlayNote(note, 0)

note = 60

spriteSurface1.run

End Sub

Здесь мы применили конструктор New для создания нового спрайта (после остановки объекта SpriteSurface, если спрайты не уничтожать, они так и лежат на сцене).

Основное событие для SpriteSurface — новый кадр (NewFrame):

Sub NewFrame()

if cat.image = cat1 then

cat.image = cat2

NotePlayer1.PlayNote(note, 100)

else

cat.image = cat1

end if

if dog.image = dog1 then

dog.image = dog2

else

dog.image = dog1

end if

dog.x = dog.x - 10

cat.x = cat.x - 20

noteplayer1.PlayNote(note, 0)

note = note + 1

if dog.x < 0 then

spriteSurface1.stop

end if

End Sub

Запустим программу и посмотрим фильм (см. рис. 9).

Рис. 9. Запущены три спрайта и загружен фон

А что произойдет, если кто-нибудь из них налетит на стол? Это событие Collision:

Window1.SpriteSurface1.Collision

Sub Collision(Sprite1, Sprite2)

Table.image = table2

End Sub

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

table.group = -1

cat.group = 1

dog.group = 1

Ну, вот и все. Надеюсь, REALbasic вам понравился, и вы самостоятельно поэкспериментируете с этой прекрасной средой.

Г.. В.. Некрасова

TopList