Прочие фрагменты процедуры Exam2 дополнительных комментариев не требуют.
Вызов процедуры Exam2 надо добавить в конец оператора case процедуры InitTask, связав его с номерами 17 и 18:
procedure InitTask(num: integer);
begin
case num of
1..2: UseTask('ExamBegin', 70 + num);
3..4: Exam1(num - 2);
5..16: UseTask('ExamTaskC', 20 + num);
17..18: Exam2(num - 16);
end;
end;
Кроме того, необходимо опять откорректировать параметр процедуры CreateGroup, определяющий количество заданий, положив его равным 18.
При нажатии клавиши [F9] на экране появится окно задачника с последним заданием данной группы (на рисунке приведен вид окна после прокрутки раздела с формулировкой задания):
Если теперь опять заменить символ ?" на символ "# " в параметре процедуры Task тестирующей программы, то при нажатии [F9] мы увидим html-страницу с описанием группы, которое теперь содержит не только импортированные, но и реализованные нами задания:
Поскольку при создании новых заданий мы указали в качестве параметра процедур CreateTask названия подгрупп (и разместили новые задания после заданий из данных подгрупп), новые задания отображаются в составе этих подгрупп: ExamDemo3 и ExamDemo4 -- в подгруппе "Преобразование массивов", а ExamDemo17 и ExamDemo18 -- в подгруппе "Обработка сложных наборов данных".
ABCObjects: быстрое введение
Основными типами графических объектов, определенными в модуле ABCObjects, являются RectangleABC, SquareABC, EllipseABC, CircleABC, TextABC, RegularPolygonABC, StarABC, PictureABC, MultiPictureABC, BoardABC и ContainerABC.
Типы графических объектов представляют собой классы, состоящие из методов и свойств, а также нуждающиеся в конструировании перед первым использованием. Изменение свойств влияет на внешний вид и поведение графических объектов. Например, при изменении свойств Width и Height меняются размеры графического объекта, при изменении свойства Color - цвет графического объекта и т.д. Вызов методов графического объекта возвращает или меняет его характеристики. Например, при вызове метода ToFront графический объект перемещается на передний план, а вызов метода Intersect(g) возвращает, пересекается ли текущий объект с объектом g.
Все графические объекты являются разновидностями класса ObjectABC, который содержит общие для всех свойства и методы.
Создадим два перекрывающихся графических объекта:
uses ABCObjects,GraphABC;
var
r: RectangleABC;
c: CircleABC;
begin
r := new RectangleABC(70,50,200,100,clMoneyGreen);
c := new CircleABC(120,80,110,clBlue);
end.
После запуска программы увидим на экране следующее:
Поменяем некоторые свойства графических объектов и вызовем метод MoveOn для окружности, дописав в конец программы следующие строки:
r.Width := 150;
c.Color := clRed;
c.MoveOn(30,30);
После запуска программы:
Добавим в конец программы следующие строки:
c.Number := 8;
r.Text := 'Hello';
r.ToFront;
После запуска программы:
ABCObjects: контейнеры графических объектов
Класс ContainerABC представляет собой контейнер графических объектов. Он также является потомком ObjectABC, но при создании не содержит ни одного объекта. Он добавляет следующий интерфейс:
procedure Add(g: ObjectABC);
property Count: integer; // количество объектов
property Objects[i: integer]: ObjectABC; // i-тый объект
При масштабировании ContainerABC производится масштабирование всех входящих в него объектов. При добавлении объекта в ContainerABC его свойство Owner становится равным этому ContainerABC. При присваивании свойству Owner объекта его владелец меняется, при этом объект перерисовывается как принадлежащий новому владельцу. При присваивании свойству Owner объекта значения nil он перестает иметь владельца и отображается непосредственно в графическом окне.
Рассмотрим следующую программу:
uses ABCObjects,GraphABC;
var
c1,c2: ContainerABC;
r: CircleABC;
begin
SetWindowSize(300,300);
c1 := new ContainerABC(50,30);
c1.Add(new RectangleABC(0,0,200,100,clGreen));
r := new CircleABC(15,15,70,clYellow);
end.
После ее запуска графический экран имеет вид:
Контейнер c1 содержит зеленый прямоугольник, а объект r не имеет владельца (r.Owner=nil). Нетрудно убедиться, что ObjectsCount=2 (контейнер и круг), а c1.Count=1.
Добавим круг в контейнер, дописав в конец программы строчку
c1.Add(r);
После запуска программы графический экран примет вид:
Круг r теперь принадлежит контейнеру (r.Owner=с2), ObjectsCount=1 (только контейнер), а c1.Count=2. Кроме этого, координаты круга пересчитываются относительно координат контейнера-владельца (они по-прежнему равны (15,15), но относительно левого верхнего угла контейнера c1).
Такой же эффект можно было получить от оператора
r.Owner := c1;
Создадим второй контейнер c2 и поменяем владельца у r на c2. Для этого допишем в конец строки:
c2 := new ContainerABC(50,160);
c2.Add(new RectangleABC(0,0,200,100,clMoneyGreen));
r.Owner := c2;
После запуска программы графический экран примет вид:
Как мы видим, круг r поменял владельца, и теперь имеет координаты (15,15), но относительно левого верхнего угла нового владельца c2.
Если вместо строчки r.Owner:=c2; написать r.Owner:=nil; , то круг r потеряет владельца и снова будет позиционироваться относительно левого верхнего угла экрана:
Примеры
Данная программа иллюстрирует применение процедур LockDrawing и Redraw для реализации анимации без мерцания:
uses GraphABC;
begin
LockDrawing;
for var i:=1 to 500 do
begin
Window.Clear;
Brush.Color := clGreen;
Ellipse(i,100,i+100,200);
Redraw;
Sleep(1);
end;
end.
Основная идея состоит в следующем: отключим рисование на экране, вызвав LockDrawing (рисование будет осуществляться только во внеэкранном буфере), после чего будем всякий раз формировать новый кадр изображения и выводить его целиком на экран, вызывая Redraw. При вызове Redraw перерисовывается все графическое окно, поэтому скорость анимации ограничена скоростью вывода внеэкранного буфера на экран.
Рисование мышью в графическом окне
Данная программа осуществляет рисование мышью в графическом окне:
uses GraphABC;
procedure MouseDown(x,y,mb: integer);
begin
MoveTo(x,y);
end;
procedure MouseMove(x,y,mb: integer);
begin
if mb=1 then LineTo(x,y);
end;
begin
// Привязка обработчиков к событиям
OnMouseDown := MouseDown;
OnMouseMove := MouseMove
end.
Перемещение окна с помощью клавиатуры
Данная программа осуществляет перемещение графического окна с помощью клавиатуры:
uses GraphABC;
procedure KeyDown(Key: integer);
begin
case Key of
VK_Left: Window.Left := Window.Left - 2;
VK_Right: Window.Left := Window.Left + 2;
VK_Up: Window.Top := Window.Top - 2;
VK_Down: Window.Top := Window.Top + 2;
end;
end;
begin
// Привязка обработчиков к событиям
OnKeyDown := KeyDown;
end.
Пример использования таймера
Данная программа выводит 1 каждые 100 миллисекунд в течение 3 секунд:
uses Timers;
procedure TimerProc;
begin
write(1);
end;
begin
var t := new Timer(100,TimerProc);
t.Start;
Sleep(3000);
end.
Вызов Sleep здесь обязателен, иначе программа после создания таймера сразу закончится, и обработчик таймера ни разу не сработает.