Обратите внимание на то, что объект класса
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 string& s)
:Widget(xy,w,h,s,0) { }
void put(int);
void put(const string&);
void attach(Window& win);
};
Объект класса
In_box
может принимать текст, набранный в нем, и мы можем прочитать этот текст в виде строки с помощью функции
get_string()
или как целое число с помощью функции
get_int()
. Если хотите убедиться, что текст был введен, то можете прочитать его с помощью функции
get_string()
и проверить, не пустая ли эта строка.
string s = some_inbox.get_string();
if (s =="") {
// текст не введен
}
Объект класса
Out_box
используется для выдачи сообщений, адресованных пользователю. По аналогии с классом
In_box
, мы можем с помощью функции
put()
ввести либо целые числа, либо строки. Примеры использования классов
In_box
and
Out_box
приведены в разделе 16.5.
Мы могли бы предусмотреть функции
get_floating_point()
,
get_complex()
и так далее, но не сделали этого, так как вы можете взять строку, поместить ее в поток
stringstream
и форматировать ввод, как захотите (см. раздел 11.4).
16.4.4. Класс Menu
Определяем очень простое меню.
struct Menu:Widget {
enum Kind { horizontal, vertical };
Menu(Point xy, int w, int h, Kind kk, const string& label);
Vector_ref<Button> selection;
Kind k;
int offset;
int attach(Button& b); // связывает кнопку с меню
int attach(Button* p); // добавляет новую кнопку в меню
void show() // показывает все кнопки
{
for (int i = 0; i<selection.size(); ++i)
selection[i].show();
}
void hide(); // hide all buttons
void move(int dx, int dy); // перемещает все кнопки
void attach(Window& win); // связывает все кнопки с объектом win