Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

void Lines_window::next

{

int x = next_x.get_int;

int y = next_y.get_int;

lines.add(Point(x,y));

// обновляем текущую позицию считывания:

ostringstream ss;

ss << '(' << x << ',' << y << ')';

xy_out.put(ss.str);

redraw;

}

Все это совершенно очевидно. Функция

get_int
позволяет получить целочисленные координаты из объектов класса
In_box
; поток
ostringstream
форматирует строки для вывода в объект класса
Out_box
; функция-член
str
позволяет вставить строку в поток
ostringstream
. Финальная функция,
redraw
, необходима для представления результатов пользователю; старое изображение остается на экране, пока не будет вызвана функция
redraw
из класса
Window
.

А что нового в этой программе? Посмотрим на ее функцию

main
.

#include "GUI.h"

int main

try {

Lines_window win(Point(100,100),600,400,"lines");

return gui_main;

}

catch(exception& e) {

cerr << "Исключение: " << e.what << '\n';

return 1;

}

catch (...) {

cerr << "Какое-то исключение\n";

return 2;

}

Так ведь здесь, по существу, ничего нет! Тело функции

main
содержит лишь определение нашего окна
win
и вызов функции
gui_main
. Ни других функций, ни операторов
if
или
switch
, ни цикла — ничего из того, чтобы изучали в главах 6–7, — только определение переменной и вызов функции
gui_main
, которая сама вызывает функцию
run
из библиотеки FLTK. Изучая программу далее, увидим, что функция
run
— это просто бесконечный цикл.

while(wait);

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

16.6. Инверсия управления

А произошло вот что: мы передали поток управления от самой программы элементам управления окном: теперь программа возобновляет свою работу каждый раз, когда активизируется какой-нибудь из этих элементов. Например, щелкните на кнопке, и программа начнет работать. После возврата обратного вызова программа “отключается”, ожидая, пока пользователь сделает что-нибудь еще. По существу, функция

wait
просит систему опросить элементы управления окном и активизировать соответствующие обратные вызовы. Теоретически функция
wait
могла бы сообщать, какой элемент управления требует внимания, и предоставить самому программисту вызывать соответствующую функцию. Однако в библиотеке FLTK и в большинстве других систем графического пользовательского интерфейса функция
wait
активизирует соответствующий обратный вызов, освобождая программиста от необходимости писать код для выбора этой функции.

Обычная программа организована следующим образом:

Программа графического пользовательского интерфейса организована иначе.

Одна из сложностей такой инверсии управления проявляется в том, что порядок выполнения программы теперь полностью определяется действиями пользователя. Это усложняет как организацию, так и отладку программы. Трудно себе представить, что сделает пользователь, но еще труднее представить себе возможные результаты случайной последовательности обратных вызовов. Это превращает систематическое тестирование в ночной кошмар (подробнее об этом — в главе 26). Методы решения этой проблемы выходят за рамки рассмотрения нашей книги, но мы просим читателей быть особенно осторожными, работая с кодом, управляемым пользователями с помощью обратных вызовов. Кроме очевидных проблем с потоком управления, существуют проблемы, связанные с видимостью и отслеживанием связей между элементами управления окном и данными. Для того чтобы минимизировать трудности, очень важно не усложнять часть программы, отвечающую за графический пользовательский интерфейс, и создавать ее постепенно, тестируя каждую часть. Работая с программой графического пользовательского интерфейса, почти всегда необходимо рисовать небольшие диаграммы объектов и взаимодействия между ними.

Как взаимодействуют части программы, активизированные разными обратными вызовами? Проще всего, чтобы функции оперировали данными, хранящимися в окне, как показано в примере из раздела 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);

  • Читать дальше
  • 1
  • ...
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: