|
iTool Programming: Creating a User Interface Panel |
|
The following example creates a simple user interface panel consisting of two buttons: Rotate and Hide/Show. The Rotate button rotates the selected iTool component 90 degrees, if possible. The Hide/Show button toggles the value of the HIDE property of the selected object.
| Note This example is intended to demonstrate the concepts involved in creating a user interface panel. For examples of more useful panels, see the files idlitwdimgmenu.pro and idlitwdvolmenu.pro, which create the user interface panels for the IIMAGE and IVOLUME iTools, respectively. Both files are located in the lib/itools/ui_widgets subdirectory of the IDL installation directory. |
To display a user interface panel named Example4_panel, this example creates the following items:
| Example Code The code for this example user interface panel is included in the file example4_panel.pro in the examples/doc/itools subdirectory of the IDL distribution. Enterat the IDL prompt to create an instance of an iTool that displays the panel. Open the file in any text editor or enter at the IDLDE prompt to open the .pro file in the IDL editor. |
The user interface panel creation routine (beginning with the line PRO Example4_panel, wPanel, oUI) does the work of displaying the IDL widgets that make up the UI panel display.
PRO Example4_panel, wPanel, oUI
; Set the title used on the panel's tab.
WIDGET_CONTROL, wPanel, BASE_SET_TITLE = 'Example Panel'
; Specify the event handler
WIDGET_CONTROL, wPanel, EVENT_PRO = "Example4_panel_event"
; Register the panel with the user interface object.
strObserverIdentifier = oUI->RegisterWidget(wPanel, "Panel", $
'Example4_panel_callback')
; Register to receive selection events on visualizations.
oUI->AddOnNotifyObserver, strObserverIdentifier, $
'Visualization'
; Retrieve a reference to the current iTool.
oTool = oUI->GetTool()
; Create a base widget to hold the contents of the panel.
wBase = WIDGET_BASE(wPanel, /COLUMN, SPACE = 5, /ALIGN_LEFT)
; Create panel contents.
wLabel = WIDGET_LABEL(wBase, VALUE = "Choose an Action:", $
/ALIGN_LEFT)
; Get the Operation ID of the rotate operation. If the operation
; exists, create the "Rotate Item" button and monitor whether
; the operation is available for the selected item.
opID = 'Operations/Operations/Rotate/RotateLeft'
oRotate = oTool->GetByIdentifier(opID)
IF (OBJ_VALID(oRotate)) THEN BEGIN
idRotate = oRotate->GetFullIdentifier()
wRotate = WIDGET_BUTTON(wBase, VALUE = "Rotate Item", $
UVALUE="ROTATE")
; Monitor for availablity of the Rotate operation.
oUI->AddOnNotifyObserver, strObserverIdentifier, idRotate
ENDIF ELSE $
idRotate = 0
wHide = WIDGET_BUTTON(wBase, VALUE = "Show/Hide Item", $
UVALUE = "HIDE")
; Pack up the state structure and store in first child.
state = {oTool:oTool, $
oUI:oUI, $
idRotate : idRotate, $
wPanel:wPanel, $
wBase:wBase, $
wRotate:wRotate, $
wHide:wHide $
}
wChild = WIDGET_INFO(wPanel, /CHILD)
IF wChild NE 0 THEN $
WIDGET_CONTROL, wChild, SET_UVALUE = state, /NO_COPY
END
It is beyond the scope of this chapter to describe the IDL widget concepts employed in the Example4_panel example; the comments in the code that creates the user interface panel describe most of the features. The following points are worth noting, however:
wPanel, in this example), and an object reference to the IDLitUI object associated with the iTool (stored in the variable oUI).
Example4_panel_event. This event-handling routine is described in Panel Event Handler Routine.
Example4_panel_callback, using the RegisterWidget method of the IDLitUI class. The callback routine is described in Panel Callback Routine.
Visualization component described in Adding Observers.
Rotate Left operation, placing it in the variable oRotate.
Rotate Left operation is available to the iTool, the example places the Rotate button on the user interface panel. It also establishes an observer to watch for changes in the availability of the Rotate Left operation, which will change based on the item selected. The callback routine uses the messages received by this observer to sensitize and desensitize the Rotate button as necessary.
The event-handler routine (beginning with the line PRO Example4_panel_event, event) receives widget events generated by the widgets that make up the user interface panel, and acts accordingly.
PRO Example4_panel_event, event ; Retrieve the widget ID of the first child widget of ; the UI panel. wChild = WIDGET_INFO(event.handler, /CHILD) ; Retrieve the state structure from the user value of ; the first child widget. WIDGET_CONTROL, wChild, GET_UVALUE = state ; Retrieve the user value of the widget that generated ; the event. WIDGET_CONTROL, event.id, GET_UVALUE = uvalue ; Now do the work for each panel item. SWITCH STRUPCASE(uvalue) OF 'ROTATE': BEGIN ; Apply the Rotate Left operation to the selected item. success = state.oUI->DoAction(state.idRotate) RETURN END 'HIDE': BEGIN ; Hide the selected item. ; oTargets = state.oTool->GetSelectedItems(count = nTarg) IF nTarg GT 0 THEN BEGIN ; If there are selected items, use only the last item ; selected, which is stored in the first element of ; the returned array. oTarget = oTargets[0] ; Get the iTool identifier of the selected item. name = oTarget->GetFullIdentifier() ; Retrieve the setting of the HIDE property. oTarget->GetProperty, HIDE = hide ; Change the value of the HIDE property from 0 to 1 ; or from 1 to 0. Use the DoSetProperty and ; CommitActions method to ensure that the change ; is entered into the undo/redo transaction buffer. void = state.oTool->DoSetProperty(name, "HIDE", $ ((hide+1) MOD 2)) state.oTool->CommitActions ENDIF BREAK END ELSE: ENDSWITCH ; Refresh the iTool window. state.oTool->RefreshCurrentWindow END
It is beyond the scope of this chapter to describe the IDL widget concepts employed in the Example4_panel event handler; the comments in the code describe most of the features. The following points are worth noting, however:
Rotate button, the example calls the DoAction method of the IDLitUI object, with the identifier of the Rotate Left operation as its argument.
Hide/Show button, the example does the following:
The user interface panel callback routine is called whenever a component, for which an OnNotifyObserver has been registered, generates a message. It parses the message received and takes action as necessary.
PRO Example4_panel_callback, wPanel, strID, messageIn, component ; Make sure we have a valid widget ID. IF ~ WIDGET_INFO(wPanel, /VALID) THEN RETURN ; Retrieve the widget ID of the first child widget of ; the UI panel. wChild = WIDGET_INFO(wPanel, /CHILD) ; Retrieve the state structure from the user value of ; the first child widget. WIDGET_CONTROL, wChild, GET_UVALUE = state ; Process as necessary, depending on the message received. SWITCH STRUPCASE(messageIn) OF ; This section handles messages generated when the rotate ; operation becomes available or unavailable, and sensitizes ; or desensitizes the "Rotate" button accordingly. 'SENSITIVE': 'UNSENSITIVE': BEGIN WIDGET_CONTROL, state.wRotate, $ SENSITIVE = (messageIn EQ 'SENSITIVE') BREAK END ; This section handles messages generated when the ; item selected in the iTool window changes and changes ; the sensitivity of the "Hide/Show" and "Rotate" buttons ; accordingly. 'SELECTIONCHANGED': BEGIN ; Retrieve the item that was selected last, which is ; stored in the first element of the returned array. oSel = state.oTool->GetSelectedItems() oSel = oSel[0] ; If the last item selected is not a visualization, ; desensitize the "Hide/Show" and "Rotate" buttons. IF (~OBJ_ISA(oSel, 'IDLITVISUALIZATION')) THEN BEGIN WIDGET_CONTROL, state.wHide, SENSITIVE = 0 WIDGET_CONTROL, state.wRotate, SENSITIVE = 0 ENDIF ELSE BEGIN ; If the selected object is a visualization, sensitize ; the "Hide/Show" and "Rotate" buttons. WIDGET_CONTROL, state.wHide, SENSITIVE = 1 WIDGET_CONTROL, state.wRotate, SENSITIVE = 1 ENDELSE BREAK END ELSE: ENDSWITCH END
The example panel's callback routine performs the following tasks:
wPanel argument to retrieve the widget state structure stored in the first child widget of the panel widget.
messageIn argument is either SENSITIVE or UNSENSITIVE, change the sensitivity of the Rotate button (stored in the wRotate field of the widget state structure) as necessary.
messageIn argument is SELECTIONCHANGED, perform the following tasks:oTool field of the state structure to retrieve a reference to the last selected component. (Note that the last object selected is stored in the first element of the returned array.)
Hide/Show button.
Hide/Show button.In order to display the Example4_panel user interface panel along with an iTool, the following two things must happen:
For the purposes of this example, we will create an iTool named example4tool, with a launch routine named example4tool.pro, and an iTool object definition routine named example4tool__define.pro.
| Example Code Both example4tool.pro, and example4tool__define.pro are included in the examples/doc/itools subdirectory of the IDL distribution. |
In the example4tool.pro file, we included the following statement:
ITREGISTER, 'Example Panel', 'Example4_panel', TYPE = 'EXAMPLE', $ /UI_PANEL
Setting the TYPE keyword equal to the string EXAMPLE specifies that the panel should be displayed for all iTools of this type.
In the example4tool__define.pro file, we include the string EXAMPLE in the TYPE property specified in the Init method:
FUNCTION example4tool::Init, _REF_EXTRA = _extra IF (self->IDLitToolbase::Init(_EXTRA = _extra, $ TYPE = 'EXAMPLE') EQ 0) $ THEN RETURN, 0
Since the TYPE specified for the user interface panel in the call to ITREGISTER matches the TYPE defined for our example iTool class, calling the launch routine example4tool at the IDL Command Line creates a new iTool and displays the Example4_panel panel on the right side of the iTool window.
IDL Online Help (March 06, 2007)