Creating Mouse Event Functions
You can create custom functions to handle mouse events in a graphics WINDOW or a WIDGET_WINDOW. These functions must use the syntax described below.
Each function must return a value of 0 to turn off default event handling or 1 to perform default event handling.
See the WINDOW example and WIDGET_WINDOW example, below.
Tip: Instead of creating a separate function for each event handler, you may find it convenient to use a custom event handling class along with the EVENT_HANDLER property. See Creating an Event Handler Class to Control Events for details on how to write this object class.
Syntax
The syntax of the various event handler functions are similar, as the following list shows.
Handler Type |
Syntax |
---|---|
Mouse_Down |
Result = FUNCTION_NAME(Window, X, Y, Button, KeyMods, Clicks) |
Mouse_Motion |
Result = FUNCTION_NAME(Window, X, Y, KeyMods) |
Mouse_Up |
Result = FUNCTION_NAME(Window, X, Y, Button) |
Mouse_Wheel |
Result = FUNCTION_NAME(Window, X, Y, Delta, KeyMods) |
Where FUNCTION_NAME is a unique name for the function, which will be called from one of the mouse event handling keywords of WINDOW or WIDGET_WINDOW. Avoid using generic names such as "MouseDownHandler" or "MouseUpHandler" to prevent name collisions with other applications using event handlers.
Arguments
Window
The object reference of the window in which the mouse event occurred.
X
The x-coordinate location of the mouse cursor (in device coordinates) at the time of the event.
Y
The y-coordinate of the mouse cursor (in device coordinates) at the time of the event.
Button
The value of the clicked button. Possible values are:
Value |
Mouse Button |
---|---|
1 |
Left |
2 |
Middle |
4 |
Right |
Clicks
The value indicating how many button clicks occurred. The value is 1 for a single click and 2 for a double click.
Delta
The value indicating the direction and number of movements of the mouse wheel.
Pushing the wheel generates positive values, pulling the wheel generates negative values. The magnitude of the value depends on the device setting for the individual mouse, but is usually limited to small integer values such as +1, -1, +2, -2, etc.
KeyMods
The value containing a bitwise mask indicating which modifier keys are active at the time the mouse event happens. Possible values are:
Value |
Modifier Key |
1 |
Shift |
2 |
Control |
4 |
Caps lock |
8 |
Alt |
Example Using WINDOW
In the following example code, the RBBoxMouseDown
function creates a polygon and caches the start point of a drag operation. In the RBBoxMouseMotion
function the polygon is updated with the current location of the cursor. In the RBBoxMouseUp
function, the polygon is again updated and the color of the polygon is modified. Copy this code into a new IDL file and run it. To test the code, drag and drop the mouse to draw a box in the graphic window.
FUNCTION RBBoxMouseDown, oWin, $
x, y, iButton, KeyMods, nClicks
state = oWin.UVALUE
state.x0 = x
state.y0 = y
state.buttonDown = 1
state.poly.HIDE = 0
state.poly.SetData, [0,0,0], [0,0,0]
state.poly.LINESTYLE='--'
oWin.UVALUE=state
RETURN, 0 ; Skip default event handling
END
FUNCTION RBBoxMouseMotion, oWin, x, y, KeyMods
state = oWin.uvalue
IF state.buttonDown then begin
x0 = state.x0
y0 = state.y0
xVector=[x0,x0,x,x,x0]
yVector=[y0,y,y,y0,y0]
xy = state.poly.ConvertCoord(xVector, yVector, /DEVICE, /TO_NORMAL)
state.poly.SetData, REFORM(xy[0,*]), REFORM(xy[1,*])
ENDIF
RETURN, 0 ; Skip default event handling
END
FUNCTION RBBoxMouseUp, oWin, x, y, iButton
state = oWin.uvalue
IF (~state.buttonDown) THEN RETURN, 0
x0 = state.x0
y0 = state.y0
xVector=[x0,x0,x,x,x0]
yVector=[y0,y,y,y0,y0]
xy = state.poly.ConvertCoord(xVector, yVector, /DEVICE, /TO_NORMAL)
state.poly.SetData, REFORM(xy[0,*]), REFORM(xy[1,*])
state.poly.LINESTYLE='-'
state.buttonDown=0
oWin.uvalue=state
; Clear the current selections
oSelect = oWin.GetSelect()
FOREACH oVis, oSelect do oVis.Select, /UNSELECT
; Do a hit test and select new items.
oVisList = oWin.HitTest(x0+(x-x0)/2, y0+(y-y0)/2, $
DIMENSIONS=ABS([x-x0, y-y0]) > 10)
FOREACH vis, oVisList do begin
if vis ne state.poly then vis.Select, /ADD
ENDFOREACH
RETURN, 0 ; Skip default event handling
END
PRO RBBoxEventsTest
x = Findgen(200)
y = Sin(x*2*!PI/25.0)*Exp(-0.01*x)
p = PLOT(x, y, TITLE='Click, hold mouse down and drag, release to draw box')
; Add a hidden polygon for the rubber-band box.
poly = POLYGON([0,0,0],[0,0,0], /DEVICE, $
LINESTYLE='--', /HIDE, $
FILL_TRANSPARENCY=90, FILL_BACKGROUND = 1, FILL_COLOR='red')
p.window.UVALUE={x0:0, y0:0, buttonDown:0L, $
poly: poly}
p.window.MOUSE_DOWN_HANDLER='RBBoxMouseDown'
p.window.MOUSE_UP_HANDLER='RBBoxMouseUp'
p.window.MOUSE_MOTION_HANDLER='RBBoxMouseMotion'
END
Example Using WIDGET_WINDOW
In this example, only the MOUSE_MOTION_HANDLER event handler is used. The event coordinates (in device coordinates) are converted to data coordinates and displayed in a label widget below the draw widget. A crosshair is also drawn at the nearest plot data point.
Mouse Event Handler Function
FUNCTION ExWidWinMouseMotionHandler, oWin, x, y, KeyMods
state = oWin.uValue
IF (~ISA(state.plot)) then return, 1
; Convert from screen coordinates to data coordinates.
xy = state.plot.ConvertCoord(x, y, /DEVICE, /TO_DATA)
; "Snap" the location to the nearest plot point.
xy = state.plot.GetValueAtLocation(xy[0])
; Update the crosshair location and the label
state.crosshair.LOCATION = xy
probe = STRING(xy[0:1], FORMAT='(2F9.2)')
WIDGET_CONTROL, state.label, SET_VALUE=probe
return, 1 ; Perform default event handling
END
Mouse Motion Procedure
Run the following code example to test the event handling functions defined in the previous code example.
PRO ExWidgetWindowEvents_event, event
; Be sure to process the internal window event first.
; This handles selection, translation, rotation, etc.
w = WIDGET_EVENT(/NOWAIT)
CASE TAG_NAMES(event, /STRUCTURE_NAME) of
'WIDGET_BASE': BEGIN
; Handle base resize events. Retrieve our cached padding,
; and our new size.
WIDGET_CONTROL, event.id, GET_UVALUE=pad, TLB_GET_SIZE=newSize
wDraw = WIDGET_INFO(event.top, FIND_BY_UNAME='ex_widwin_window')
; Change the draw widget to match the new size, minus padding.
xy = newSize - pad
WIDGET_CONTROL, wDraw, $
DRAW_XSIZE=xy[0], DRAW_YSIZE=xy[1], $
SCR_XSIZE=xy[0], SCR_YSIZE=xy[1]
END
ELSE: ; do nothing
ENDCASE
END
PRO ExWidgetWindowEvents
; Create the widgets (start unmapped)
wBase = WIDGET_BASE(/COLUMN, /TLB_SIZE_EVENTS, MAP=0)
wDraw = WIDGET_WINDOW(wBase, $
UNAME='ex_widwin_window', $
MOUSE_MOTION_HANDLER='ExWidWinMouseMotionHandler', $
X_SCROLL_SIZE=640, Y_SCROLL_SIZE=512)
w1 = WIDGET_LABEL(wBase, /ALIGN_LEFT, /DYNAMIC)
WIDGET_CONTROL, wBase, /REALIZE
; Cache the padding between the base and the draw
WIDGET_CONTROL, wBase, TLB_GET_SIZE=basesize
padding = basesize - [640, 512]
WIDGET_CONTROL, wBase, SET_UVALUE=padding
; Retrieve the newly-created Window object.
WIDGET_CONTROL, wDraw, GET_VALUE=win
; Make sure this is the current window
win.Select
p = PLOT(/TEST, /CURRENT)
; Change crosshair to "manual" mode and set some properties.
c = p.CROSSHAIR
c.STYLE = 'Manual'
c.COLOR = 'Red'
c.LINESTYLE = '-'
; Cache the graphics references for the event handlers
win.uValue = {plot:p, label:w1, crosshair: c}
; Draw the widgets and start the event processing
WIDGET_CONTROL, wBase, /MAP
XMANAGER, 'ExWidgetWindowEvents', wBase, /NO_BLOCK
END