Tuesday, January 25, 2011

Pharo GUI with Polymorph

I've written a tiny address book to prepare a screencast on Polymorph basis. If you want to look at it:
Gofer it
 squeaksource: 'Pharocasts';
 package: 'ContactManager';
 load.
 
(Smalltalk at:#ContactListEditor) open.


Start by looking how the contact list is built:
ContactListEditor>>open
  |builder content|
  builder := UITheme builder.
  content := builder newColumn: {   
        builder 
                newListFor: self   
                list: #contacts
                selected: #contactSelectedIndex
                changeSelected: #contactSelectedIndex:
                help: 'contacts'.
        builder newRow: {
                builder newButtonFor: self 
                        action: #addButtonClick 
                        label: 'Add' 
                        help: 'Create a new contact'.
                builder newButtonFor: self 
                        action: #removeButtonClick 
                        getEnabled: #hasSelectedContact 
                        label: 'Remove' 
                        help: 'Remove selected contact'.
                builder newButtonFor: self 
                        action: #editButtonClick 
                        getEnabled: #hasSelectedContact 
                        label: 'Edit' 
                        help: 'Edit selected contact'  }}.
   
  (content openInWindowLabeled: 'Contacts') extent: 400@500.
#newRow: and #newColumn: are an easy way to align elements on the window.

When the Add button is clicked, message #addButtonClick is sent on the ContactListEditor object:
ContactListEditor>>addButtonClick
  |newContact|
  newContact := Contact new.
 
  ContactEditor new
        contact: newContact;
        onOK: [ Contact database add: newContact.  
                selectedContactIndex := Contact database size.
                self 
                        changed: #contacts;
                        changed: #hasSelectedContact];
        openModal.
The closure given to onOK: adds the new Contact and tells the view to refresh components which depends on #contacts and #hasSelectedContact selectors - that means the contact list and the Remove and Edit buttons.

ContactEditor defines a modal dialog to edit the firstName and lastName of a Contact:
ContactEditor>>openModal
  |builder dialog content firstName|
  
  builder := UITheme builder.
  content := (builder newLabelGroup: {
                'First name' -> (
                       firstName := (builder
                         newTextEntryFor: contact
                         getText: #firstName
                         setText: #firstName: 
                         help: 'Enter the first name of the contact')
                       acceptOnCR: false;
                       minWidth: 200).
                'Last name' -> (
                       (builder
                          newTextEntryFor: contact 
                          getText: #lastName 
                          setText: #lastName: 
                          help: 'Enter the last name of the contact')
                        acceptOnCR: false;
                        minWidth: 200) }).
 
  dialog := builder 
              newPluggableDialogWindow:'Edit contact' 
              for: content.
  dialog rememberKeyboardFocus: firstName.
  builder openModal: dialog.
 
  dialog cancelled ifFalse: [self doOnOK].
From Gary Chambers (and thanks !):

Disabling the acceptOnCR for each text frield allows the default dialog handling for the return key (defaults to OK).

Normally the initial keyboard focus for a dialog is the default button, if specified. Remembering the first name field prior to opening will give that field focus.


Now it should be easier to understand Polymorph examples found in
UITheme class>>exampleBasicControls and friends (in examples protocol).

No comments:

Post a Comment