Using (New) Graphics in an IDL widget program, part I
Here’s an example of embedding an IDL 8 (aka New) Graphics
(NG) window in an IDL widget program with the WIDGET_WINDOW function. There’s quite a bit of code + explanation involved, so I’m breaking this example into two posts: I’ll go over the widget creation routine this week and the event handlers next week. Please download the final version of the program from here
if you’d like to follow along with my explanation.
Start the widget creation routine by reading some sample data included with the IDL distribution:
xsize = 80
ysize = 100
n_images = 57
head = read_binary(file_which('head.dat'), $
The file head.dat
is a flat binary file that holds 57 transverse MRI scans of Dave Stern
’s head. Each image is 80 x 100 pixels.
Next, declare a top-level base widget and use WIDGET_WINDOW to create a draw widget that embeds a NG window:
wtop = widget_base( $
title='NG event handling with IDL widgets')
wdraw = widget_window(wtop, $
The MOUSE_WHEEL_HANDLER keyword acts as an analog to the combination of the EVENT_PRO and WHEEL_EVENTS keywords to WIDGET_DRAW. Here I’m using it to override the default NG user interaction with the scroll wheel (i.e., zooming). These events will be sent to the event handler WIDGET_WINDOW_EX1_MOUSE_WHEEL_EVENT (I like descriptive event handler names). All other NG events (e.g., panning, selection, etc.) will work in this window as they would by default.
Finish the widget creation by 1) making a slider to index the images in the MRI stack, 2) realizing the widget hierarchy and 3) giving the draw widget the initial focus:
windex = widget_slider(wtop, $
title='Image index', $
widget_control, wtop, /realize
widget_control, wdraw, /input_focus
Note that the slider widget uses the traditional EVENT_PRO keyword to identify its event handler.
Next, extract the NG window reference from the draw widget:
widget_control, wdraw, get_value=w
This is analogous to getting the window index of a DG draw widget or the window object from an OG draw widget. Use the window reference w
as the target for the IMAGE function to display the first image in the stack, enlarged by a factor of four:
g = image(head[*,*,0], $
title='MRI Image Stack: Transverse Plane', $
g.scale, 4.0, 4.0, 1.0
Note that I’ve set the NAME property in the call to IMAGE: this tags this NG visualization so I can retrieve its reference later (more on this here
). I’ll use this in next week’s post.
Next, set up a state variable to store information about the widget program that’ll be needed in the event handlers. In IDL 8, I like to use a hash as a state variable
; I think it’s somewhat more readable than the pointer-referencing-a-structure technique.
state = hash()
state['image'] = head
state['n_images'] = n_images
state['index'] = 0
state['index slider'] = windex
I’ve included the original image data, the number of images in the stack, the current image index and the widget identifier for the slider.
Typically, we attach the state variable to the user value of the top-level base (TLB) widget, since the TLB is available in every event structure. When using WIDGET_WINDOW, however, we need a variation on this technique, since NG event handlers don’t accept the traditional IDL widget event structure. The technique that I’ve been using is to attach the state variable to the NG window's user value, then attach the NG window to the top-level base's user value. This ensures that state information is communicated to both the widget and NG event handlers.
w.uvalue = state
widget_control, wtop, set_uvalue=w
End the widget creation routine with a call to XMANAGER to register the program and start event handling:
xmanager, 'widget_window_ex1', wtop, /no_block
Here’s a screenshot of the resulting widget interface from the Linux side of my laptop:
I’ll finish this program next week by looking at the widget event handlers and explaining how they hook into the interface.