Previous iTool Programming: Creating a User Interface Panel Next

Example: A Simple UI 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.

Figure 14-1: The example panel.

Figure 14-1: The example panel.


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. Enter

example4tool

at the IDL prompt to create an instance of an iTool that displays the panel. Open the file in any text editor or enter

.edit example4_panel


at the IDLDE prompt to open the .pro file in the IDL editor.

Panel Creation Routine

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  
Discussion

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:

Panel Event Handler Routine

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  
Discussion

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:

  • If the event received by the event handler routine is generated by the Rotate button, the example calls the DoAction method of the IDLitUI object, with the identifier of the Rotate Left operation as its argument.
  •  

  • If the event received by the event handler routine is generated by the Hide/Show button, the example does the following:
    • Use the reference to the iTool object stored in the state structure to retrieve the list of selected items using the GetSelectedItems method.
    •  

    • Retrieve the object identifier of the last item selected. (Note that the last item selected is stored in the first element of the returned array.)
    •  

    • Retrieve the value of the HIDE property of the selected item.
    •  

    • Use the DoSetProperty method of the IDLitTool object to toggle the value of the HIDE property for the selected item.
    •  

    • Commit the property change in the undo/redo transaction buffer using the CommitActions method of the IDLitTool object.

     

  • After the iTool display has been changed, call the RefreshCurrentWindow method of the IDLitTool object to redraw the iTool window.

Panel Callback Routine

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  
Discussion

The example panel's callback routine performs the following tasks:

  • Uses the widget ID provided in the wPanel argument to retrieve the widget state structure stored in the first child widget of the panel widget.
  •  

  • If the value of the 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.
  •  

  • If the value of the messageIn argument is SELECTIONCHANGED, perform the following tasks:
    • Use the reference to the iTool object stored in the 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.)
    •  

    • If the selected component is not a visualization, desensitize the Hide/Show button.
    •  

    • If the selected component is a visualization, sensitize the Hide/Show button.

Panel Type Specification

In order to display the Example4_panel user interface panel along with an iTool, the following two things must happen:

  1. The UI panel must be registered, using the ITREGISTER procedure.
  2.  

  3. A tool with the appropriate TYPE must be created.

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)