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:
To demonstrate the controls available from the WIDGET_PROPERTYSHEET, do the following and note the Selected and Changed messages in the IDL Output Log:
- Change the Boolean field to False.
- Select a new Color from the color picker.
- Select a new "numberness" value in the User Defined field.
- Change the Integer field to a new value. Note that this field has been restricted to integers in the range -100 to 100.
- Change the first Floating Point field to a new value by moving the slider.
- Change the second Floating Point field to a new value by editing the text. Note that this field has been restricted to floating point numbers in the range -1.0 to 1.0.
- Change the Line Style field to a new style.
- Change the Line Thickness field to a new thickness.
- Select a new symbol in the Symbol field.
- Select a new string from the String List.
Click the eight buttons at the bottom of the property sheet to initiate the following events:
- The Refresh button loads the data specified in
refresh_eventinto the property sheet, using the REFRESH_PROPERTY keyword to WIDGET_CONTROL. - The Reload button reloads the data specified in
LoadValuesinto the property sheet, using the SET_VALUE keyword to WIDGET_CONTROL. - The Hide Color button runs
hide_event, which sets the HIDE attribute for the color property to one. - The Show Color button runs
show_event, which sets the HIDE attribute for the color property to zero. - The Clear button runs
clear_event, which creates a new set of empty objects, deactivating all but the Reload button. - The Desensitize button runs
sensitivity_event, which deactivates the displayed fields. - The Sensitize button runs
sensitivity_event, which reactivates the displayed fields. - The Quit button runs
quit_event, which destroys the top-level base and ends the program.
