Programmer Reference : Common Widgets : Extended widgets : Example: a primitive extended widget
Example: a primitive extended widget
Two example extended widgets are provided in the next two sections. The first, below, is a subclass of CwExtendedPrimitive, and the second, on page Example: a composite extended widget, is a subclass of CwExtendedComposite. The prefix 'Cew' is used to differentiate these new widgets from basic widgets. For simplicity, the examples do not include robust error-checking, nor does each widget provide a complete set of resources.
The CewEntryField widget, shown below, has a label on the left and a text box on the right. It allows a user to enter text into its text box, and it invokes a valueChanged callback if a new value is present when the user either hits the tab key or clicks on a different widget.
The extended widget is implemented using a CwForm as the primary widget with CwLabel and CwText children. A losingFocus callback on the CwText enables the widget to test entered data, and possibly call any registered valueChanged callbacks.
Extended widget
CwExtendedPrimitive subclass: #CewEntryField
instanceVariableNames: 'label value valueChangedCallback labelWidget textWidget '
classVariableNames: ''
poolDictionaries: ''
createPrimaryWidget: theName parent: parent argBlock: argBlock
"Private - Create and answer the basic widget that is the root of the
widget hierarchy for the receiver's widget system."
^self parent
createForm: theName, 'Form'
argBlock: argBlock
createWidgetSystem
"Private - Create the children of the receiver's primary widget which form the
widget hierarchy."
| pw |
pw := self primaryWidget.
self labelWidget:
(pw
createLabel: pw name , 'Label'
argBlock: [:w | w labelString: self label])
manageChild.
self textWidget:
(pw
createText: pw name , 'Text'
argBlock: [:w |
w
borderWidth: 1;
value: self value])
manageChild.
self textWidget
addCallback: XmNlosingFocusCallback
receiver: self
selector: #losingFocus:clientData:callData:
clientData: nil.
"Add form attachments for the two children."
self labelWidget
setValuesBlock: [:w |
w
topAttachment: XmATTACHFORM;
leftAttachment: XmATTACHFORM;
rightAttachment: XmATTACHNONE;
bottomAttachment: XmATTACHFORM].
self textWidget
setValuesBlock: [:w |
w
topAttachment: XmATTACHFORM;
leftAttachment: XmATTACHWIDGET;
leftWidget: self labelWidget;
rightAttachment: XmATTACHFORM;
bottomAttachment: XmATTACHFORM].
initializeResources
"Private - Set the default extended widget resource values. This is sent
during create with isCreated set to false. All extended resource
variables should be initialized to default values here."
label := String new.
value := String new.
initializeAfterCreate
"Private - Perform any widget-specific post-create initialization."
self primaryWidget
horizontalSpacing: 4;
verticalSpacing: 4;
borderWidth: 1.
"Resources that involve the children of the primary widget have to be set
after the children are created."
self labelWidget labelString: label.
self textWidget value: value.
label
"Answer the value of the label resource.
Resource type: String
Default setting: ''
Resource access: CSG
Description:
Specifies the string for the CewEntryField's label.
This label is to the left of the CewEntryField's text box."
^label
label: resourceValue
"Set the value of the label resource to resourceValue.
Resource type: String
Default setting: ''
Resource access: CSG
Description:
Specifies the string for the CewEntryField's label.
This label is to the left of the CewEntryField's text box."
label := resourceValue.
self isCreated
ifTrue: [labelWidget labelString: resourceValue]
value
"Answer the value of the value resource.
Resource type: String
Default setting: '
Resource access: CSG
Description:
Specifies the string for the CewEntryField's value.
This value is displayed in the CewEntryField's text box if
set using the #value: message, or if a valid string followed
by a tab key is entered by the user.
Note that while the user is typing, the string displayed in the
text box might not be the same as the CewEntryField's value."
^value
value: resourceValue
"Set the value of the value resource to resourceValue.
Resource type: String
Default setting: '
Resource access: CSG
Description:
Specifies the string for the CewEntryField's value.
This value is displayed in the CewEntryField's text box if
set using the #value: message, or if a valid string followed
by a tab key is entered by the user.
Note that while the user is typing, the string displayed in the
text box might not be the same as the CewEntryField's value."
value := resourceValue.
self isCreated
ifTrue: [textWidget value: resourceValue]
valueChangedCallback
"Private - Answer the value of valueChangedCallback."
valueChangedCallback isNil
ifTrue: [self valueChangedCallback: OrderedCollection new].
^valueChangedCallback
valueChangedCallback: resourceValue
"Set the value of the XmNvalueChangedCallback resource to resourceValue.
Resource type: OrderedCollection of CwCallbackRec
Default setting: OrderedCollection new
Resource access: C
Callback reason: XmCRVALUECHANGED
Calldata structure: CwValueCallbackData
Description:
Specifies the list of callbacks that is called when the value
of the CewEntryField has changed. The reason sent by the
callback is XmCRVALUECHANGED. The structure returned
by this callback is CwValueCallbackData."
valueChangedCallback := resourceValue.
labelWidget
"Private - Answer the value of labelWidget."
^labelWidget
labelWidget: aCwLabel
"Private - Set the value of labelWidget to aCwLabel."
labelWidget := aCwLabel.
textWidget
"Private - Answer the value of textWidget."
^textWidget
textWidget: aCwText
"Private - Set the value of textWidget to aCwText."
textWidget := aCwText.
losingFocus: widget clientData: clientData callData: callData
"Private - Process a losing focus callback for the primary widget."
| newValue |
newValue := self textWidget value.
"If the new value is different, invoke the entryField widget's
valueChanged callback."
self value = newValue
ifTrue: [
self
value: newValue;
callCallbacks: XmNvalueChangedCallback
callData: (CwValueCallbackData new value: newValue)].
Using the CewEntryField primitive extended widget
The following code creates a CewEntryField instance, sets its name and label resources inside the create argBlock, and hooks a valueChanged callback to it. The new widget is shown in the diagram at the beginning of this section, on page Example: a primitive extended widget.
| shell entryField |
shell := CwTopLevelShell
createApplicationShell: 'CewEntryField Test'
argBlock: nil.
entryField := CewEntryField
createManagedWidget: 'entryField'
parent: shell
argBlock: [:w |
w
label: 'Name :';
value: 'Your name here'].
entryField
addCallback: XmNvalueChangedCallback
receiver: self
selector: #valueChanged:clientData:callData:
clientData: nil.
shell realizeWidget.
valueChanged: widget clientData: clientData callData: callData
"Display the new value on the transcript."
Transcript cr; show: 'Value changed to: ' , callData value printString.
The CewEntryField class can be subclassed to provide a slightly different extended widget by simply overriding one method, as in the following class definition for CewNumericEntryField:
CewEntryField subclass: #CewNumericEntryField
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
losingFocus: widget clientData: clientData callData: callData
"Private - Process a losing focus callback for the primary widget."
| newValue |
newValue := self textWidget value.
"Verify that the new value string represents a number.
If it doesn't, reset the text widget and return."
(newValue notEmpty and: [newValue conform: [:c | c isDigit]])
ifFalse: [^self value: value].
"If the new value is different, invoke the entryField widget's
valueChanged callback."
self value = newValue
ifTrue: [
self
value: newValue;
callCallbacks: XmNvalueChangedCallback
callData: (CwValueCallbackData new value: newValue)]
Last modified date: 12/22/2017