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