А произошло вот что: мы передали поток управления от самой программы элементам управления окном: теперь программа возобновляет свою работу каждый раз, когда активизируется какой-нибудь из этих элементов. Например, щелкните на кнопке, и программа начнет работать. После возврата обратного вызова программа “отключается”, ожидая, пока пользователь сделает что-нибудь еще. По существу, функция wait()
просит систему опросить элементы управления окном и активизировать соответствующие обратные вызовы. Теоретически функция wait()
могла бы сообщать, какой элемент управления требует внимания, и предоставить самому программисту вызывать соответствующую функцию. Однако в библиотеке FLTK и в большинстве других систем графического пользовательского интерфейса функция wait()
активизирует соответствующий обратный вызов, освобождая программиста от необходимости писать код для выбора этой функции.
Обычная программа организована следующим образом:
Программа графического пользовательского интерфейса организована иначе.
Как взаимодействуют части программы, активизированные разными обратными вызовами? Проще всего, чтобы функции оперировали данными, хранящимися в окне, как показано в примере из раздела 16.5. В нем функция next()
класса Lines_window
активизировалась щелчком на кнопке Next point, считывала данные из объектов класса In_box
(next_x
и next_y
), а затем обновляла переменную-член lines
и объект класса Out_box (xy_out)
. Очевидно, что функция, активизированная обратным вызовом, может делать все, что угодно: открывать файлы, связываться с сетью веб и т.д. Однако пока мы рассмотрим простой случай, когда данные хранятся в окне.
16.7. Добавление меню
Исследуем вопросы управления и взаимодействия, поднятые в разделе “Инверсия управления”, на примере создания меню для программы, рисующей линии. Для начала опишем меню, позволяющее пользователю выбирать цвет всех линий в переменной lines
. Добавим меню color_menu
и обратные вызовы.
struct Lines_window:Window {
Lines_window(Point xy,int w,int h,const string& title);
Open_polyline lines;
Menu color_menu;
static void cb_red(Address,Address); // обратный вызов
// для красной кнопки
static void cb_blue(Address,Address); // обратный вызов
// для синей кнопки
static void cb_black(Address,Address); // обратный вызов
// для черной кнопки
// действия:
void red_pressed() { change(Color::red); }
void blue_pressed() { change(Color::blue); }
void black_pressed() { change(Color::black); }
void change(Color c) { lines.set_color(c); }
// ...как и прежде...
};
Создание всех таких практически идентичных функций обратного вызова и функций “действия” — довольно утомительное занятие. Однако оно не вызывает никаких затруднений, а описание более простых средств выходит за рамки нашей книги. После щелчка на кнопке меню цвет линий изменяется на требуемый.
Определив член color_menu
, мы должны его инициализировать.
Lines_window::Lines_window(Point xy,int w,int h,
const string&title):Window(xy,w,h,title),
// ...как и прежде...
color_menu(Point(x_max()–70,40),70,20,Menu::vertical,"color")
{