Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lektsia_5.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
2.02 Mб
Скачать

7. Обработка событий в приложениях класса mfc

Затем рассматривается ввод с помощью мыши. Благодаря библиотеке базовых классов Мисrosoft (МFС - Мисrosoft Faundetion Classes) времена низкоуровневого кода обработки событий мыши остались в далеком прошлом (безусловно, если у разработчика достаточно свободного времени, он может позволить себе и такую ​​роскошь). В данном разделе описываются методы МFС, обеспечивающих контроль и манипулирование мышью, а также рассматриваются такие вопросы, как внешний вид (форма) курсора мыши, захват мыши и ограничения перемещения курсора мыши.

И в заключение рассмотрим способы, позволяющие приложению использовать ввод с клавиатуры. Применяя такие элементы пользовательского интерфейса, как поле ввода, можно предоставить Windows и МFС возможность самостоятельно выполнять все задачи по обработке ввода с клавиатуры. Однако довольно часто бывает необходим более жесткий контроль над событиями клавиатуры. В ходе обсуждения этой темы будут затронуты такие понятия, как фокус ввода с клавиатуры (Keyboard focus ), текстовый курсор (точка ввода) (keyboard kursor (insertion point )), состояние выделения (selection stste) и многие другие элементы конструкции пользовательского интерфейса, связанные с вводом с клавиатуры.

Срок управляемый событиями (event - driven) означает, что при каждом нажатии пользователем клавиши или щелчке мышью вместо кода опроса, соответствующего нажатию клавиш или щелчок мышью, операционная система передает приложению сообщения Windows (WM - windows message).

Библиотека MFC соотносит (map) сообщения Windows с функциями С, называемыми обработчиками сообщений (message handler). Операторы, обрабатывающие данные, вводимые в приложение, расположены именно в этих функциях-обработчиках сообщений.

Сообщения мыши

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

Позиция мыши отображается на экране с помощью указателя, который по умолчанию имеет форму стрелки. Конец стрелки называется активной точкой (hotspot ), поскольку он соответствует реальной точки для стандартной

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

• Щелчок - нажатие и отпускание кнопки мыши

• Двойной щелчок - два последовательных нажатия и отпускания кнопки мыши, пауза между кото ¬ рыми не превышает заданного значения

• Перемещение - Движение мыши без нажатия на кнопки

• Перетаскивание - Движение мыши при нажатой кнопке

Эти операции определяют типы сообщений, которые генерируются Windows при соответствующих событиях, связанных с мышью. Сообщения мыши делятся на два класса: сообщение для рабочей области окна и текст служебной панели. Сообщение для рабочей области окна используются значительно чаще, поэтому им будет уделено первоочередное внимание. В табл. 8.2 приведен список

Сообщение WM_MOUSEMOVE передается в том случае, когда указатель мыши перемещается в рабочей области окна. Сообщение WM_MOUSEACTIVATE передается при щелчок над окном, которое до этого было неактивным, в результате чего окно становится активным. Сообщение WM_MOUSEHOVER и WM_MOUSELEAVE передаются в ответ на трассировку мыши при вызове функции TrackMouseEvent (). Сообщение WM_MOUSEHOVER генерируется в том случае, если в течение заданного периода времени трассировки указатель мыши не выходил за пределы указанной прямоугольной области. Обычно это со ¬ общения служит для вызова контекстных подсказок. Сообщение WM_MOUSELEAVE генерируется в том случае, если в течение заданного периода времени трассировки указатель мыши выходит за пределы рабочей области окна.

Остальные сообщения связанные с вращением колесика прокрутки и щелчками на кнопках мыши. Колесико прокрутки - это сравнительно новое усовершенствование мыши, которое впервые появилось в модели Microsoft Intcllimouse. При вращении колесика прокрутки генерируется сообщение WM_MOUSEWHEEL, содержащий информацию об угле поворота. В большинстве приложений это колесико используется как альтернатива полосах прокрутки. Иными словами, поворот колесика эквивалентен щелчку на стрелке в конце полосы прокрутки.

Сообщение WM_XBUTTONDOWN передаются в результате нажатия кнопки мыши в пределах рабочей области окна, а сообщение WM_XBUTTONUP передаются при отпускании кнопки. Сообщение WMXBUTTONDBLCLK генерируются при двойном нажатии в рабочей области окна. Все эти сообщения существуют в трех вариантах, соответствующих левой, правой и средней кнопок. Во многих типов мыши средняя кнопка отсутствует, поэтому они не могут нарушить соответствующие сообщения.

Ниже представлены объявления процедуры OnMouseMoveQ, r котором указаны параметры, которые используются большинством подпрограмм обработки мыши:

afxmsg void OnMouseMove (UINT nFlags, CPoint point);

Параметр nFlags соответствует нажатию различных виртуальных клавиш. Этот параметр может содержать произвольное сочетание следующих флагов:

• MK_LBUTTON - устанавливается при нажатии левой кнопки мыши

• М КМ В UTTON - устанавливается при нажатии средней кнопки мыши

• MK_RBUTTON - устанавливается при нажатии правой кнопки мыши

• MK_CONTROL - устанавливается при нажатии клавиши Ctrl

• MK_SHIFT - устанавливается при нажатии клавиши Shift

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

Введение с помощью мыши

Как уже говорилось, Windows сообщает окна программ о действиях пользователя, посылая им сообщения, хранящиеся в аппаратной очереди ввода (input queue). Табл. 1 содержит список основных сообщений Windows для мыши, обработчики которых используются для организации реакции на действия пользователя.

Таблица 1 - Сообщение Windows для мыши

Имена сообщений начинаются с префикса WM (Windows Message ), что указывает, что это сообщение Windows.

Использование методов ClassWizard для работы с мышью Создайте проект SDI -приложения с именем mouser. Наделите ее теми же функциями работы с клавиатурой, и предварительную программу carets; иначе говоря, вводимые пользователем символы должны храниться в объекте документа St ringData.

Кроме того, добавьте методы OnKillFocus () и OnSetFocus () и включите в них вызовы HideCaret () и ShowCaret (), как это было сделано в предыдущей программе (можно скопировать необходимые фрагменты кода). Перейдем к отображению данных, вводимые пользователем.

Если пользователь щелкнул мышью в некоторой точке клиентской области, он хочет, чтобы текст выводился в указанном им месте. Мы должны воспользоваться

ClassWizard и добавить метод для обработки сообщения Windows WM_LBUTT0ND0WN;

ClassWizard присваивает ему имя OnLButtonDown ().

Запустите ClassWizard (рис. 4.3).

Проследите, чтобы в списке Class name был избран класс вида CMouserView, и найдите в списке Messages сообщение WM_LBUTT0ND0WN. Дважды щелкните на его имени; при этом создается и выводится в списке Member functions метод OnLButtonDown ().

Дважды щелкните на строке с eFO именем OnLButtonDown (), чтобы перейти к коду:

void CMouserView:: OnLButtonDown (UINT nFlags, CPoint point)

{

/ / TODO: добавьте код обработки сообщения

/ / И / или вызовите обработчик по умолчанию

CView:: 0nl_ButtonDown (nFlags, point);

}

Кроме метода OnLButtonDown (), можно использовать и другие методы для работы с мышью - OnLButtonUp (), отвечающий за обработку отпуск левой кнопки мыши, OnRButtonDownO, соответствующий нажатию правой кнопки мыши, OnLButtonDblClick (), обрабатывающий двойной щелчок левой кнопкой, и т. д.

Методы для работы с мышью перечислены в табл. 2.

Методом OnLButtonDown () передаются два параметра, nFlags и point. Первый содержит информацию о состоянии различных служебных клавиш и может принимать следующие значения:

MK_C0NTR0L нажата клавиша Ctrl

MK_LBUTTON нажата левая кнопка мыши

MK_MBUTTON нажата средняя кнопка мыши

MK_RBUTTON нажата правая кнопка мыши

MK_SHIFT нажата клавиша Shift

Параметр point, объект класса CPoint, содержит текущие координаты указателя мыши.

Итак, кнопка мыши нажата. Первым делом необходимо сохранить текущее положение указателя. Мы воспользуемся переменными х и у и присвоим им значения, полученные из переменных х и у объекта point:

void CMouserView:: OnLButtonDown (UINT nFlags, CPoint point)

{

/ / TODO: добавьте код обработки сообщения

/ / И / или вызовите обработчик по умолчанию

х = point.х;

у = point.у;

...

}

Переменные для хранения координат объявляются в заголовочном файле вида

mouserView.h:

/ / MouserView.h: интерфейс класса CMouserView

...

protected: / / создание только при сериализации

CMouserViewO;

DECLARE_DYNCREATE (CMouserView)

CPoint CaretPosition;

boolean CaretCreated;

int x, y;

...

Щелчок мышью означает, что текст будет выводиться в новом положении, - для очистки срочного объекта мы воспользуемся методом Empty () класса CString:

void CMouserView:: OnLButtonDown (UINT nFlags, CPoint point)

{

/ / TODO: добавьте код обработки сообщения

/ / И / или вызовите обработчик по умолчанию

х = point.х;

у = point.у;

CMouserDoc * pDoc = GetDocument ();

ASSERT__VALID (pDoc);

pDoc-> StringData.Empty ();

}

Остается только объявить текущее состояние вида недействительным, чтобы перерисовать его и отразить курсор в новом месте (соответствующий код был добавлен в метод OnDraw ()):

void CMouserView:: OnLButtonDown (UINT nFlags, CPoint point)

{

/ / TODO: добавьте код обработки сообщения

/ / И / или вызовите обработчик по умолчанию

х = point.х;

у = point.у;

CMouserDoc * pDoc = GetDocument ();

ASSERT_VALID (pDoc);

pDoc-> StringData.Empty ();

Invalidate ();

CView:: 0nl_ButtonDown (nFlags, point);

}

Координаты указателя мыши сохранены. Следующий шаг - вывод в месте, выбранном пользователем.

Обработка сообщений

Давайте теперь сделаем так, что бы наша программа, созданная на предыдущей лекции, обращала внимание на наши действия.

Откроем проект, созданный и сохраненный на прошлом занятии. File-> Open Workspace... -> имя файла.dsw

Создадим, например, чтобы при щелчке мышкой выскакивал MessageBox (окно сообщения).

Для этого в наш класс вставьте следующий строчки:

class CMyMainWnd: public CFrameWnd

{

public:

     CMyMainWnd ()

    {

         Create (NULL, "My title");

     }

     afx_msg void OnLButtonDown (UINT, CPoint);

     DECLARE_MESSAGE_MAP ()

};

Далее после класса напишите

BEGIN_MESSAGE_MAP (CMyMainWnd, CFrameWnd) ON_WM_LBUTTONDOWN () END_MESSAGE_MAP ()

И, наконец, в конце файла добавьте строки

CMyApp theApp; void CMyMainWnd:: OnLButtonDown (UINT, CPoint )

{

AfxMessageBox (" Левая кнопка мыши");

}

Откомпилируйте приложение (Ctrl F5). При нажатии левой кнопки мыши в окне должен выскочить MessageBox с надписью " Левая кнопка мыши".

Давайте теперь обсудим код. Для того, чтобы наш класс обращал внимание на наши действия, мы должны сделать следующие действия.

Первое. Мы должны вставить в конец нашего класса макрос DECLARE_MESSAGE_MAP (). Это достаточно сделать один раз. Этот макрос в классе и означает, что этот класс будет реагировать на некоторые сообщения.

Второе. Мы должны где-то после класса добавить два макроса BEGIN_MESSAGE_MAP () и END_MESSAGE_MAP (). Это тоже достаточно сделать только один раз. Это так называемая карта сообщений. В первый макрос первым параметром вы должны вставить имя вашего класса, вторым - имя родительского класса. Первый параметр показывает, для какого класса мы пишем нашу карту сообщений, а второй - кто должен обрабатывать то или иное сообщение, если наш класс не может.

Теперь мы должны написать код для конкретного сообщения. Для этого делаем следующий шаги.

Третий шаг. В классе пишем метод для обработки конкретного сообщения. Для стандартных сообщений имена методов стандартные. Образуются они так: пишем новый префикс On, после которого пишем нужное сообщение Windows без префикса WM_, причем в нем большими буквами пишем только первые буквы в каждом слове. Например, сообщение WM_ONLBUTTONDOWN превратится в OnLButtonDown. Параметры и возвращаемое значение берем из подсказок. Перед названием метода не забудем написать afx_msg. В нашем примере это afx_msg void OnLButtonDown (UINT, CPoint);

Четвертый шаг. В карту сообщений пишем макрос для нашего уведомления. В нашем примере это строка ON_WM_LBUTTONDOWN ()

BEGIN_MESSAGE_MAP (CMyMainWnd, CFrameWnd) ON_WM_LBUTTONDOWN () END_MESSAGE_MAP ()

Его имя - это ON_ плюс имя сообщения.

Пятый шаг. Пишем, что же конкретно делает наш метод. Здесь мы для примера написали

void CMyMainWnd:: OnLButtonDown (UINT, CPoint)

{

AfxMessageBox ("Левая кнопка мыши");

}

Функции с префиксом Afx определены в MFC глобально. Они не принадлежат конкретному классу.

Рисование простых элементов в окне

Давайте теперь посмотрим, как можно в нашем окне что-нибудь нарисовать. В Windows все рисование происходит на так называемом контексте устройства (Device context по - английски). При этом рисование происходит одинаково и для экрана, и для принтера, и для плоттера и т. п. Вы можете думать, что контекст устройства - это как бы полотно. На нем вы рисуете, применяя кисти, перья, шрифты и другие объекты.

Когда окна надо либо перерисовать, оно получает сообщение WM_PAINT. Для рисования нам надо написать обработчик для этого события. Для этого мы должны сделать шаги 3-5 из предыдущего вопроса. Напомним их.

Итак, вносим объявление функции в класс:

class CMyMainWnd:

public CFrameWnd

{

...

afx_msg void OnLButtonDown (UINT, CPoint);

afx_msg void OnPaint ();

DECLARE_MESSAGE_MAP ()

};

Затем добавляем макрос в карту сообщений:

BEGIN_MESSAGE_MAP (CMyMainWnd, CFrameWnd)... ON_WM_PAINT () END_MESSAGE_MAP ()

И, наконец, пишем реализацию нашей функции:

void CMyMainWnd:: OnPaint ()

{

CPaintDC * pDC = new CPaintDC (this);

pDC-> Rectangle (10,10,500,500);

pDC-> Ellipse (10,130,500,500);

pDC-> MoveTo (500,300);

pDC-> LineTo (800,130);

}

В реализации мы делаем следующее - заводим контекст устройства для рисования в строке

CPaintDC * pDC = new CPaintDC (this);

Здесь контест устройства мы создаем динамично. Слово this означает, что мы его тут же прикрепляем к нашему окна (так как сейчас мы находимся в классе CMyMainWnd). В контекста устройства много различных методов. Один из них - это рисование прямоугольника, который мы и используем. Его параметры - это координаты верхнего левого и правого нижнего углов. Есть и множество других методов - для рисования круга и эллипса

pDC - > Rectangle (10,10,500,500); / / Рисования прямоугольника

pDC - > Ellipse (10,130,500,500); / / Рисования эллипса

pDC - > MoveTo (500,300); / / Перенос начальной точки

pDC - > LineTo (800,130); / / Рисования линии

Запускаем программу. В левом углу должен появится квадратик, эллипс, линия.

КОНТРОЛЬНЫЕ ВОПРОСЫ

1. Что вы понимаете под термином автоматизация процесса создания приложения ?

2. Что такое генератор приложения ?

3. Что такое MFC AppWizard, для чего он нужен ?

4. Что такое MFC ?

5. Дайте определение API (Application Programming Interfase) ?

6. Дайте определение DLL, какие функции она выполняет?

7. Как вы понимаете определение многозадачнисть в Windows?

8. Как организован цикл сообщений в Windows?

9. Назовите основные типы данных в Windows ?

10. Назовите преимущества использования MFC ?

11. Назовите типы мастеров проектов?

12. Назовите преимущества использования мастеров проектов?

13. Что означает управляемый событиями ?

14. Перечислите основные операции с мышью ?

15. Приведите примеры сообщений win32, связанные с событиями мыши ?

16. Как осуществить ввод с помощью мыши ?

17. Какие методы для работы с мышью вы знаете?

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]