Mouse Input

team bbl


Broadly speaking, there are two categories of mouse input. Basic mouse events are sent using wxMouseEvent and are passed uninterpreted to your handler function. Commands associated with controls, on the other hand, are often the result of interpreting a mouse (or other) event as a particular command.

For example, when you add EVT_BUTTON to an event table, you are intercepting a wxCommandEvent that was generated by the wxButton. Internally, the button is intercepting EVT_LEFT_DOWN and generating the command event as a result. (Of course, on most platforms, wxButton is implemented natively and doesn't use low-level wxWidgets event handling, but it's true of custom classes.)

Because we've already seen examples of handling command events, we will concentrate on basic mouse events.

You can intercept button up, button down, and double-click events for left, middle, and right mouse buttons. You can intercept motion events, whether the mouse is moving with or without buttons pressed. You can intercept events telling you that the mouse is entering or leaving the window. Finally, you can intercept scroll wheel events if the hardware provides a scroll wheel.

When you receive a mouse event, you can also check the state of the mouse buttons, and the pressed state of the modifier keys (Shift, Alt, Control, and Meta). You can also retrieve the current mouse position relative to the top-left corner of the window's client area.

Table 6-1 lists the event table macros you can use. wxMouseEvent does not propagate to parents of the originating window, so to handle these events, you must derive from a window class or derive from wxEvtHandler and plug the object into the window with SetEventHandler or PushEventHandler. Alternatively, you can use dynamic event handling with Connect.

Table 6-1. Mouse Event Table Macros

EVT_LEFT_DOWN(func

Handles a wxEVT_LEFT_DOWN event, generated when the left mouse button changes to the "down" state.

EVT_LEFT_UP(func)

Handles a wxEVT_LEFT_UP event, generated when the left mouse button changes to the "up" state.

EVT_LEFT_DCLICK(func)

Handles a wxEVT_LEFT_DCLICK event, generated when the left mouse button is double-clicked.

EVT_MIDDLE_DOWN(func)

Handles a wxEVT_MIDDLE_DOWN event, generated when the middle mouse button changes to the "down" state.

EVT_MIDDLE_UP(func)

Handles a wxEVT_MIDDLE_UP event, generated when the middle mouse button changes to the "up" state.

EVT_MIDDLE_DCLICK(func)

Handles a wxEVT_MIDDLE_DCLICK event, generated when the middle mouse button is double-clicked.

EVT_RIGHT_DOWN(func)

Handles a wxEVT_RIGHT_DOWN event, generated when the right mouse button changes to the "down" state.

EVT_RIGHT_UP(func)

Handles a wxEVT_RIGHT_UP event, generated when the right mouse button changes to the "up" state.

EVT_RIGHT_DCLICK(func)

Handles a wxEVT_RIGHT_DCLICK event, generated when the right mouse button is double-clicked.

EVT_MOTION(func)

Handles a wxEVT_MOTION event, generated when the mouse moves.

EVT_ENTER_WINDOW(func)

Handles a wxEVT_ENTER_WINDOW event, generated when the mouse enters the window.

EVT_LEAVE_WINDOW(func)

Handles a wxEVT_LEAVE_WINDOW event, generated when the mouse leaves the window.

EVT_MOUSEWHEEL(func)

Handles a wxEVT_MOUSEWHEEL event, generated when the mouse wheel moves.

EVT_MOUSE_EVENTS(func)

Handles all mouse events.


Handling Button and Motion Events

These are the main mouse event functions that you can use within your event handler when handling mouse button and motion events.

To test whether a modifier key is down at the time of generating the event, use AltDown, MetaDown, ControlDown, or ShiftDown. Use CmdDown if you want to test for either the Meta key (on Mac OS X) or the Control key (other platforms). See "Modifier Key Variations" later in the chapter for more on this.

To determine which mouse button is currently pressed, use LeftIsDown, MiddleIsDown, and RightIsDown. You can also test whether a button is pressed by passing wxMOUSE_BTN_LEFT, wxMOUSE_BTN_MIDDLE, wxMOUSE_BTN_RIGHT or wxMOUSE_ BTN_ANY to Button. Note that these test whether a button is down at the time of the mouse event, rather than whether the button changed state.

On Mac OS X, the Command key translates to Meta, and the Option key is Alt. Because the Mac is often configured with only one mouse button, the user holds down the Control key while clicking to generate a right-click event. This means that there is no such thing as Control-Right Click on Mac unless you have an external mouse with two or three buttons.

You can test for the type of mouse event with Dragging (the mouse is moving with a button pressed down), Moving (no button is currently pressed), Entering, Leaving, ButtonDown, ButtonUp, ButtonDClick, LeftClick, LeftDClick, LeftUp, RightClick, RightDClick, RightUp, ButtonUp, and IsButton.

Retrieve the mouse position in device units (relative to the client window's top-left corner) with GetPosition or GetX and GetY. You can get the position in logical units by passing a device context to GetLogicalPosition.

Here's an example of mouse handling for a simple doodling application.

 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())     {         // End the segment on mouse left up         if (s_currentSegment->GetLines().GetCount() == 0)         {             // Empty segment: delete it             delete s_currentSegment;             s_currentSegment = (DoodleSegment *) NULL;         }         else         {             // We've got a valid segment, so store it             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())     {         // We're dragging: append a line to the current segment         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; } 

In this application, line segments are stored in a document. While the user drags using the left button, the function adds lines to the current segment and also draws the lines. When the user releases the left mouse button, the current segment is submitted to the document using the command processor (part of the document-view framework), which allows undo/redo to be implemented. In the application's OnPaint handler (not shown), all the document's line segments are drawn. For a complete doodling program with undo/redo, see Chapter 19, "Working with Documents and Views."

A more realistic application would capture the mouse on left button down and release it on left button up so that when dragging outside the window, the window would still receive events.

Handling Mouse Wheel Events

When you get a mouse wheel event, you retrieve the positive or negative rotation amount with GetWheelRotation. Divide this value by the value returned by GetWheelDelta to get the number of lines that this rotation represents. Most devices generate one event per delta, but future devices may send events more frequently, so you need to be able to accumulate the amount of rotation and only take action when rotation equivalent to a full line has been received. Alternatively, you may be able to scroll by a fraction of a line. You should take into account the value returned by GetLinesPerAction, as configured by the user via the system control panel, and multiply by this amount to scroll the desired number of actual lines.

In fact, the mouse may be configured to scroll by a page at a time. In this case, you need to call IsPageScroll, and if this returns true, scroll by a page.

To illustrate, here's how wxScrolledWindow implements default scroll wheel processing. The variable m_wheelRotation accumulates the rotation, and action is only taken if the number of lines is non-zero.

 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);         }     } } 

    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net