The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Fun With Forms

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
Fun With Forms Posted: Jul 27, 2007 12:55 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Fun With Forms
Feed Title: Pollock
Feed URL: http://www.cincomsmalltalk.com/rssBlog/pollock-rss.xml
Feed Description: Pollock - the next VW GUI
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Pollock

Advertisement

Today we look at the Form, and the two basic ways to use it.

Design

We'll be making three UserInterface. We'll start with one we'll name FormWork, and it will have a method that creates a Form object, and adds panes to it, then we'll call that twice giving each a different position on the window.

Then we'll create a UserInterface we'll name AddressUserInterface, which will have a singe set of panes on it. We'll then create a UserInterface named MoreFormWork which will load the AddressUserInterface into two forms.

Here is our starting UserInterface subclass:

	Smalltalk defineClass: #FormWork
		superclass: #{Widgetry.UserInterface}
		indexedType: #none
		private: false
		instanceVariableNames: ' '
		classInstanceVariableNames: ''
		imports: 'private Widgetry.*'
		category: '(none)'

Dress Making

A Form is in essence a grouping of panes gathered into a container. The purpose of a Form is mostly for reuse. You can create many instances of a Form, and place them in a single user interface, or use a Form in many UserInterfaces.

Our example today is a simple set of address fields. Some Labels and InputFields to allow the entering of a street address, city, state and zip. I always like this example, because this is the basis of a very common pattern in some everyday application development: Ship To and Bill To addresses. With the Form, we'll be able to create a generic address form, and be able to use it for ship to and bill to.

Our first example as implied in the Design section, is a method that answers a Form, with all its parts all laid out. This is what that looks like:

	addressForm

		| form label inputField |
		form := Form new.
		label := DisplayLabel string: 'Street'.
		label frame extent: 30 @ 25.
		form addComponent: label.
		inputField := InputField new.
		(inputField frame)
			inset: 33 @ 0;
			extent: 140 @ 25.
		form addComponent: inputField.
		label := DisplayLabel string: 'City'.
		(label frame)
			inset: 0 @ 28;
			extent: 30 @ 25.
		form addComponent: label.
		inputField := InputField new.
		(inputField frame)
			inset: 33 @ 28;
			extent: 35 @ 25.
		form addComponent: inputField.
		label := DisplayLabel string: 'State'.
		(label frame)
			inset: 70 @ 28;
			extent: 25 @ 25.
		form addComponent: label.
		inputField := InputField new.
		(inputField frame)
			inset: 97 @ 28;
			extent: 25 @ 25.
		form addComponent: inputField.
		label := DisplayLabel string: 'Zip'.
		(label frame)
			inset: 124 @ 28;
			extent: 15 @ 25.
		form addComponent: label.
		inputField := InputField new.
		(inputField frame)
			inset: 142 @ 28;
			extent: 31 @ 25.
		form addComponent: inputField.
		^form

You may notice I'm reusing the same temporary variables over and over here. For this posting, we're concentrating on Forms and how to use them. In the future we'll talk about how to access panes in a Form.... For a hint though, look at #paneAt:.

Now, in our #createInterface method, we'll get that form, give it a frame, and put it in our window. If you look at my layouts, you'll see that the total width is 173. So we'll make our form have a width of 175 because I'm fond of that rounded number, and the total height is 53, and again, I'll round it out to 55.

	createInterface

		| addressForm |
		addressForm := self addressForm.
		(addressForm frame)
			inset: 10 @ 10;
			extent: 175 @ 55.
		self addComponent: addressForm

Note that we gave our Form an inset of 10 @ 10... Here is what this looks like when we execute FormWork open:

Yeah, I know, not the most compelling layout or sizes, but you get the picture.

Pig Iron

Now we'll add a second instance of our address form, below the first:

	createInterface

		| addressForm |
		addressForm := self addressForm.
		(addressForm frame)
			inset: 10 @ 10;
			extent: 175 @ 55.
		self addComponent: addressForm.
		addressForm := self addressForm.
		(addressForm frame)
			inset: 10 @ 75;
			extent: 175 @ 55.
		self addComponent: addressForm

And here is what it looks like after I've played with the input fields some:

Kenetic Energy

For our second example, we'll first create a whole new UserInterface we'll name AddressUserInterface, and make instance variables for all those input fields:

	Smalltalk defineClass: #AddressUserInterface
		superclass: #{Widgetry.UserInterface}
		indexedType: #none
		private: false
		instanceVariableNames: 'street city state zip'
		classInstanceVariableNames: ''
		imports: 'private Widgetry.*'
		category: '(none)'

Now we'll take our #addressForm method from our FormWork class, and make it into a #createInterface method, using instance variables for the InputFields instead of reusing the inputField temporary. Yes, I know this is reuse by copy/paste... so sue me.

Note, we don't use the form in this method, we just add components directly to the user interface itself:

	createInterface

		| label |
		label := DisplayLabel string: 'Street'.
		label frame extent: 30 @ 25.
		self addComponent: label.
		street := InputField new.
		(street frame)
			inset: 33 @ 0;
			extent: 140 @ 25.
		self addComponent: street.
		label := DisplayLabel string: 'City'.
		(label frame)
			inset: 0 @ 28;
			extent: 30 @ 25.
		self addComponent: label.
		city := InputField new.
		(city frame)
			inset: 33 @ 28;
			extent: 35 @ 25.
		self addComponent: city.
		label := DisplayLabel string: 'State'.
		(label frame)
			inset: 70 @ 28;
			extent: 25 @ 25.
		self addComponent: label.
		state := InputField new.
		(state frame)
			inset: 97 @ 28;
			extent: 25 @ 25.
		self addComponent: state.
		label := DisplayLabel string: 'Zip'.
		(label frame)
			inset: 124 @ 28;
			extent: 15 @ 25.
		self addComponent: label.
		zip := InputField new.
		(zip frame)
			inset: 142 @ 28;
			extent: 31 @ 25.
		self addComponent: zip.

If we execute AddressUserInterface open, here is what we see:

You'll notice that the widgets are all pushed up to the top and left. That is what we want.

Abracadabra

Now we create a new UserInterface subclass which will use our AddressUserInterface twice:

	Smalltalk defineClass: #MoreFormWork
		superclass: #{Widgetry.UserInterface}
		indexedType: #none
		private: false
		instanceVariableNames: 'billTo shipTo'
		classInstanceVariableNames: ''
		imports: 'private Widgetry.*'
		category: '(none)'

Here is how we use our prior AddressUserInterface for our forms:

	createInterface

		billTo := Form new.
		billTo addComponentsFromClass: AddressUserInterface.
		(billTo frame)
			inset: 10 @ 20;
			extent: 175 @ 55.
		self addComponent: billTo.
		shipTo := Form new.
		shipTo addComponentsFromClass: AddressUserInterface.
		(shipTo frame)
			inset: 10 @ 100;
			extent: 175 @ 55.
		self addComponent: shipTo.

Here is what it looks like when we execute MoreFormWork open:

The method #addComponentsFromClass: takes a UserInterface, and collects all of the panes in it, and adds them to the Form.

You might now be able to imagine how with this facility, you can build up UserInterfaces from other UserInterfaces and so on.

Extra Credit

We'll add a few GroupBoxes:

	createInterface

		| groupBox |
		groupBox := GroupBox string: 'Bill To:'.
		(groupBox frame)
			inset: 5 @ 5;
			extent: 185 @ 75.
		self addComponent: groupBox.
		groupBox := GroupBox string: 'Ship To:'.
		(groupBox frame)
			inset: 5 @ 85;
			extent: 185 @ 75.
		self addComponent: groupBox.
		billTo := Form new.
		billTo addComponentsFromClass: AddressUserInterface.
		(billTo frame)
			inset: 10 @ 20;
			extent: 175 @ 55.
		self addComponent: billTo.
		shipTo := Form new.
		shipTo addComponentsFromClass: AddressUserInterface.
		(shipTo frame)
			inset: 10 @ 100;
			extent: 175 @ 55.
		self addComponent: shipTo.

This will make it ready for next time when we have fun with TabControls...

Isn't that pretty?

And So It Goes
Sames

Read: Fun With Forms

Topic: Sports under a Cloud Previous Topic   Next Topic Topic: Version Control Questions

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use