Home | Categories | Alphabetical | Classes | All Contents | [ < ] | [ > ]

Using Property Sheet Widgets


The purpose of a property sheet is to enable the user to view and edit the properties of an object subclassed from the IDLitComponent class. (All IDLgr* and IDLit* objects subclass from the IDLitComponent class.)

For example, a user may have rendered data as a surface. Using IDL's iSurface tool, the user can select the surface and bring up a property sheet that lists all of the surface's properties, including color, shading method, etc. To change the color, the user can go to the property sheet, select the color property, bring up the color picker, and select a new color. The name of the changed property is placed into an IDL event. It is in the processing of this event that the object is updated. An existing property sheet can be assigned a new component, which causes it to reload with the new list of properties and their values.

The following topics show how to use the property sheet widget with the iTool's paradigm:

Registering Properties

In order for a property associated with a component object to be included in the property sheet for that component, the property must be registered. The property registration mechanism accomplishes several things:

Groups of properties of graphical atomic objects can be registered by setting their REGISTER_PROPERTIES properties to True when the object is initialized. See the property tables for each graphical atomic object in the IDL Reference Guide.

Selecting Properties

A property sheet consists of rows and columns. The left-most column identifies the properties, and the other column or columns identify the property values of one or more objects (also known as components). A select event is generated whenever a cell containing a property name or a property value is selected by left-clicking on it using the mouse. When a single property value is clicked on, the associated property name appears indented. Only a single property value can be selected at one time. However, when the MULTIPLE_PROPERTIES keyword is set, multiple properties can be selected in a property sheet using the Ctrl key to make nonadjacent selections or using the Shift key to make adjacent selections.

Note
Setting the EDITABLE keyword to 0 (zero) allows the user to select, but not modify properties. See WIDGET_PROPERTYSHEET in the IDL Reference Guide for details.

When the property sheet is initially realized, no properties are selected by default. However a single property or multiple properties can be selected programmatically using the PROPERTYSHEET_SETSELECTED keyword to the WIDGET_CONTROL procedure.

Set the PROPERTYSHEET_SETSELECTED keyword to a string or an array of strings identifying the properties to appear selected. The strings should match valid property identifiers. When this keyword is set to an empty string or an array that contains only an empty sting, it clears all property selections. For example, the following code pre-selects two properties in a property sheet:

; Create the property sheet. 
oComp = OBJ_NEW('IDLitVisAxis') 
wPropAxis = WIDGET_PROPERTYSHEET(base, VALUE = oComp, $ 
   EVENT_PRO = 'PropertyEvent', UNAME = 'PropSheet', $ 
   /MULTIPLE_PROPERTIES) 
 
; Pre-select the color and transparency properties of  
; axis component. 
WIDGET_CONTROL, wPropAxis,  
   PROPERTYSHEET_SETSELECTED=['Color', 'Transparency'] 

Accessing Property Sheet Selection Events

The event structure (WIDGET_PROPSHEET_SELECT) provided when selection occurs contains a COMPONENT tag, an IDENTIFIER tag, and a NSELECTED tag.

{WIDGET_PROPSHEET_SELECT, ID:0L, TOP:0L, HANDLER:0L, TYPE:0L,  
   COMPONENT:OBJREF, IDENTIFIER:"", NSELECTED:0L }  

The COMPONENT tag is a reference to the object associated with the selected property value. When multiple objects (also known as components) are associated with the property sheet, this member indicates which one object had one of its property values selected. If a property (instead of a property value) is selected, the COMPONENT tag always contains an object reference to the first object, even if there are multiple objects in the property sheet. The IDENTIFIER tag uniquely identifies the property. This identifier is unique among all of the component's properties. The component and identifier can be used to obtain the value of the selected property:

isDefined = event.component-> $ 
   GetPropertyByIdentifier(event.identifier, value) 

where event is the event structure, isDefined is a 1 if the value is defined (0, otherwise), and value receives the property's value.

The NSELECTED tag returns the number of currently selected properties. When more than a single property is selected, the IDENTIFIER field holds the identifier of the first item selected. This is not the first item selected with the mouse, but the first item encountered in the property sheet definition among those which are selected. The NSELECTED tag is equivalent to calling WIDGET_INFO with the /PROPERTYSHEET_NSELECTED keyword.

Using WIDGET_INFO, it is also possible to return the identifiers of all selected properties using the /PROPERTYSHEET_SELECTED keyword. This returns a string or string array containing the identifiers of the selected properties.

; Return information about single or multiple property 
; selections.  
vNumSelected = WIDGET_INFO(event.ID, /PROPERTYSHEET_NSELECTED)       
vSelected = WIDGET_INFO(event.ID, /PROPERTYSHEET_SELECTED) 
PRINT, 'Number properties selected: ' + STRING(vNumSelected) 
PRINT, 'Selected properties: '  
PRINT, vSelected  

Controlling When Properties are Selectable

Three things that determine the appearance of a property sheet data cells. They are, in order of greatest to least precedence:

  1. Sensitivity of the entire widget - If SENSITIVE=0 for WIDGET_PROPERTYSHEET then no selection or scrolling is possible.
  2. Editability of the entire widget - If EDITABLE=0 for the property sheet (meaning it is marked as read-only), cells can be selected but cannot be changed. If EDITABLE=1 (the default value meaning properties can be selected and modified), then the editability of individual properties is controlled by their individual sensitivity values.
  3. Sensitivity of an individual property - If SENSITIVE=0 for an individual property (set using the RegisterProperty or SetPropertyAttribute methods of IDLitComponent), then the individual property cannot be selected or changed.

Changing Properties

A change event is generated whenever a new value is entered for a property. It is also used to signal that a user-defined property needs changing. The event structure (WIDGET_PROPSHEET_CHANGE) provided when a change occurs contains a COMPONENT, an IDENTIFIER, a PROPTYPE, and a SET_DEFINED tag. The COMPONENT tag contains a reference to the object associated with the property sheet. When multiple objects are associated with the property sheet, this member indicates which object is to change. The IDENTIFIER tag specifies the value of the property's identifier attribute. This identifier is unique among all of the component's properties. The PROPTYPE tag indicates the type of the property (integer, string, etc.). Integer values for these types can be found in the documentation for components. The SET_DEFINED tag indicates whether or not an undefined property is having its value set. In most circumstances, along with its new value, the property should have its 'UNDEFINED' attribute set to zero. If a property is never marked as undefined, this field can be ignored.

Although the component's object reference is included in the event structure, it can also be retrieved via the following call:

WIDGET_CONTROL, event.id, GET_VALUE = obj 

where event is the event structure and obj is the object reference of the component.

The PROPTYPE field is provided for convenience. The property type should be known implicitly based on IDENTIFIER, but can be retrieved (in integer form) by:

obj->GetPropertyAttribute, event.identifier, TYPE = type 

where obj is the object reference of the component, event is the event structure, and type represents the data type of the property. Here, the value returned in by the TYPE keyword is the same as the value of the PROPTYPE field of the widget event structure.

Properties can use their UNDEFINED attribute to show an indeterminate state (set attribute UNDEFINED = 1). This might arise after the aggregation of two or more properties. One could imagine a COLOR property representing both the border and the interior color of a polygon so that just one color property is displayed in the property sheet. When set, the chosen color would be applied to both, and then the following code could be used to mark the property as defined:

IF (event.set_defined) THEN $ 
   event.component->SetPropertyAttribute, $ 
      event.identifier, UNDEFINED = 0 
WIDGET_CONTROL, event.id, REFRESH_PROPERTY = event.identifier 

where event is the event structure.

Note
The REFRESH_PROPERTY keyword to WIDGET_CONTROL is used to refresh the property sheet. This is necessary because although the property sheet knows about its component, it does not directly change the component itself. Just as with changing properties values, the property sheet and underlying component have a clear boundary and can only affect each other through IDL statements.

Properties can also be hidden (removing them from the property sheet entirely) or desensitized (displaying the property in the property sheet, but not allowing the user to change its value). See Property Attributes for additional details.

Updating the Component

When a value has been changed in the property sheet, you can access this resulting value through the WIDGET_INFO function:

value = WIDGET_INFO(event.id, PROPERTY_VALUE = event.identifier) 

where event is the event structure. This value can then be used to update the changed property in the component object by calling its SetPropertyByIdentifier method:

event.component->SetPropertyByIdentifier, event.identifier, $ 
   value 

where event is the event structure and value is the modified property value.

User-defined Properties

User-defined properties allow IDL programmers to provide their own custom means for editing a property. One significant difference from other types of properties is that user-defined properties must have a string version of their value. This string value is stored in the USERDEF attribute of the property and must be explicitly updated. The string value is the value displayed in the property sheet. See Property Management for further discussion of user-defined properties.

Updating User-defined Properties

Like other property types, user-defined properties generate IDL property sheet change events. The difference is that the IDL event handler cannot query the property sheet for the new value. It must use some other means to determine a new value. Typically this is done through widget code, in which the user is asked to set a value, but virtually any other technique is valid.

When handling change events, determine the property's type using the PROPTYPE field of the widget event structure. Once a value has been acquired, update the component using its SetProperty method. In addition, the string version of the user-defined property's value should be updated. This is done by executing a statement similar to the following example:

eventBase.component->SetPropertyAttribute, $ 
   eventBase.identifier, USERDEF = userDefValue 

where eventBase is the event structure of the top-level-base and userDefValue is the string representing the user-defined value when the property sheet is refreshed.

Once the underlying component has been updated, the property sheet is ready to be refreshed. Execute a call to update a given property with the current value:

widget_control, propsheet, refresh_property = eventBase.identifier 

where propsheet is the widget ID of the property sheet widget and eventBase is the event structure of the top-level-base.

Property Sheet Sizing

Property sheets without a size definition (lacking a specified SCR_XSIZE or XSIZE keyword value) are naturally sized. Column widths are dependent upon the cell contents of the components. Naturally sized property sheets allow the full contents of the longest cell to be visible in a column as shown in the left-hand image in the following figure. When a size definition is provided, selecting the cell displays the list contents in a drop-down box that is wide enough for the longest item as shown in the right-hand image in the following figure.

Note
If you manually change the width of a property sheet column, natural resizing functionality is overridden. Dynamic resizing is not supported when the property sheet is refreshed or loaded with different data. Natural sizing can be recovered by destroying and recreating the property sheet.

The following elements are considered when determining column width in a naturally sized property sheet:

When a property sheet size is explicitly defined, the column width may crop the display of the full cell contents. However, when you select the cell, the full contents will be visible as follows:

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:

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

Multiple Properties Example

The following example shows how to create a property sheet for multiple components.

Enter the following text in the IDL Editor:

; ExMultiSheet.pro 
; 
; Provides an example of a property sheet that is 
; associated with more than one object. In this case, 
; multiple IDLitVisAxis objects are used, with random 
; colors and hidden cells, just for fun. 
 
PRO PropertyEvent, event 
 
IF (event.type EQ 0) THEN BEGIN   ; Value changed. 
 
   PRINT, 'Changed: ', event.component 
   PRINT, '   ', event.identifier, ': ', $ 
   WIDGET_INFO(event.id, COMPONENT = event.component, $ 
      PROPERTY_VALUE = event.identifier) 
 
ENDIF ELSE BEGIN                ; Selection changed. 
 
   PRINT, 'Selected: ' + event.identifier 
 
ENDELSE 
 
END 
 
PRO CleanupEvent, baseID 
 
WIDGET_CONTROL, baseID, GET_UVALUE = objects 
 
FOR i = 0, (N_ELEMENTS(objects) - 1) DO $ 
   OBJ_DESTROY, objects[i] 
 
END 
 
PRO ExMultiSheet_event, event 
 
ps = WIDGET_INFO(event.id, $ 
   FIND_BY_UNAME = 'PropSheet') 
 
geo_tlb = WIDGET_INFO(event.id, /GEOMETRY) 
 
WIDGET_CONTROL, ps, $ 
   SCR_XSIZE = geo_tlb.xsize - (2*geo_tlb.xpad), $ 
   SCR_YSIZE = geo_tlb.ysize - (2*geo_tlb.ypad) 
 
END 
 
PRO ExMultiSheet 
 
tlb = WIDGET_BASE(/COLUMN, /TLB_SIZE_EVENTS, $ 
   KILL_NOTIFY = 'CleanupEvent') 
 
; Create some columns. 
 
oComp1 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s1, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s7, 3)*256) 
oComp2 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s2, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s8, 3)*256) 
oComp3 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s3, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s9, 3)*256) 
oComp4 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s4, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s10, 3)*256) 
oComp5 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s5, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s11, 3)*256) 
oComp6 = OBJ_NEW('IDLitVisAxis', $ 
   COLOR = RANDOMU(s6, 3)*256, $ 
   TEXT_COLOR = RANDOMU(s12, 3)*256) 
 
oComps = [oComp1, oComp2, oComp3, $ 
   oComp4, oComp5, oComp6] 
 
WIDGET_CONTROL, tlb, SET_UVALUE = oComps 
 
; Hide some properties. 
 
oComp2->SetPropertyAttribute, 'color', /HIDE 
oComp2->SetPropertyAttribute, 'ticklen', /HIDE 
oComp5->SetPropertyAttribute, 'ticklen', /HIDE 
 
; Create the property sheet. 
prop = WIDGET_PROPERTYSHEET(tlb, $ 
   UNAME = 'PropSheet', $ 
   VALUE = oComps, $ 
   FONT = 'Courier New*16', $ 
   XSIZE = 100, YSIZE = 24, $ 
   /FRAME, EVENT_PRO = 'PropertyEvent') 
 
; Activate the widgets. 
 
WIDGET_CONTROL, tlb, /REALIZE 
 
XMANAGER, 'ExMultiSheet', tlb, /NO_BLOCK 
 
END 

Save the program as ExMultiSheet.pro, then compile and run it. A property sheet displaying the properties of six axes is displayed:

The gray boxes indicate properties that have been hidden. To remove the gray boxes, comment out the code after the following comment:

; Hide some properties. 

The text is displayed at 16 points in the Courier New font. To view the property sheet with the text displayed in the default size and font, comment out the following segment of the property sheet creation code:

FONT = "Courier New*16", $ 

To see the text displayed in a font and size of your choosing, edit the same segment to include a different font name and size.


Home | Categories | Alphabetical | Classes | All Contents | [ < ] | [ > ]