Литмир - Электронная Библиотека
A
A

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Здесь ключевое слово
static
гарантирует, что функция
cb_next()
может быть вызвана как обычная функция, т.е. не как функция-член, вызываемая через конкретный объект. Если бы функцию-член могла вызывать сама операционная система, было бы намного лучше. Однако интерфейс обратного вызова нужен для программ, написанных на многих языках, поэтому мы используем статическую функцию-член. Аргументы
Address
указывают на то, что функция
cb_next()
получает аргументы, имеющие адреса “где-то в памяти”. Ссылки, существующие в языке C++, во многих языках неизвестны, поэтому мы не можем их использовать. Компилятор не знает, какие типы имеют эти аргументы, расположенные “где-то”. Здесь мы снижаемся на уровень аппаратного обеспечения и не можем использовать обычные средства языка. Система вызовет функцию обратного вызова, первый аргумент которой должен представлять собой адрес некоторого элемента графического пользовательского интерфейса (объекта класса
Widget
), для которого был сделан обратный вызов. Мы не хотим использовать этот первый аргумент, поэтому его имя нам не нужно. Второй аргумент — это адрес окна, содержащего данный объект класса
Widget
; для функции
cb_next()
аргументом является объект класса
Simple_window
.

Эту информацию можно использовать следующим образом:

void Simple_window::cb_next(Address,Address pw)

// вызов Simple_window::next() для окна, расположенного по адресу pw

{

  reference_to<Simple_window>(pw).next();

}

Вызов функции

reference_to<Simple_window>(pw)
сообщает компьютеру, что адрес, хранящийся в переменной
pw
, должен интерпретироваться как адрес объекта класса
Simple_window
; иначе говоря, мы можем использовать значение
reference_to<Simple_window>(pw)
как ссылку на объект класса
Simple_window
. В главах 17-18 мы еще вернемся к вопросам адресации памяти. Определение функции
reference_to
(кстати, совершенно тривиальное) мы покажем в разделе Д.1. А пока просто рады наконец получить ссылку на наш объект класса
Simple_window
и непосредственный доступ к нашим данным и функциям, которые собирались использовать. Теперь поскорее выходим из этого системно-зависимого кода, вызывая нашу функцию-член
next()
.

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Мы могли бы привести весь код, который следовало бы выполнить в функции
cb_next()
, но мы, как и большинство хороших программистов, разрабатывающих графические пользовательские интерфейсы, предпочитаем отделять запутанный низкоуровневый код от нашего превосходного пользовательского кода, поэтому решили обрабатывать обратный вызов с помощью двух функций.

• Функция

cb_next()
превращает системные соглашения об обратных вызовах в вызов обычной функции-члена next().

• Функция

next()
делает то, что мы хотели (ничего не зная о запутанном механизме обратного вызова).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Мы используем здесь две функции, руководствуясь общим принципом, гласящим: каждая функция должна выполнять отдельное логическое действие, т.е. функция
cb_next()
скрывает низкоуровневую системно-зависимую часть программы, а функция
next()
выполняет требуемое действие. В ситуациях, когда необходим обратный вызов (из системы) в одном из окон, мы всегда определяем пару таких функций; например, см. разделы 16.5–16.7. Перед тем как идти дальше, повторим сказанное.

• Мы определяем наш объект класса Simple_window.

• Конструктор класса

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

• Когда пользователь щелкает на изображении объекта

next_button
на экране, графический пользовательский интерфейс вызывает функцию
cb_next()
.

• Функция

cb_next()
преобразует низкоуровневую информацию системы в вызов нашей функции-члена next() для нашего окна.

• После щелчка на кнопке функция

next()
выполняет требуемое действие.

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

• Как правило, на компьютере одновременно выполняется много программ.

• Программа создается намного позже операционной системы.

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

• Программа может быть написана на языке, отличающемся от того, который используется в операционной системе.

• Описанный метод охватывает все виды взаимодействий (а не только щелчок на кнопке).

• Окно может иметь много кнопок, а программа может иметь много окон.

Однако, поняв, как вызывается функция

next()
, мы фактически поймем, как обрабатывается каждое действие в программе, имеющей графический пользовательский интерфейс. 

16.3.2. Цикл ожидания

 

Программирование. Принципы и практика использования C++ Исправленное издание - _002.png
 Итак, что должна делать функция
next()
класса
Simple_window
после каждого щелчка на кнопке в данном (простейшем) случае? В принципе мы хотели бы, чтобы эта операция останавливала выполнение нашей программы в некоторой точке, давая возможность увидеть, что было сделано к этому моменту. Кроме того, мы хотим, чтобы функция
next()
возобновляла работу нашей программы после паузы.

// создаем и/или манипулируем некоторыми объектами, изображаем

// их в окне

win.wait_for_button(); // работа программы возобновляется с этой

 // точки

// создаем и/или манипулируем некоторыми объектами

На самом деле это просто. Сначала определим функцию

wait_for_button()
.

void Simple_window::wait_for_button()

  // модифицированный цикл событий:

  // обрабатываем все события (по умолчанию),

212
{"b":"847443","o":1}