после каждого щелчка на кнопке в данном (простейшем) случае? В принципе мы хотели бы, чтобы эта операция останавливала выполнение нашей программы в некоторой точке, давая возможность увидеть, что было сделано к этому моменту. Кроме того, мы хотим, чтобы функция
next
возобновляла работу нашей программы после паузы.
// создаем и/или манипулируем некоторыми объектами, изображаем
// их в окне
win.wait_for_button; // работа программы возобновляется
с этой
// точки
// создаем и/или манипулируем некоторыми объектами
На самом деле это просто. Сначала определим функцию
wait_for_button
.
void Simple_window::wait_for_button
// модифицированный цикл событий:
// обрабатываем все события (по умолчанию),
// выходим из цикла, когда переменная button_pushed становится
// true
// это позволяет рисовать без изменения направления потока
// управления
{
while (!button_pushed) Fl::wait;
button_pushed = false;
Fl::redraw;
}
Как и большинство систем графического интерфейса, библиотека FLTK содержит функцию, приостанавливающую работу программы, пока не произойдет какое-то событие. Версия этой функции в библиотеке FLTK называется
wait
. На самом деле функция
wait
делает много полезных действий, чтобы наша программа могла правильно возобновить работу, когда произойдет ожидаемое событие. Например, при работе под управлением системы Microsoft Windows программа должна перерисовать окно, которое было перемещено или ранее перекрыто другим окном. Кроме того, объект класса
Window
должен самостоятельно реагировать на изменение размеров окна. Функция
Fl::wait
выполняет все эти задания так, как это предусмотрено по умолчанию. Каждый раз, когда функция
wait
обрабатывает какое-то событие, она возвращает управление, чтобы наша программа могла выполнить какие-то действия.
Итак, когда кто-то щелкает на кнопке Next, функция
wait
вызывает функцию
cb_next
и возвращает управление (нашему циклу ожидания). Для того чтобы сделать это в функции
wait_for_button
, функция
next
должна просто присвоить булевой переменной
button_pushed
значение
true
. Это просто.
void Simple_window::next
{
button_pushed = true;
}
Разумеется, мы также должны где-то определить переменную
button_pushed
.
bool button_pushed; // Инициализируется в конструкторе
// значением false
После определенного периода ожидания функция
wait_for_button
должна восстановить прежнее значение переменной
button_pushed
и вызвать функцию
redraw
, чтобы все внесенные изменения были видны на экране. Именно это мы и сделали.
16.4. Класс Button и другие разновидности класса Widget
Определим класс, описывающий кнопку.
struct Button:Widget {
Button(Point xy, int w, int h, const string& label, Callback cb);
void attach(Window&);
};
Класс
Button
является производным от класса
Widget
с координатами
xy
,
размерами
w
и
h
, текстовой меткой
label
и обратным вызовом
cb
. В принципе все, что появляется на экране в результате какого-то действия (например, обратный вызов), является объектом класса
Widget
.
16.4.1. Класс Widget
Виджет (widget) — это технический термин. У него есть более информативный, но менее эффектный синоним — элемент управления окном (control). Такой элемент используется для определения форм взаимодействия с программой через графический пользовательский интерфейс. Определение класса
Widget
приведено ниже.
class Widget {
// Класс Widget — это дескриптор класса Fl_widget,
// он не является классом Fl_widget;
// мы стараемся, чтобы наши интерфейсные классы отличались
// от FLTK
public:
Widget(Point xy, int w, int h, const string& s, Callback cb);
virtual void move(int dx,int dy);
virtual void hide;
virtual void show;
virtual void attach(Window&) = 0;
Point loc;
int width;
int height;
string label;
Callback do_it;
protected:
Window* own; // каждый объект класса Widget принадлежит
Window
Fl_Widget* pw; // связь с классом Widget из библиотеки FLTK
};
Класс
Widget
имеет две интересные функции, которые можно применить в классе
Button
(а также в любом другом классе, производном от класса
Widget
, например
Menu
; см. раздел 16.7).
• Функция
hide
делает объект класса
Widget
невидимым.
• Функция
show
делает объект класса
Widget
снова видимым.
Изначально объект класса
Widget
является видимым.
Как и в классе
Shape
, мы можем с помощью функции
move
перемещать объект класса
Widget
в окне и должны связать этот объект с окном, вызвав функцию
attach
перед тем, как использовать. Обратите внимание на то, что мы объявили функцию
attach
чисто виртуальной (см. раздел 16.3.5): каждый класс, производный от класса
Widget
, должен самостоятельно определить, что означает его связывание с объектом класса
Window
. Фактически системные элементы управления окном создаются в функции
attach
. Функция
attach
вызывается из объекта класса
Window
как часть реализации его собственной функции
attach
. В принципе связывание окна и элемента управления окном — это очень тонкое дело, в котором каждая из сторон выполняет свое задание. В результате окно знает о существовании своих элементов управления, а каждый элемент управления знает о своем окне.
Обратите внимание на то, что объект класса
Window
не знает о том, какая разновидность класса
Widget
с ним взаимодействует. Как описано в разделах 16.4 и 16.5, объектно-ориентированное программирование позволяет объектам класса