Главная :: Программы для программирования :: wxWidgets :: Перевод книги "Programming with wxWidgets" :: Глава 6 – Обработка данных с устройств ввода. Часть 2
Можно ли сообщение "Программа выполнила недопустимую операцию... обратитесь к разработчику" считать официальным вызовом в США?

Глава 6 – Обработка данных с устройств ввода. Часть 2

6.1.1 Обработка событий о движении мыши и нажатии кнопок

Ниже представлены главные функции событий мыши, которые вы можете использовать для обработки событий о передвижениях мыши и нажатиях на ее кнопки.

Для проверки, нажаты ли клавиши-модификаторы во время перехвата события, используйте функции AltDown, MetaDown, ControlDown или ShiftDown. Функция CmdDown используется для проверки, нажата ли клавиша Meta (на Mac OS X) или клавиша Control (на других платформах). Дополнительную информацию можно найти далее в этой главе в разделе “Разновидности клавиш-модификаторов”.

Для определения, какая кнопка мыши нажата в данный момент, используйте функции LeftIsDown, MiddleIsDown и RightIsDown. Также можно проверить, нажата ли какая-либо кнопка, послав событие wxMOUSE_BTN_LEFT, wxMOUSE_BTN_MIDDLE, wxMOUSE_BTN_RIGHT или wxMOUSE_BTN_ANY объекту wxButton. Обратите внимание, что это проверка на нажатие какой-либо кнопки на момент совершения события, а не при смене его состояния.

В Mac OS X клавиша Command означает клавишу Meta, а клавиша Alt — Option. Так как часто на Mac-комьютерах мышь имеет только одну кнопку мыши, то пользователь должен удерживать Control во время клика, чтобы получить событие клика правой кнопкой. Это означает, что в Mac OS невозможно сделать правый клик одновременно с Control, если у вас нет обычной мыши с двумя или тремя кнопками.

Вы можете выяснить тип произошедшего события с помощью функций Dragging (движение курсора с удерживаемой кнопкой), Moving (без нее), Entering, Leaving, ButtonDown, ButtonUp, ButtonDClick, LeftClick, LeftDClick, LeftUp, RightClick, RightDClick, RightUp, ButtonUp и IsButton.

Чтобы получить позицию курсора в пикселях монитора (относительно верхнего левого угла клиентской области окна) используйте функции GetPosition или GetX и GetY. Также возможно получить позицию в логических координатах, передав контекст устройства функции GetLogicalPosition.

Вот пример обработки событий мыши в простом демонстрационном приложении:

BEGIN_EVENT_TABLE(DoodleCanvas, wxWindow) EVT_MOUSE_EVENTS(DoodleCanvas::OnMouseEvent) END_EVENT_TABLE() void DoodleCanvas::OnMouseEvent(wxMouseEvent& event) { static DoodleSegment *s_currentSegment = NULL; wxPoint pt(event.GetPosition()); if (s_currentSegment && event.LeftUp()) { // Заканчиваем сегмент, если пользователь отпустил левую кнопку if (s_currentSegment->GetLines().GetCount() == 0) { // Если сегмент пустой, то удаляем его delete s_currentSegment; s_currentSegment = (DoodleSegment *) NULL; } else { // Сохраняем сегмент DrawingDocument *doc = GetDocument(); doc->GetCommandProcessor()->Submit( new DrawingCommand(wxT("Add Segment"), DOODLE_ADD, doc, s_currentSegment)); doc->Modify(true); s_currentSegment = NULL; } } else if (m_lastX > -1 && m_lastY > -1 && event.Dragging()) { // При движении мыши с нажатой кнопкой, добавляем линию в текущий сегмент if (!s_currentSegment) s_currentSegment = new DoodleSegment; DoodleLine *newLine = new DoodleLine(m_lastX, m_lastY, pt.x, pt.y); s_currentSegment->GetLines().Append(newLine); wxClientDC dc(this); DoPrepareDC(dc); dc.SetPen(*wxBLACK_PEN); dc.DrawLine( m_lastX, m_lastY, pt.x, pt.y); } m_lastX = pt.x; m_lastY = pt.y; }

В этом приложении сегменты линий хранятся в документе. Пока пользователь, удерживая левую кнопку, двигает мышь, функция добавляет линии к текущему сегменту и одновременно рисует их. Как только пользователь отпускает левую кнопку мыши, текущий сегмент передается в документ, используя управляющий процессор (часть архитектуры Документ/Вид), который отвечает за реализацию операций “отменить” и “повторить”. В обработчике OnPaint этого приложения (не приводится) рисуются все сегменты линий документа. За полной реализацией действий “отменить” и “повторить”, обратитесь к Главе 19 “Работа с архитектурой Документ/Вид”. Более полное приложение захватывало бы мышь по нажатию левой кнопки и освобождала ее после отпускания кнопки, чтобы при выходе курсора за пределы окна, оно бы по-прежнему получало события.

6.1.2 Обработка событий от колесика мыши

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

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

В некоторых ситуациях мышь может быть настроена проматывать страницу за раз. В этом случае вам нужно вызвать IsPageScroll и если она вернет значение true, то проматывать страницу.

Ниже показана реализация обработки колесика прокрутки в классе wxScrolledWindow. В переменной m_wheelRotation суммируется вращение, и действие происходит только если количество строк ненулевое.

void wxScrollHelper::HandleOnMouseWheel(wxMouseEvent& event) { m_wheelRotation += event.GetWheelRotation(); int lines = m_wheelRotation / event.GetWheelDelta(); m_wheelRotation -= lines * event.GetWheelDelta(); if (lines != 0) { wxScrollWinEvent newEvent; newEvent.SetPosition(0); newEvent.SetOrientation(wxVERTICAL); newEvent.m_eventObject = m_win; if (event.IsPageScroll()) { if (lines > 0) newEvent.m_eventType = wxEVT_SCROLLWIN_PAGEUP; else newEvent.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN; m_win->GetEventHandler()->ProcessEvent(newEvent); } else { lines *= event.GetLinesPerAction(); if (lines > 0) newEvent.m_eventType = wxEVT_SCROLLWIN_LINEUP; else newEvent.m_eventType = wxEVT_SCROLLWIN_LINEDOWN; int times = abs(lines); for (; times > 0; times) m_win->GetEventHandler()->ProcessEvent(newEvent); } } }