Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
Итак, когда кто-то щелкает на кнопке 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, объектно-ориентированное программирование позволяет объектам класса Window взаимодействовать с любыми разновидностями класса Widget. Аналогично, классу Widget не известно, с какой разновидностью класса Window он имеет дело.
Мы проявили небольшую неаккуратность, оставив открытыми данные-члены. Члены own и pw предназначены исключительно для реализации производных классов, поэтому мы объявили из в разделе protected.
Определения класса Widget и его конкретных разновидностей (Button, Menu и т.д.) содержатся в файле GUI.h.
16.4.2. Класс Button
Класс Button — это простейший класс Widget, с которым нам придется работать. Все, что он делает, — всего лишь обратный вызов после щелчка на кнопке.
class Button:public Widget {
public:
Button(Point xy,int ww,int hh,const string& s,Callback cb)
:Widget(xy,ww,hh,s,cb) { }
void attach(Window& win);
};
Только и всего. Весь (относительно сложный) код библиотеки FLTK содержится в функции attach(). Мы отложили ее объяснение до приложения Д (пожалуйста, не читайте его, не усвоив главы 17 и 18). А пока заметим, что определение простого подкласса Widget не представляет особого труда.
Мы не касаемся довольно сложного и запутанного вопроса, связанного с внешним видом кнопки (и других элементов управления окном) на экране. Проблема заключается в том, что выбор внешнего вида элементов управления окном практически бесконечен, причем некоторые стили диктуются конкретными операционными системами. Кроме того, с точки зрения технологии программирования в описании внешнего вида кнопок нет ничего нового. Если вы расстроились, то обратите внимание на то, что размещение фигуры поверх кнопки не влияет на ее функционирование, а как нарисовать фигуру, вам уже известно.
16.4.3. Классы In_box и Out_box
Для ввода и вывода текста в программе предусмотрены два класса, производных от класса Widget.
struct In_box:Widget {
In_box(Point xy,int w,int h,const string& s)
:Widget(xy,w,h,s,0) { }
int get_int();
string get_string();
void attach(Window& win);
};
struct Out_box:Widget {
Out_box(Point xy, int w, int h, const