The absolute beginners guide - Part VI - for gnu-smalltalk/gtk (RAD with gnu smalltalk, gtk and glade)
After I had some issues with the planned subject of the next guide, I switched - for an example - to glade and would like to show, how you can do RAD with glade and gnu-smalltalk. It's really easy and fast, and you won't blow up your source-code with the complete gui-creation stuff. As an example I picked a password-generator, because I frequently have to set passwords for different user etc. in the company I work for.

| Might be updated in the future... |
|---|
| Some glade and GtkBuilder issues: |
|---|
So, after all the above is made clear, let's start with the example.
I decided to break the application into a model and the view. So we need a class, which provides the password generation method, which could than be called from the gui. Here it is, with the idea from Samuel Montgomery-Blinn and his blog-post: http://smalltalk.gnu.org/blog/sblinn/fun-md5-and-random.
Object subclass: Model [
| chars charsLength |
Model class >> new [
^super new init
]
init [
chars := '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
charsLength := chars size
]
createPassword: length [
| returnValue |
"This code is directly from: http://smalltalk.gnu.org/blog/sblinn/fun-md5-and-random"
returnValue := String new: length.
1 to: length do: [:x|
returnValue at: x put: (chars at: (Random between: 1 and: charsLength))
].
^returnValue
]
]
Then I created with glade the user interface and saved it as a GtkBuilder project. This gui has a menubar with an exit and about menuitem, 2 entry fields for selecting the length of the password and an output field for displaying the generated password, and a button, which starts the generation of the password.
(see the code of the GtkBuilder xml-file at the end of this post.)
Then I start to coding the gui-part.
Therefore I created a new Object with the name Pwgen and initialized the gui afterwards. For the initialization, I have to instantiate the GtkBuilder class, call the method addFromFile: with the name of the generated glade-project file and connect instance variables to all the fields where I want to have access to, while running the application. And, I have of course connect the signals where I'm interested in to methods in my app. The rest is already explained in one of the previous blog-posts.
Object subclass: Pwgen [
| model window lengthField outputField |
Pwgen class >> open [
^super new initialize show
]
initialize [
| builder error |
model := Model new.
(builder := GTK.GtkBuilder new)
addFromFile: 'pwgen.glade' error: error.
(window := builder getObjectAsWindow: 'window')
connectSignal: 'delete' to: self selector: #delete:event:data:;
connectSignal: 'destroy' to: self selector: #destroy:data:.
(builder getObjectAsToolItem: 'menuExit') connectSignal: 'activate' to: self selector: #menuExit.
(builder getObjectAsToolItem: 'menuAbout') connectSignal: 'activate' to: self selector: #menuAbout.
lengthField := builder getObjectAsEntry: 'entryLength'.
outputField := builder getObjectAsEntry: 'entryOutput'.
(builder getObjectAsButton: 'button')
connectSignal: 'clicked' to: self selector: #buttonClicked:data:.
]
show [
window showAll
]
delete: object event: event data: data [
window destroy
]
destroy: object data: data [
GTK.Gtk mainQuit
]
menuExit [
GTK.Gtk mainQuit
]
menuAbout [
(GTK.GtkAboutDialog new)
setVersion: '0.1';
setLicense: 'See the license under www.gnu.org';
setWebsite: 'http://smalltalk.gnu.org';
setComments: 'a password generation utility, written in GNU-smalltalk!';
setProgramName: 'Pwgen.st';
run; destroy
]
showError: message [
(GTK.GtkMessageDialog
new: window
flags: GTK.Gtk gtkDialogDestroyWithParent
type: GTK.Gtk gtkMessageError
buttons: GTK.Gtk gtkButtonsClose
message: message)
setTitle: 'Pwgen Error!';
run; destroy
]
buttonClicked: object data: data [
| length |
length := lengthField getText.
(length size = 0) ifTrue: [ self showError: 'You have to enter a password length' ]
ifFalse: [ (length asInteger > 12) ifTrue: [ self showError: 'The password length should be less than 13' ]
ifFalse: [ outputField setText: (model createPassword: (length asInteger)) ]
]
]
]
| As explained earlier: |
|---|
Namespace current: GTK [
GtkBuilder extend [
getObjectAsWindow: name [
<cCall: 'gtk_builder_get_object' returning: #{GtkWindow}
args: #( #self #string )>
]
getObjectAsToolItem: name [
<cCall: 'gtk_builder_get_object' returning: #{GtkToolItem}
args: #( #self #string )>
]
getObjectAsEntry: name [
<cCall: 'gtk_builder_get_object' returning: #{GtkEntry}
args: #( #self #string )>
]
getObjectAsButton: name [
<cCall: 'gtk_builder_get_object' returning: #{GtkButton}
args: #( #self #string )>
]
]
]
That's it.
And a huge saving, instead of writing the gui-code by yourself.
Of course, you have to load the package 'GTK' before running this script and call:
GTK.Gtk gstGtkInit. Pwgen open. GTK.Gtk main
but that's the same as in the examples from the last days.
Happy coding,
Joachim.

I think having multiple methods is not necessary. Just use #getObject:, it uses #{GTK.GObject} and the bindings will assign the correct class automatically. It would be a bug otherwise.
Paolo
Hello,
this one was/is very instructive to me.
I could replicate your example using Glade 2.12 and the conversion utility gtk-builder-convert. I've put your .st codes into separate files, made a loading script and could finally run it successfully.
I have two problems though. First, the menu options don't call their handlers, at least there is no visible respond and second, the error box doesn't work. It shows up with the correct title, but it has no contents.
Anyway, it's another great big step into scripting the Gnome desktop from Smalltalk and I'll definitely stay tuned. Upto now, I've done this kind of work using Tcl/Tk (a very flexible tool) and it's 'Gnocl' extention, but I'd like to ascend to Smalltalk for lots of reasons ;)
Thanks for the tutorials.
My pleasure! And even nicer if someone is reading them!
Regards,
Joachim.