Шрифт:
Интервал:
Закладка:
// определяем переменные и/или вычисляем значения, вырабатываем
// результаты
cin >> var; // ожидаем ввода
// определяем переменные и/или вычисляем значения, вырабатываем
// результаты
cin >> var; // ожидаем ввода
// определяем переменные и/или вычисляем значения, вырабатываем
// результаты
cin >> var; // ожидаем ввода
С точки зрения реализации эти два вида программы совершенно отличаются друг от друга. Когда программа выполняет инструкцию cin>>var, она останавливается и ждет, пока система не вернет символы, которые ввел пользователь. Однако система графического пользовательского интерфейса, управляющая экраном и отслеживающая вашу работу с мышью, следует другой модели: она определяет, где находится курсор мыши и что пользователь с нею делает (щелкает и т.д.). Если ваша программа ожидает каких-то действий, то она должна делать следующее.
• Указать, за чем должна следить система графического пользовательского интерфейса (например, “Кто-то щелкнул на кнопке Next”).
• Указать, что делать, когда произошло ожидаемое событие.
• Ожидать, пока графический пользовательский интерфейс определит требуемое действие.
Новый интересный аспект заключается в том, что система графического пользовательского интерфейса не просто возвращает управление вашей программе, она разрабатывается так, чтобы по-разному реагировать на разные действия пользователя, такие как щелчок мышью на одной из многих кнопок, изменение размера окна, перерисовка окна после закрытия вложенного окна и открытие выпадающих меню.
Мы просто хотим сказать диспетчеру: “Пожалуйста, проснись, когда кто-то щелкнет на кнопке”, иначе говоря, “Пожалуйста, продолжай выполнять мою программу, когда кто-то щелкнет на кнопке в то время, когда курсор будет в прямоугольной области, представляющей собой изображение моей кнопки”. Это простейшее действие, которое можно себе представить. Однако эта операция не предусмотрена системой — ее необходимо написать самому. Как это сделать — первый вопрос, который мы рассмотрим, приступая к изучению программирования графического пользовательского интерфейса.
16.3. Простое окно
В принципе система (т.е. комбинация библиотеки графического пользовательского интерфейса и операционной системы) непрерывно отслеживает положение курсора мыши и состояние ее кнопок. Программа может проявить интерес к определенной области экрана и попросить систему вызвать функцию, когда произойдет что-нибудь интересное. В частности, мы можем попросить систему вызвать одну из наших функций обратного вызова (callback functions), когда пользователь щелкнет на кнопке. Для этого необходимо сделать следующее.
• Определить кнопку.
• Отобразить ее на экране.
• Определить функцию, которую должен вызвать графический пользовательский интерфейс.
• Сообщить графическому пользовательскому интерфейсу о данной кнопке и функции.
• Подождать, когда графический пользовательский интерфейс вызовет нашу функцию.
Давайте сделаем это. Кнопка — это часть объекта класса Window, поэтому (в файле Simple_window.h) мы определим класс Simple_window, содержащий член next_button.
struct Simple_window:Graph_lib::Window {
Simple_window(Point xy,int w,int h,const string& title );
void wait_for_button(); // простой цикл событий
private:
Button next_button; // кнопка Next
bool button_pushed; // деталь реализации
static void cb_next(Address, Address); // обратный вызов
// для кнопки next_button
void next(); // действие, которое следует выполнить,
// когда при щелчке на кнопке next_button
};
Очевидно, что класс Simple_window является производным от класса Window из библиотеки Graph_lib. Все наши окна должны быть объектами класса, явно и неявно выведенными из класса Graph_lib::Window, поскольку именно этот класс (с помощью библиотеки FLTK) связывает наше понятие окна с его реализацией в системе. Детали реализации класса Window описаны в разделе Д.3.
Наша кнопка инициализируется в конструкторе класса Simple_window.
Simple_window::Simple_window(Point xy, int w, int h,const string& title)
:Window(xy,w,h,title),
next_button(Point(x_max()–70,0),70,20,"Next",cb_next),button_pushed(false)
{
attach(next_button);
}
Нет ничего удивительного в том, что класс Simple_window передает положение своего объекта (xy), размер (w,h) и заголовок (title) классу Window из библиотеки Graph_lib для дальнейшей обработки. Далее конструктор инициализирует член next_button координатами (Point(x_max()–70,0); это где-то в области верхнего правого угла), размером (70,20), меткой ("Next") и функцией обратного вызова (cb_next). Первые четыре параметра совпадают с параметрами, которые мы использовали при описании класса Window: мы задаем положение прямоугольника на экране и указываем его метку.
В заключение вызываем функцию attach() и связываем член next_button с классом Simple_window; иначе говоря, сообщаем окну, что оно должно отобразить кнопку в указанном месте и сделать так, чтобы графический пользовательский интерфейс узнал о ней.
Член button_pushed — это довольно запутанная деталь реализации; мы используем его для того, чтобы отслеживать щелчки на кнопке после последнего выполнения функции next(). Фактически здесь все является деталью реализации и, следовательно, должно быть объявлено в разделе private. Игнорируя детали реализации, опишем класс в целом.
struct Simple_window:Graph_lib::Window {
Simple_window(Point xy,int w,int h,const string& title );
void wait_for_button(); // простой цикл событий
// ...
};
Другими словами, пользователь может создать окно и ожидать, пока не произойдет щелчок на кнопке.
16.3.1. Функции обратного вызова


Такое имя выбирается просто для того, чтобы мы помнили о предназначении этой функции, — ни язык, ни библиотека этого не требуют. Очевидно, что мы выбрали имя cb_next потому, что эта функция должна быть вызвана для кнопки Next. Определение функции cb_next выглядит уродливым куском “шаблонов”. Перед демонстрацией ее кода посмотрим, что она делает.
