Линия изображается как объект класса Open_polyline
. Кнопки и поля ввода-вывода объявляются как объекты классов Button
, In_box
и Out_box
, и для каждой кнопки в них предусмотрены функции-члены, реализующие желательное действие вместе с шаблонным обратным вызовом функции.
Конструктор класса Lines_window
инициализирует все его члены.
Lines_window::Lines_window(Point xy,int w,int h,const string& title)
:Window(xy,w,h,title),
next_button(Point(x_max()–150,0),70,20,"Next point",cb_next),
quit_button(Point(x_max()–70,0),70,20,"Quit",cb_quit),
next_x(Point(x_max()–310,0),50,20,"next x: "),
next_y(Point(x_max()–210,0),50,20,"next y: "),
xy_out(Point(100,0),100,20,"current (x,y): ")
{
attach(next_button);
attach(quit_button);
attach(next_x);
attach(next_y);
attach(xy_out);
attach(lines);
}
Иначе говоря, каждый элемент управления окном сначала создается, а потом связывается с окном.
Обработка кнопки Quit тривиальна.
void Lines_window::cb_quit(Address, Address pw) // "как обычно"
{
reference_to
}
void Lines_window::quit()
{
hide(); // любопытная идиома библиотеки FLTK для удаления окна
}
Все как обычно: функция обратного вызова (в данном случае cb_quit()
) передается функции (в данном случае quit()
), выполняющей реальную работу (удаляющей объект класса Window
). Для этого используется любопытная идиома библиотеки FLTK, которая просто скрывает окно.
Вся реальная работа выполняется кнопкой Next point. Ее функция обратного вызова устроена как обычно.
void Lines_window::cb_next(Address, Address pw) // " как обычно "
{
reference_to
}
Функция next()
определяет действие, которое действительно выполняется после щелчка на кнопке Next point: она считывает пару координат, обновляет объект Open_polyline
и позицию считывания, а также перерисовывает окно.
void Lines_window::next()
{
int x = next_x.get_int();
int y = next_y.get_int();
lines.add(Point(x,y));
// обновляем текущую позицию считывания:
ostringstream ss;
ss << '(' << x << ',' << y << ')';
xy_out.put(ss.str());
redraw();
}
Все это совершенно очевидно. Функция get_int()
позволяет получить целочисленные координаты из объектов класса In_box
; поток ostringstream
форматирует строки для вывода в объект класса Out_box
; функция-член str()
позволяет вставить строку в поток ostringstream
. Финальная функция, redraw()
, необходима для представления результатов пользователю; старое изображение остается на экране, пока не будет вызвана функция redraw()
из класса Window
.
А что нового в этой программе? Посмотрим на ее функцию main()
.
#include "GUI.h"
int main()
try {
Lines_window win(Point(100,100),600,400,"lines");
return gui_main();
}
catch(exception& e) {
cerr << "Исключение: " << e.what() << '\n';
return 1;
}
catch (...) {
cerr << "Какое-то исключение\n";
return 2;
}
Так ведь здесь, по существу, ничего нет! Тело функции main()
содержит лишь определение нашего окна win
и вызов функции gui_main()
. Ни других функций, ни операторов if
или switch
, ни цикла — ничего из того, чтобы изучали в главах 6–7, — только определение переменной и вызов функции gui_main()
, которая сама вызывает функцию run()
из библиотеки FLTK. Изучая программу далее, увидим, что функция run()
— это просто бесконечный цикл.
while(wait());
За исключением некоторых деталей реализации, описание которых вынесено в приложение Д, мы просмотрели весь код, запускающий программу рисования линий. Мы увидели всю логику этой программы. Что же произошло?
16.6. Инверсия управления