You can create a custom event handler to handle events in a graphics WINDOW or a WIDGET_WINDOW. The event handler class must be a subclass of GraphicsEventAdapter. Your subclass can then override any of the following methods: ::MouseDown, ::MouseUp, ::MouseMotion, ::MouseWheel, ::KeyHandler, and ::SelectChange.
Each function method 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.
Syntax
The syntax of the various event handler methods are similar, as the following list shows.
Result = obj.MouseDown(Window, X, Y, Button, KeyMods, Clicks)
Result = obj.MouseMotion(Window, X, Y, KeyMods)
Result = obj.MouseUp(Window, X, Y, Button)
Result = obj.MouseWheel(Window, X, Y, Delta, KeyMods)
Result = obj.KeyHandler(Window, IsASCII, Character, KeyValue, X, Y, Press, Release, KeyMods)
Result = obj.SelectChange(Window, Graphic, Mode, WasSelected)
Arguments
Window
The object reference of the window in which the 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 |
IsASCII
A scalar byte value that indicates whether the keyboard event corresponds to an ASCII character. If IsASCII is non-zero, the Character argument will be set to a byte value corresponding to the character of the pressed key. If IsASCII is zero, the KeySymbol argument will be set to a numeric value indicating the key that was pressed.
Character
If IsASCII is non-zero, this argument is set to a byte value corresponding to the ASCII character of the key that was pressed. Otherwise, this argument is set to zero.
KeyValue
If IsASCII is zero, this argument is set to a value that indicates the key that was pressed. Otherwise, this argument is set to zero. Possible values are:
Value |
Key |
1 |
Shift |
2 |
Control |
3 |
Caps lock |
4 |
Alt |
5 |
Left |
6 |
Right |
7 |
Up |
8 |
Down |
9 |
Page up |
10 |
Page down |
11 |
Home |
12 |
End |
Note: On East Asian (Chinese, Japanese, Korean) localized Windows operating systems with an Asian language pack installed, characters entered in the Windows Input Method Manager (IMM)composition window are returned in the the KeyValue argument as unsigned integers representing a Wide character (Unicode value). The I18N_WIDECHARTOMULTIBYTE routine can convert these characters to multibyte strings. For more information, see Internationalizing Code.
Press
The value indicating that this event represents a key press. This argument is non-zero if the event is the result of pressing the key.
Release
The value indicating that this event represents a key release. This argument is non-zero if the event is the result of releasing the key.
Graphic
The graphic to be selected or unselected.
Mode
A value representing the mode that was used for the current selection. Possible values are:
Value |
Selection Type |
0 |
Unselect |
1 |
Select |
2 |
Toggled selection
|
3 |
Additive |
WasSelected
A value indicating if the graphic item was already selected prior to this event. A value of 1 indicates an item was previously selected; 0 if not selected.
GraphicsEventAdapter Class
The GraphicsEventAdapter class provides a default implementation for all of the event handler methods. The default implementation returns a value of 1 for each of the methods. For convenience, you should create your event handler as a subclass of GraphicsEventAdapter and only override the methods that you need.
The GraphicsEventAdapter class is written in the IDL language. Its source code can be found in the file graphicseventadapter__define.pro in the lib/graphics subdirectory of the IDL distribution.
Example Using WINDOW
In the following example code, the RBBox class create a "rubber-band" box. The RBBox::MouseDown method creates a polygon and caches the start point of a drag operation. In the RBBox::MouseMotion method the polygon is updated with the current location of the cursor. In the RBBox::MouseUp method, 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 RBBox::MouseDown, oWin, $
x, y, iButton, KeyMods, nClicks
if (~ISA(self.poly)) then begin
self.poly = POLYGON([0,0,0],[0,0,0], /DEVICE, $
LINESTYLE='--', /HIDE, $
FILL_TRANSPARENCY=90, FILL_BACKGROUND = 1, FILL_COLOR='red')
endif
self.x0 = x
self.y0 = y
self.buttonDown = 1
self.poly.HIDE = 0
self.poly.SetData, [0,0,0], [0,0,0]
self.poly.LINESTYLE='--'
RETURN, 0
END
FUNCTION RBBox::MouseMotion, oWin, x, y, KeyMods
IF self.buttonDown then begin
x0 = self.x0
y0 = self.y0
xVector=[x0,x0,x,x,x0]
yVector=[y0,y,y,y0,y0]
xy = self.poly.ConvertCoord(xVector, yVector, /DEVICE, /TO_NORMAL)
self.poly.SetData, REFORM(xy[0,*]), REFORM(xy[1,*])
ENDIF
RETURN, 0
END
FUNCTION RBBox::MouseUp, oWin, x, y, iButton
IF (~self.buttonDown) THEN RETURN, 0
x0 = self.x0
y0 = self.y0
xVector=[x0,x0,x,x,x0]
yVector=[y0,y,y,y0,y0]
xy = self.poly.ConvertCoord(xVector, yVector, /DEVICE, /TO_NORMAL)
self.poly.SetData, REFORM(xy[0,*]), REFORM(xy[1,*])
self.poly.LINESTYLE='-'
self.buttonDown=0
oSelect = oWin.GetSelect()
FOREACH oVis, oSelect do oVis.Select, /UNSELECT
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 self.poly then vis.Select, /ADD
ENDFOREACH
RETURN, 0
END
PRO RBBox__define
void = {RBBox, inherits GraphicsEventAdapter, $
X0: 0, Y0:0, BUTTONDOWN:0, POLY:OBJ_NEW()}
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')
p.window.EVENT_HANDLER=Obj_New('RBBox')
END
Example Using WIDGET_WINDOW
In this example, only the MouseMotion event method 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. Save all of the code in a file, exwidgetwindowevents.pro, and then run the ExWidgetWindowEvents procedure.
FUNCTION ExWidWin::Init, plot, label, crosshair
self.plot = plot
self.label = label
self.crosshair = crosshair
return, 1
END
FUNCTION ExWidWin::MouseMotion, oWin, x, y, KeyMods
xy = self.plot.ConvertCoord(x, y, /DEVICE, /TO_DATA)
xy = self.plot.GetValueAtLocation(xy[0])
self.crosshair.LOCATION = xy
probe = STRING(xy[0:1], FORMAT='(2F9.2)')
WIDGET_CONTROL, self.label, SET_VALUE=probe
return, 1
END
PRO ExWidWin__define
void = {ExWidWin, inherits GraphicsEventAdapter, $
plot: OBJ_NEW(), label: 0L, crosshair: OBJ_NEW()}
END
PRO ExWidgetWindowEvents_event, event
w = WIDGET_EVENT(/NOWAIT)
CASE TAG_NAMES(event, /STRUCTURE_NAME) of
'WIDGET_BASE': BEGIN
WIDGET_CONTROL, event.id, GET_UVALUE=pad, TLB_GET_SIZE=newSize
wDraw = WIDGET_INFO(event.top, FIND_BY_UNAME='ex_widwin_window')
xy = newSize - pad
WIDGET_CONTROL, wDraw, $
DRAW_XSIZE=xy[0], DRAW_YSIZE=xy[1], $
SCR_XSIZE=xy[0], SCR_YSIZE=xy[1]
END
ELSE:
ENDCASE
END
PRO ExWidgetWindowEvents
wBase = WIDGET_BASE(/COLUMN, /TLB_SIZE_EVENTS, MAP=0)
wDraw = WIDGET_WINDOW(wBase, $
UNAME='ex_widwin_window', $
X_SCROLL_SIZE=640, Y_SCROLL_SIZE=512)
w1 = WIDGET_LABEL(wBase, /ALIGN_LEFT, /DYNAMIC)
WIDGET_CONTROL, wBase, /REALIZE
WIDGET_CONTROL, wBase, TLB_GET_SIZE=basesize
padding = basesize - [640, 512]
WIDGET_CONTROL, wBase, SET_UVALUE=padding
WIDGET_CONTROL, wDraw, GET_VALUE=win
win.Select
p = PLOT(/TEST, /CURRENT)
c = p.CROSSHAIR
c.STYLE = 'Manual'
c.COLOR = 'Red'
c.LINESTYLE = '-'
handler = OBJ_NEW('ExWidWin', p, w1, c)
win.EVENT_HANDLER = handler
WIDGET_CONTROL, wBase, /MAP
XMANAGER, 'ExWidgetWindowEvents', wBase, /NO_BLOCK
END