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 6-3: User-Defined Property Sheet Example

wid_prop_large.gif

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: