Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 160 161 162 163 164 165 166 167 168 ... 337
кнопку 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);

  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. Поскольку на самом деле мы не используем это имя, это кажется разумным, но компилятор решит, что, поскольку вы не используете окно, его можно сразу удалить. Ой! Это окно существовало всего несколько миллисекунд. Ничего удивительно, что мы его не заметили.

 

 Другая распространенная проблема заключается в том, что окно располагается точно поверх другого окна. Это выглядит так, будто на экране открыто только одно окно. А куда делось другое? Мы можем долго искать несуществующие ошибки в своей программе. Та же самая проблема может возникнуть, если вы размещаете одну фигуру поверх другой.

 

 И в заключение (чтобы еще больше огорчить читателей) отметим, что при работе с библиотеками графического пользовательского интерфейса исключения не всегда срабатывают так, как мы от них ожидаем. Поскольку наша программа управляется библиотекой графического пользовательского интерфейса, сгенерированное исключение может никогда не попасть к своему обработчику — библиотека или операционная система может “съесть” его (т.е. использовать механизмы обработки ошибок, отличающиеся от исключения языка С++).

 

 К типичным проблемам, выявляемым при отладке, относится и отсутствие изображений объектов Shape и Widget из-за отсутствия связи с окном или неправильного поведения объекта. Однако их описание выходит за рамки нашей книги. Посмотрите, как программист может создать и связать кнопку с меню, породив проблемы.

// вспомогательная функция для загрузки кнопки в меню

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);

  // ...

}

1 ... 160 161 162 163 164 165 166 167 168 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий