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")
{
// ...как и прежде...
color_menu.attach(new Button(Point(0,0),0,0,"red",cb_red));
color_menu.attach(new Button(Point(0,0),0,0,"blue",cb_blue));
color_menu.attach(new Button(Point(0,0),0,0,"black",cb_black));
attach(color_menu);
}
Кнопки динамически связываются с меню (с помощью функции
attach()
) и при необходимости могут быть удалены и/или изменены. Функция
Menu::attach()
настраивает размер и место кнопки, а также связывает его с окном. Это все. Теперь мы увидим на экране следующее.
Экспериментируя с этой программой, мы решили, что нам необходимо выпадающее меню; т.е. мы не хотим фиксировать конкретное место на экране, в котором оно будет появляться. Итак, мы добавили кнопку Color menu. Когда пользователь щелкнет на ней, всплывет меню цвета, а после того как выбора меню снова исчезнет, и на экране отобразится кнопка.
Посмотрим сначала на окно, в которое добавлено несколько линий.
Мы видим новую кнопку Color menu и несколько черных линий. Щелкнем на кнопке Color menu, и на экране откроется меню.
Обратите внимание на то, что кнопка Color menu исчезла. Она не нужна, пока открыто меню. Щелкнем на кнопке blue и получим следующий результат.
Теперь линии стали синими, а кнопка Color menu вновь появилась на экране.
Для того чтобы достичь такого эффекта, мы добавили кнопку Color menu и модифицировали функцию “pressed”, настроив видимость меню и кнопки. Вот как выглядит класс
Lines_window
после всех этих модификаций.
struct Lines_window:Window {
Lines_window(Point xy, int w, int h, const string& title );
private:
// данные:
Open_polyline lines;
// элементы управления окном:
Button next_button; // добавляет (next_x,next_y) к линиям
Button quit_button; // завершает работу программы
In_box next_x;
In_box next_y;
Out_box xy_out;
Menu color_menu;
Button menu_button;
void change(Color c) { lines.set_color(c); }
void hide_menu() { color_menu.hide(); menu_button.show(); }
// действия, инициирующие обратные вызовы:
void red_pressed() { change(Color::red); hide_menu(); }
void blue_pressed() { change(Color::blue); hide_menu(); }
void black_pressed() { change(Color::black); hide_menu(); }
void menu_pressed() { menu_button.hide(); color_menu.show(); }
void next();
void quit();
// функции обратного вызова:
static void cb_red(Address, Address);
static void cb_blue(Address, Address);
static void cb_black(Address, Address);
static void cb_menu(Address, Address);