// вспомогательная функция для загрузки кнопки в меню
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);
// ...
}
Этот код не работает. Все кнопки являются локальными объектами в функции
load_disaster_menu
, и их связывание с меню не изменяет состояние самого меню. Объяснение этого факта приведено в разделе 18.5.4, а размещение локальных переменных в памяти было проиллюстрировано в разделе 8.5.8. Дело в том, что после возврата управления из функции
load_disaster_menu()
эти локальные объекты были уничтожены, и меню disasters ссылается на несуществующие (уничтоженные) объекты. Результат неожиданный и неприятный. Устранить эту ошибку можно, используя неименованные объекты, созданные оператором new, а не именованные локальные объекты.
// вспомогательная функция для загрузки кнопки в меню
void load_disaster_menu(Menu& m)
{
Point orig(0,0);
m.attach(new Button(orig,0,0,"flood",cb_flood));
m.attach(new Button(orig,0,0,"fire",cb_fire));
// ...
}
Правильное решение даже проще, чем ошибочный код (впрочем, очень широко распространенный).
Задание
1. Создайте совершенно новый проект, связав его с библиотекой FLTK1. (Установки редактора связей описаны в приложении Г.)
2. Используя средства, описанные в файле
Graph_lib
, выведите какой-нибудь текст в программе из раздела 16.5 и выполните ее.
3. Модифицируйте программу так, чтобы она использовала всплывающее меню, как описано в разделе 16.7, и выполните ее.
4. Измените программу так, чтобы в ней было второе меню для выбора стиля линий, и выполните ее.
Контрольные вопросы
1. Зачем нужен графический пользовательский интерфейс?
2. Когда нужен текстовый интерфейс?
3. Что такое уровень программного обеспечения?
4. Зачем нужны уровни программного обеспечения?
5. В чем заключается фундаментальная проблема взаимодействия с операционной системой с помощью языка C++?
6. Что такое обратный вызов?
7. Что такое виджет?
8. Как еще называют виджет?
9. Что означает аббревиатура FLTK?
10. Как читается аббревиатура FLTK?
11. О каких еще инструментах графического пользовательского интерфейса вы знаете?
12. Какие системы используют термин виджет, а какие — элемент управления окном?
13. Приведите примеры виджетов.
14. Когда используются окна редактирования для ввода?
15. Какие типы данных могут храниться в окнах редактирования для ввода?
16. Когда используется кнопка?
17. Когда используется меню?
18. Что такое инверсия управления?
19. Опишите основную стратегию отладки программ с графическим пользовательским интерфейсом.
20. Почему отладка программ с графическим пользовательским интерфейсом труднее, чем отладка обычной программы с потоками ввода-вывода?
Термины
Упражнения
1. Создайте класс
My_window
, похожий на класс
Simple_window
, за исключением того, что он имеет две кнопки:
Next и
Quit.
2. Создайте окно (на основе класса
My_window
) с шахматной доской 4×4. После щелчка на кнопке должно выполняться простое действие, например вывод ее координат в окно редактирования или изменение цвета (пока не будет выполнен другой щелчок на другой кнопке).
3. Разместите объект класса
Image
поверх объекта класса
Button
; после щелчка на кнопке переместите оба объекта. Для выбора нового местоположения кнопки с изображением используйте следующий генератор случайных чисел:
int rint(int low, int high)
{ return low+rand()%(high–low); }
Эта функция возвращает случайное целое число в диапазоне
[low, high]
.
4. Создайте меню с пунктами “окружность”, “квадрат”, “равносторонний треугольник” и “шестиугольник”. Создайте окно редактирования (или два окна) для ввода пар координат и разместите фигуру, созданную после щелчка на соответствующей кнопке, в заданной точке. Не применяйте метод “перетащить и отпустить”.
5. Напишите программу, рисующую фигуру по вашему выбору и перемещающую ее в новую точку после щелчка на кнопке Next. Новая точка должна выбираться на основе пары координат, считанной из потока ввода.
6. Создайте “аналоговые часы”, т.е. часы с двигающимися стрелками. Определите время, используя средства операционной системы. Основная часть этого упражнения: найти функции, определяющие время дня и прекращающие выполнение программы на короткий период времени (например, на секунду), а также научиться использовать их по документации. Подсказка:
clock()
,
sleep()
.
7. Использование приемов из предыдущего упражнения позволяет создать иллюзию полета самолета по экрану. Создайте кнопки Start и Stop.
8. Создайте конвертер валют. Считайте курсы валют из файла в момент запуска программы. Введите сумму в окне ввода и предусмотрите возможность выбора валют для конверсии (например, пару меню).
9. Модифицируйте калькулятор из главы 7 так, чтобы выражение вводилось в окне редактирование, а результат возвращался в окне вывода.
10. Разработайте программу, в которой можно выбрать одну из нескольких функций (например,
sin()
и
log()
), введите параметры этих функций и постройте ее график.
Послесловие
Графический пользовательский интерфейс — неисчерпаемая тема. Большая часть этой темы касается стиля и совместимости с существующими системами. Более того, много сложностей возникает при работе с чрезвычайно разнообразными элементами управления окном (например, библиотека графического пользовательского интерфейса предлагает многие десятки альтернативных стилей кнопок), — раздолье для “ботаников”. Однако лишь немногие вопросы из этой области относятся к фундаментальным методам программирования, поэтому мы не будем углубляться в этом направлении. Другие темы, такие как масштабирование, вращение, анимация, трехмерные объекты и так далее, требуют изложения сложных фактов, связанных с графикой и/или математикой, которые мы затрагивать здесь не хотим.