View this PageEdit this PageAttachments to this PageHistory of this PageHomeRecent ChangesSearch the SwikiHelp Guide
Hotspots: Admin Pages | Turn-in Site |
Current Links: Cases Final Project Summer 2007

"1, 2, Combo" boxes and random GUI tips

Hello, my name is Jeffro and I am here to teach you the "1, 2, combo" that will knock all of those pesky combo boxes out when trying to do your UI. I will also teach you some "cheap" tricks to get your GUI to drawing itself. Anyways, lets talk combo boxes!

Combo Boxes

First, what are combo boxes?

Well, combo boxes are input fields that have a restrictive set of valid entries. Let's say that you have a collection of something like scenarios and you want a way to select one of these scenarios, you could use a combo box with the entries as these scenarios. When the user selects an entry, you could display information about that particular selection in some form.

Ok, so how do I use them?

Well before I start explaining combo boxes, let me point out a wonderful resource about Combo boxes and GUI developing in general: This guide has a lot of information about the various widgets and developing strategies for GUIs.

A combo box is a widget that you can use so, lets take a look at the widget's aspect:

Uploaded Image: combo.jpg
Figure 1.1 Combo Box Widget Aspect

You will notice that a lot of fields are filled in. I will explain why each of the fields are there and what they do.

The Entries (attributes: Type, Choices)

First of all, Combo boxes needs some sort of list to form its entries. There are a lot of predefined types that this list can be. You can see these types by clicking on the drop down menu for the attribute "Type". I will focus on objects since Smalltalk is object oriented and most of the time you will be using arbitrary object lists. Like a lot of widgets, we can defined a aspect and an id, which in the picture I choose "scenario" since the list contains scenarios and I want to choose one scenario from this list. Now that we know what types the combo box can contain, we need to specify a list. The attribute "Choices:" is a message that it calls to the application that retrieves a list of some sorts. The following code is associated with "#retrieveScenarioList":
	"Retrieves the scenario list for the combo box."

	^ stepperService retrieveScenarioList asValue.

In the code, I retrieve a list from something called a stepperService. Main point of having this method is that it returns a list of some sort. Note, make sure to call asValue. A lot of your GUI code uses ValueHolders and asValue creates a ValueHolder with the list as the value. So, now that we got our list we need to figure out ways to display and retrieve the data selected by the user.

Displaying and Selecting (attributes: Read, Print)

Since we are using arbitrary lists, we need a way to format each entry in our list. The attribute that takes care of that part is the "Print". For our example I used the "#scenarioToString:". Notice the ":" at the end of the value, the value you supply for "Print" must accept a parameter which is the object or entry of the list that you used for the combo box. Since I used a scenario list, I need to accept a scenario object. So, the code from my "#scenarioToString:" are as follows:
scenarioToString: aScenario
	"Returns the name of the scenario."

	^ (aScenario value) name.

It just so happens that the object that I am accepting is a ValueHolder as well. So before I can assess the Scenario object, I have to pass the ValueHolder the "#value" message. Then, a String representation of the object would be its name in my case. Also, note that your method must return a String. This is what the widget uses to format each entry. Hence, when you hit the drop down menu, you can see each scenario by its name. Another note is that if you don't use a ValueHolder as a list, you might not be passed a ValueHolder for this method. You will have to do some testing to see what exactly you are passed and it might take two tries to get it correct. Congrats, the user can now see the various entries of your combo box list. However, we want a way to retrieve the selection after the user picks an entry. You would think that you need to do nothing else and you can simply grab the aspect in your methods. You couldn't be further from the truth if it was like brick trying to be Jupiter. OK, maybe not that far, but you need one more thing before you are done. Combo Boxes keeps tracks of strings, so it needs to have some way to retrieve an object after the user selects one of the Strings in the list. For this, we need to take a look at the attribute "Read". Notice again my value is "#stringToScenario:". The method you will write needs to accept a string and return the object chosen in some way. Let's look at the code associated with "#stringToScenario:" in order to make sense of what is happening:
stringToScenario: aString
	"Converts a string into a scenario."

	| scen |
	scen := stepperService findScenarioByName: aString.

The method accepts a String. From here, I have a method in stepperService that tries to find the corresponding Scenario with a string. After finding, this value I return it. You can chose your object in a number of ways. For instance if you saved that list you used for your combo box, you can iterate through it and find the object that corresponds with that string value in some way. After you finish this last step, your combo box will work as expected. If you define an aspect for the combo box, you can simply call it in your methods to access your selection. You add an "#updateSomething" message for the "Update" attribute that so may widgets have.

GUI Cheap Tricks

We finished looking at GUI Combo Boxes. After experimenting with what you can do with GUIs, you can make individual components update their displays without using all of that complicated AspectAdapters and other Adapters (although you should learn how they work). Just like Java components, each display component in Smalltalk has a "#displayOn:" message which receives a GraphicsContext. For instance, lets say that your selection lists aren't redisplaying when you want to them too or after a certain event. You can quickly cheat and make it draw by doing the following:
| cardsWidget |
	cardsWidget := self widgetAt: #cardList.
	cardsWidget displayOn: cardsWidget graphicsContext.

The code grabs the widget called cardList, which is a selection list that holds cards of some sort. After the cardWidget is retrieved, the "#displayOn:" message is sent to the object with a graphicsContext. Note: I call cardsWidget graphicsContext, this grabs the graphicsContext of itself. The graphicsContext is already defined because it is a widget.

Hopefully, this guide has help you become more familiar with combo boxes.

Links to this Page