Previous User Interface Programming: Using Property Sheet Widgets Next

Property Sheet Example

The following example provides a property sheet containing all the available controls, including user-defined properties of a custom component.

Enter the following text into the IDL Editor:

; Property Sheet Demo  
;  
; This program contains these sections of code:  
;  
; (1) Definition of the IDLitTester class.  
; (2) Methods for handling the user-defined data type.  
; (3) Event handlers and main widget program.  
  
;================================================  
; (1) Definition of the IDLitTester class.  
;------------------------------------------------  
; IDLitTester  
;  
; Superclasses:  
;   IDLitComponent  
;  
; Subclasses:  
;   none  
;  
; Interfaces:  
;   IIDLProperty  
;  
; Intrinsic Methods:  
; none (because it contains no objects)  
  
;------------------------------------------------  
; IDLitTester::Init  
  
FUNCTION IDLitTester::Init, _REF_EXTRA = _extra  
  
compile_opt idl2  
  
; Initialize the superclass.  
IF (self->IDLitComponent::Init() ne 1) THEN $  
   RETURN, 0  
  
; Create IDLitTester.  
; Nothing to do, for now.  
  
; Register properties.  
;  
; * Only registered properties will show up in the property sheet.  
; * <identifier> must match self.<identifier>.  
  
self->RegisterProperty, 'BOOLEAN', /BOOLEAN , $  
   NAME = 'Boolean', DESCRIPTION = 'TRUE or FALSE'  
  
self->RegisterProperty, 'COLOR', /COLOR, $  
   NAME = 'Color', DESCRIPTION = 'Color (RGB)'  
  
self->RegisterProperty, 'USERDEF', USERDEF = '', $  
   NAME = 'User Defined', DESCRIPTION = 'User defined property'  
  
self->RegisterProperty, 'NUMBER1', /INTEGER , $  
   NAME = 'Integer', DESCRIPTION = 'Integer in [-100, 100]', $  
   valid_range = [-100, 100]  
  
self->RegisterProperty, 'NUMBER2', /FLOAT, $  
   NAME = 'Floating Point', DESCRIPTION = 'Number trackbar', $  
   valid_range = [-19.0D, 6.0D, 0.33333333333333D]  
  
self->RegisterProperty, 'NUMBER3', /FLOAT, $  
   NAME = 'Floating Point', $  
   DESCRIPTION = 'Double in [-1.0, 1.0]', $  
   valid_range = [-1.0D, 1.0D]  
  
self->RegisterProperty, 'LINESTYLE', /LINESTYLE, $  
   NAME = 'Line Style', DESCRIPTION = 'Line style'  
  
self->RegisterProperty, 'LINETHICKNESS', /THICKNESS , $  
   NAME = 'Line Thickness', $  
   DESCRIPTION = 'Line thickness (pixels)'  
  
self->RegisterProperty, 'STRINGOLA', /STRING , $  
   NAME = 'String', DESCRIPTION = 'Just some text'  
  
self->RegisterProperty, 'SYMBOL', /SYMBOL , $  
   NAME = 'Symbol', DESCRIPTION = 'Symbol of some sort'  
  
self->RegisterProperty, 'STRINGLIST', $  
   NAME = 'String List', DESCRIPTION = 'Enumerated list', $  
   enumlist = ['dog', 'cat', 'bat', 'rat', 'nat', $  
   'emu', 'owl', 'pig', 'hog', 'ant']  
  
; Set any property values.  
self->SetProperty, _EXTRA = _extra  
  
RETURN, 1  
END  
  
;------------------------------------------------  
; IDLitTester::Cleanup  
  
PRO IDLitTester::Cleanup  
  
compile_opt idl2  
  
self->IDLitComponent::Cleanup  
  
END  
  
;------------------------------------------------  
; IDLitTester::GetProperty  
;  
; Implemention for IIDLProperty interface  
  
PRO IDLitTester::GetProperty, $  
   boolean = boolean, $  
   color = color, $  
   userdef = userdef, $  
   font = font, $  
   number1 = number1, $  
   number2 = number2, $  
   number3 = number3, $  
   linestyle = linestyle, $  
   linethickness = linethickness, $  
   stringola = stringola, $  
   stringlist = stringlist, $  
   symbol = symbol, $  
   _REF_EXTRA = _extra  
  
compile_opt idl2  
  
IF (arg_present(boolean)) THEN boolean = self.boolean  
IF (arg_present(color)) THEN color = self.color  
IF (arg_present(userdef)) THEN userdef = self.userdef  
IF (arg_present(font)) THEN font = self.font  
IF (arg_present(number1)) THEN number1 = self.number1  
IF (arg_present(number2)) THEN number2 = self.number2  
IF (arg_present(number3)) THEN number3 = self.number3  
IF (arg_present(linestyle)) THEN linestyle = self.linestyle  
IF (arg_present(linethickness)) $  
   THEN linethickness = self.linethickness  
IF (arg_present(stringola)) THEN stringola = self.stringola  
IF (arg_present(stringlist)) THEN stringlist = self.stringlist  
IF (arg_present(symbol)) THEN symbol = self.symbol  
  
; Superclass' properties:  
IF (n_elements(_extra) gt 0) THEN $  
   self->IDLitComponent::GetProperty, _EXTRA = _extra  
  
END  
  
;------------------------------------------------  
; IDLitTester::SetProperty  
;  
; Implementation for IIDLProperty interface  
  
PRO IDLitTester::SetProperty, $  
   boolean = boolean, $  
   color = color, $  
   userdef = userdef, $  
   font = font, $  
   number1 = number1, $  
   number2 = number2, $  
   number3 = number3, $  
   linestyle = linestyle, $  
   linethickness = linethickness, $  
   stringola = stringola, $  
   stringlist = stringlist, $  
   symbol = symbol, $  
   _REF_EXTRA = _extra  
  
compile_opt idl2  
  
IF (n_elements(boolean) ne 0) THEN self.boolean = boolean  
IF (n_elements(color) ne 0) THEN self.color = color  
IF (n_elements(userdef) ne 0) THEN self.userdef = userdef  
IF (n_elements(font) ne 0) THEN self.font = font  
IF (n_elements(number1) ne 0) THEN self.number1 = number1  
IF (n_elements(number2) ne 0) THEN self.number2 = number2  
IF (n_elements(number3) ne 0) THEN self.number3 = number3  
IF (n_elements(linestyle) ne 0) THEN self.linestyle = linestyle  
IF (n_elements(linethickness) ne 0) THEN $  
   self.linethickness = linethickness  
IF (n_elements(stringola) ne 0) THEN self.stringola = stringola  
IF (n_elements(stringlist) ne 0) THEN self.stringlist = stringlist  
IF (n_elements(symbol) ne 0) THEN self.symbol = symbol  
  
self->IDLitComponent::SetProperty, _EXTRA = _extra  
  
END  
  
;------------------------------------------------  
; IDLitTester__Define  
  
PRO IDLitTester__Define  
  
compile_opt idl2, hidden  
  
struct = {$  
   IDLitTester, $  
   inherits IDLitComponent, $  
   boolean:0L, $  
   color:[0B,0B,0B], $  
   userdef:"", $  
   number1:0L, $  
   number2:0D, $  
   number3:0D, $  
   linestyle:0L, $  
   linethickness:0L, $  
   stringola:"", $  
   stringlist:0L, $  
   symbol:0L $  
   }  
  
END  
  
;================================================  
; (2) Methods for handling the user-defined data type.  
;------------------------------------------------  
; UserDefEvent  
;  
; This procedure is just part of the widget code for  
; the user defined property.  
  
PRO UserDefEvent, e  
  
IF (tag_names(e, /structure_name) eq 'WIDGET_BUTTON') $  
   THEN BEGIN  
  
   widget_control, e.top, get_uvalue = uvalue  
   widget_control, e.id, get_uvalue = numb_ness  
  
   propsheet  = uvalue.propsheet  
   component  = uvalue.component  
   identifier = uvalue.identifier  
  
   ; Set the human readable value.  
   component->SetPropertyAttribute, $  
      identifier, userdef = numb_ness  
  
   ; Set the real value of the component.  
   component->SetPropertyByIdentifier, identifier, numb_ness  
  
   widget_control, propsheet, refresh_property = identifier  
   print, 'Changed: ', uvalue.identifier, ': ', numb_ness  
   widget_control, e.top, /destroy  
  
ENDIF  
  
END  
  
;------------------------------------------------  
; GetUserDefValue  
;  
; Creates widgets used to modify the user defined property's  
; value.  The value is actually set in UserDefEvent.  
  
PRO GetUserDefValue, e  
  
base = widget_base(/row, title = 'Pick a Number', $  
   /modal, group_leader = e.top)  
  
one = widget_button(base, value = 'one', uvalue = 'oneness')  
two = widget_button(base, value = 'two', uvalue = 'twoness')  
six = widget_button(base, value = 'six', uvalue = 'sixness')  
ten = widget_button(base, value = 'ten', uvalue = 'tenness')  
  
; We will need this info when we set the value  
widget_control, base, $  
   set_uvalue = {propsheet:e.id, $  
   component:e.component, $  
   identifier:e.identifier}  
  
widget_control, base, /realize  
  
xmanager, 'UserDefEvent', base, event_handler = 'UserDefEvent'  
  
END  
  
;================================================  
; (3) Event handlers and main widget program.  
;------------------------------------------------  
;  
; Event handling code for the main widget program and  
; the main widget program.  
  
;------------------------------------------------  
; prop_event  
;  
; The property sheet generates an event whenever the user changes  
; a value.  The event holds the property's identifier and type, and  
; an object reference to the component.  
;  
; Note: widget_control, e.id, get_value = objref also retrieves an  
; object reference to the component.  
  
PRO prop_event, e  
  
IF (e.type eq 0) THEN BEGIN   ; Value changed  
  
; Get the value of the property identified by e.identifier.  
  
   IF (e.proptype ne 0) THEN BEGIN  
  
      ; Get the value from the property sheet.  
      value = widget_info(e.id, property_value = e.identifier)  
  
      ; Set the component's property's value.  
      e.component->SetPropertyByIdentifier, e.identifier, $  
         value  
  
      ; Print the change in the component's property value.  
      PRINT, 'Changed', e.identifier, ': ', value  
   ENDIF ELSE BEGIN  
  
      ; Use alternative means to get the value.  
      GetUserDefValue, e  
  
   ENDELSE  
  
ENDIF ELSE BEGIN                ; selection changed  
  
   print, 'Selected: ' + e.identifier  
   r = e.component->GetPropertyByIdentifier(e.identifier, value)  
   PRINT, ' Current Value: ', value  
  
ENDELSE  
  
END  
  
;------------------------------------------------  
; refresh_event  
  
PRO refresh_event, e  
  
widget_control, e.id, get_uvalue = uvalue  
  
uvalue.o->SetProperty, boolean = 0L  
uvalue.o->SetProperty, color = [255, 0, 46]  
uvalue.o->SetPropertyAttribute, 'userdef', userdef = "Yeehaw!"  
uvalue.o->SetProperty, number1 = 99L  
uvalue.o->SetProperty, number2 = -13.1  
uvalue.o->SetProperty, number3 = 6.5  
uvalue.o->SetProperty, linestyle = 6L  
uvalue.o->SetProperty, stringola = 'It worked!'  
uvalue.o->SetProperty, stringlist = 6L  
uvalue.o->SetProperty, symbol = 6L  
  
uvalue.o->SetPropertyAttribute, 'Number1', sensitive = 1  
uvalue.o->SetPropertyAttribute, 'Number2', sensitive = 1  
  
widget_control, uvalue.prop, $  
   refresh_property = ['boolean', 'color', 'userdef', $  
   'number1', 'number2', 'number3', 'linestyle', $  
   'stringola', 'stringlist', 'symbol']  
  
END  
  
;------------------------------------------------  
; reload_event  
  
PRO reload_event, e  
  
widget_control, e.id, get_uvalue = uvalue  
  
LoadValues, uvalue.o  
  
widget_control, uvalue.prop, set_value = uvalue.o  
  
update_state, e.top, 1  
  
END  
  
;------------------------------------------------  
; hide_event  
  
PRO hide_event, e  
  
widget_control, e.id, get_uvalue = uvalue  
  
uvalue.o->SetPropertyAttribute, 'color', /hide  
  
widget_control, uvalue.prop, refresh_property = 'color'  
  
END  
  
;------------------------------------------------  
; show_event  
  
PRO show_event, e  
  
widget_control, e.id, get_uvalue = uvalue  
  
uvalue.o->SetPropertyAttribute, 'color', hide = 0  
  
widget_control, uvalue.prop, refresh_property = 'color'  
  
END  
  
;------------------------------------------------  
; clear_event  
  
PRO clear_event, e  
  
update_state, e.top, 0  
  
widget_control, e.id, get_uvalue = uvalue  
  
widget_control, uvalue.prop, set_value = obj_new()  
  
END  
  
;------------------------------------------------  
; psdemo_large_event  
;  
; Handles resize events for the property sheet demo program.  
  
PRO psdemo_large_event, e  
  
WIDGET_CONTROL, e.id, GET_UVALUE = base  
geo_tlb = WIDGET_INFO(e.id, /GEOMETRY)  
  
WIDGET_CONTROL, base.prop, $  
   SCR_XSIZE = geo_tlb.xsize - (2*geo_tlb.xpad), $  
   SCR_YSIZE = geo_tlb.ysize - (2*geo_tlb.ypad)  
  
END  
  
;------------------------------------------------  
; sensitivity_event  
;  
; Procedure to test sensitizing and desensitizing  
  
PRO sensitivity_event, e  
  
widget_control, e.id, get_uvalue = uvalue, get_value = value  
  
IF (value eq 'Desensitize') THEN b = 0 $  
ELSE b = 1  
  
uvalue.o->SetPropertyAttribute, 'Boolean', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Color', sensitive = b  
uvalue.o->SetPropertyAttribute, 'UserDef', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Number1', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Number2', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Number3', sensitive = b  
uvalue.o->SetPropertyAttribute, 'LineStyle', sensitive = b  
uvalue.o->SetPropertyAttribute, 'LineThickness', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Stringola', sensitive = b  
uvalue.o->SetPropertyAttribute, 'Symbol', sensitive = b  
uvalue.o->SetPropertyAttribute, 'StringList', sensitive = b  
  
widget_control, uvalue.prop, $  
   refresh_property = ['Boolean', 'Color', 'UserDef', $  
   'Number1', 'Number2', 'Number3', 'LineStyle', $  
   'LineThickness', 'Stringola', 'Symbol', 'StringList']  
  
END  
  
;------------------------------------------------  
; LoadValues  
  
PRO LoadValues, o  
  
o->SetProperty, boolean = 1L             ; 0 or 1  
o->SetProperty, color = [200, 100, 50]   ; RGB  
o->SetPropertyAttribute, 'userdef', userdef = ""   
; to be set later  
o->SetProperty, number1 = 42L            ; integer  
o->SetProperty, number2 = 0.0            ; double  
o->SetProperty, number3 = 0.1            ; double  
o->SetProperty, linestyle = 4L           ; 5th item (zero based)  
o->SetProperty, linethickness = 4L       ; pixels  
o->SetProperty, stringola = "This is a silly string."  
o->SetProperty, stringlist = 3L          ; 4th item in list  
o->SetProperty, symbol = 4L              ; 5th symbol in list  
  
END  
  
;------------------------------------------------  
; quit_event  
  
PRO quit_event, e  
  
widget_control, e.top, /destroy  
  
END  
  
;------------------------------------------------  
; update_state  
  
PRO update_state, top, sensitive  
  
widget_control, top, get_uvalue = uvalue  
  
for i = 0, n_elements(uvalue.b) - 1 do $  
   widget_control, uvalue.b[i], sensitive = sensitive  
  
END  
  
;------------------------------------------------  
; psdemo_large  
  
PRO psdemo_large  
  
; Create and initialize the component.  
  
o = obj_new('IDLitTester')  
  
LoadValues, o  
  
; Create some widgets.  
  
base = widget_base(/column, /tlb_size_event, $  
   title = 'Property Sheet Demo (Large)')  
  
prop = widget_propertysheet(base, value = o, $  
   ysize = 13, /frame, event_pro = 'prop_event')  
  
b1 = widget_button(base, value = 'Refresh', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'refresh_event')  
  
b2 = widget_button(base, value = 'Reload', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'reload_event')  
  
b3 = widget_button(base, value = 'Hide Color', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'hide_event')  
  
b4 = widget_button(base, value = 'Show Color', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'show_event')  
  
b5 = widget_button(base, value = 'Clear', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'clear_event')  
  
b6 = widget_button(base, value = 'Desensitize', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'sensitivity_event')  
  
b7 = widget_button(base, value = 'Sensitize', $  
   uvalue = {o:o, prop:prop}, $  
   event_pro = 'sensitivity_event')  
  
b8 = widget_button(base, value = 'Quit', $  
event_pro = 'quit_event')  
; Buttons that can't be pushed after clearing:  
b = [b1, b3, b4, b5, b6, b7]   
  
; Activate the widgets.  
  
widget_control, base, set_uvalue = {prop:prop, b:b}, /realize  
  
xmanager, 'psdemo_large', base, /no_block  
  
END  

The following figure displays the output of this example:

 

Figure 7-3: User-Defined Property Sheet Example

Figure 7-3: User-Defined Property Sheet Example

To demonstrate the controls available from the WIDGET_PROPERTYSHEET, do the following and note the Selected and Changed messages in the IDL Output Log:

Click the eight buttons at the bottom of the property sheet to initiate the following events:

  IDL Online Help (March 06, 2007)