На этом шаге мы рассмотрим рисование с помощью мыши в окне Sweep.
Теперь попробуем рисовать в окне. Всякий раз, когда нажата кнопка мыши, программа регистрирует координаты точек, через которые проходит мышь (захватывая события e_MouseMove в течение промежутка времени от нажатия до освобождения кнопки мыши), и рисует линию от каждой точки до других точек. Мы хотим получить примерно такое окно (рис. 1):
Рис.1. Внешний вид окна Sweep
Сначала мы создадим предикаты, которые могут нарисовать линии из любой точки в списке к каждой из других точек в списке. Напечатайте следующие предложенияв верхней части модуля Sweep.pro, они должны быть помещены прямо под операторами include.
/**************************************
Рисование линий sweep
**************************************/
predicates
connect(window,pntlist)
drawlines(window,pnt,pntlist)
clauses
connect(_,[]):-!.
connect(Win,[From | Rest]):-
drawlines(Win,From,Rest),
connect(Win,Rest).
drawlines(_,_,[]):-!.
drawlines(Win,pnt(X,Y),[pnt(ToX,ToY) |Rest]):-
draw_Line(Win,pnt(X,Y),pnt(ToX,ToY)),
drawlines(Win,pnt(X,Y),Rest).
На следующем шаге рассмотрим логику обработки событий. Нам необходим факт базы данных для сохранения позиций мыши; мы будем называть этот факт point (точка). Так как события e_MouseMove возникают независимо от изменений состояния кнопки мыши (событие e_MouseMove возникает как результат перемещений мыши), нам нужно зарегистрировать то, что кнопка мыши была нажата. Ну и, наконец, мы хотим, чтобы было более одного окна со своим локальным рисунком. Будем сохранять дескриптор окна - значение, которое гарантируется уникальным для каждого окна, вместе с другими необходимыми данными, в фактах.
Напечатайте эти строки в верхней части программы Sweep.pro после конструкции include:
/***************************************************
Факты для окна sweep
***************************************************/
facts-apl
nocopy point(WINDOW,PNT)
mouse_isdown(WINDOW)
Теперь рассмотрим сущность функционирования. Какие события нужно фиксировать и как мы должны реагировать на них? Мы будем обрабатывать следующие четыре события, для которых (при помощи эксперта окон и диалоговых окон) должен быть добавлен код по умолчанию (к модулю Sweep.pro).
Когда кнопка мыши нажата, мы сначала удалим любые факты, которые уже могут быть занесены в базу фактов для окна. Затем занесем факт, указывающий на то, что кнопка мыши сейчас нажата (в окне), и в конце сделаем вызов предиката win_Invalidate, чтобы, если окно уже содержит рисунок, оно очистилось.
Выберите тип компонента Window в окне проекта. Выделите окно Sweep. Используйте комбинацию клавиш <Ctrl>+<W> для активизации эксперта окон и диалоговых окон. В списке Event Type выберите строку Mouse, а в списке Event or Item - событие e_MouseDown. Нажмите кнопку Add Clause, чтобы добавить код по умолчанию для предложения обработчика событий, обрабатывающего событие e_MouseDown. После того как текст Add Clause на кнопке преобразуется в Edit Clause, нажмите кнопку снова. Вы окажетесь в редакторе (для файла Sweep.pro) на соответствующем предложении. Напечатайте 4 строки, показанные далее:
win_sweep_eh(Win,e_MouseDown(_PNT,_ShiftCtlAlt,Button),0):-!, retractall(mouse_isdown(_Win)), %1 Эти 4 линии retractall(point(_Win,_)), %2 следует assert(mouse_isdown(_Win)), %3 вставлять win_Invalidate(_Win), %4 вручную !.
На событие перемещения мыши, если мышь нажата, мы будем запоминать позицию мыши. Чтобы показать, где двигалась мышь, мы изменим также цвет пиксела. Вставьте этот код, как было описано для события e_MouseDown:
win_sweep_eh(_Win, e_MouseMove(_PNT;_ShiftCtlAlt,_Button),0):-!, mouse_isdown(_Win), assert(point(_Win,_PNT)), draw_Pixel(_Win,_PNT,color_Black), !.
На событие e_MouseUp мы сначала удалим флаг, указывающий на то, что кнопка мыши нажата, и затем вызовем предикат win_Invalidate, так что в окне может быть изображен заново созданный рисунок.
win_sweep_eh(_Win,e_MouseUp(_PNT,_ShiftCtlAlt,_Button),0):-!, retractall(mouse_isdown(_Win)), win_Invalidate(_Win), !.
Событие обновления e_Update содержит код, который очищает окно, перед тем как собрать все точки в списке и соединить их друг с другом.
Напечатайте код следующего предиката в начале программы Sweep.pro (после кода предиката drawlines):
/*******************************************
Рисование окна sweep
*******************************************/
predicates
sweep_Draw(window Win,window AssertWin)
clauses
sweep_Draw(_Win,AssertWin):-
win_Clear(_Win,color_White),
findall(X,point(AssertWin,X),List),
connect(_Win,List).
Затем добавьте следующее предложение в предикат обработчика окна Sweep. Обратите внимание, что в эксперте окон и диалоговых окон вам следует выбрать строку Window в списке Event Type и строку e_Update в списке Event or Item:
win_sweep_eh(_Win,e_Update(_Rct),0):-!, sweep_Draw(_Win,_Win), !.
На следующем шаге мы рассмотрим управление панелью инструментов.