Шрифт:
Интервал:
Закладка:

Обратите внимание на то, что кнопка 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);
static void cb_next(Address, Address);
static void cb_quit(Address, Address);
};

Lines_window::Lines_window(Point xy,int w,int h,
const string&title)
:Window(xy,w,h,title),
next_button(Point(x_max()–150,0),70,20,
"Next point", cb_next),
quit_button(Point(x_max()–70,0),70,20,"Quit",cb_quit),
next_x(Point(x_max()–310,0),50,20,"next x:"),
next_y(Point(x_max()–210,0),50,20,"next y:"),
xy_out(Point(100,0),100,20,"current (x,y):")
color_menu(Point(x_max()–70,30),70,20,Menu::vertical,"color"),
menu_button(Point(x_max()–80,30),80,20,
"color menu",cb_menu),
{
attach(next_button);
attach(quit_button);
attach(next_x);
attach(next_y);
attach(xy_out);
xy_out.put("нет точек");
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);
color_menu.hide();
attach(menu_button);
attach(lines);
}
Обратите внимание на то, что инициализация выполняется в порядке определения данных-членов. Это правильный порядок инициализации. Фактически инициализация членов всегда происходит в порядке их объявления. Некоторые компиляторы выдают предупреждения, если конструктор базового класса или члена нарушает этот порядок.
16.8. Отладка программы графического пользовательского интерфейса
После того как программа графического пользовательского интерфейса начнет работать, ее отладка будет довольно простой: что видите, то и получите. Однако иногда возникает трудный фрустрационный период перед появлением первой фигуры или элемента управления окном и даже перед появлением самого окна на экране. Протестируем функцию main().
int main()
{
Lines_window (Point(100,100),600,400,"lines");
return gui_main();
}

• Тщательно исследовать части программы (классы, функции, библиотеки).
• Упростить все добавления, понемногу увеличивая объем программы, начиная с простейшей версии и тщательно отслеживая строку за строкой.
• Проверить все установки редактора связей.
• Сравнить ее с уже работающей программой.
• Объяснить код другу.

Итак, в чем же проблема? Вот правильная версия (см. раздел 16.5).
int main()
{
Lines_window win(Point(100,100),600,400,"lines");
return gui_main();
}
Мы забыли указать имя win объекта класса Lines_window. Поскольку на самом деле мы не используем это имя, это кажется разумным, но компилятор решит, что, поскольку вы не используете окно, его можно сразу удалить. Ой! Это окно существовало всего несколько миллисекунд. Ничего удивительно, что мы его не заметили.



// вспомогательная функция для загрузки кнопки в меню
void load_disaster_menu(Menu& m)
{
Point orig(0,0);
Button b1(orig,0,0,"flood",cb_flood);
Button b2(orig,0,0,"fire",cb_fire);
// ...
m.attach(b1);
m.attach(b2);
// ...
}
int main()
{
// ...
Menu disasters(Point(100,100),60,20,Menu::horizontal,"disasters");
load_disaster_menu(disasters);
win.attach(disasters);
// ...
}