Ruby/GTK+ Development in SliTaz: Part II
Last time, we got off to a flying start with a simple desktop application powered by Ruby. We shall run through completing the wizard with a simple selector widget (a spinner) and displaying that result in the final page. This is just to use one of the many widgets, show off the wizard and how to do some magic in it.
Before we get back into Glade³, you may notice a small ‘feature’ in the wizard: it’s fixed at the introductory page! This really a feature; as a wizard, we must flag each page as complete before being allowed to move on. But how can we do this?
Enter, Ruby!
You may have noticed Gladex created second file, the “callbacks” file no less. This is where the UI and code come together; this is where we can work out if the page is complete. At first this file is more or less empty, the only code here is a bizarre-looking constructor with a puts statement inside:
def init_callbacks(xmltree)
$tree = xmltree
puts "initialize"
end
The clue this gives us is indeed the puts statement because, when the program is run from a terminal, this initialize can be seen. In fact, the main class file uses this line:
init_callbacks(@glade)
We need to add callbacks from the Glade³ file to Ruby code. This is where it all ties together! Each event that may occur can be associated with a method. Each mouse click, movement, selection or any other event can trigger a method in the callbacks file.
Before You Start, Know How To Stop
One interesting feature you may notice is that we cannot yet exit the wizard without killing it from the terminal (Ctrl+C). Okay, that’s not a feature at all, it’s just darned annoying. In the metaphorical bug-tracker, that’s probably MUSTFIX. To do so, we should attach a callback to the Apply button; similar to before:
- Ensure the main window is selected in Glade³.
- In the Signals tab of Properties area, open GtkAssistant and select apply.
- Create a name for the method as the Handler, I have chosen quit_app.
- Back in the callbacks file, create this method. There’s not much to it as we can just quit straight-away, for now:
def quit_app()
Gtk.main_quit
end
That should be fairly readable; all that is needed to note is that it comes directly from the Gtk module, and that doesn’t really matter.
Go, Go, Go!
The above task shows how the Glade³ file links with Ruby code; it is fairly evident that Ruby/Gtk programs truly are powered by Ruby. Now we can go on to do more with the program. The first thing we should do is sate when we can proceed from a page. This is done by ‘flagging’ the page as complete and allowing the Next button to become active, for now it will be as we load each page:
- Ensure the main window is selected.
- In the Signals tab of Properties area, open GtkWidget and select configure-event.
- Create a name for the method as the Handler, I have chosen prepare_page as we shall use it with every page.
- Repeat the previous step for the GtkAssistant > prepare signal.
- Back in the callbacks file, create this method. As we will use it on every page, it can be quite generic, without much logic:
def prepare_page()
curr = @glade["assistant1"].get_nth_page(@glade["assistant1"].current_page)
@glade["assistant1"].set_page_complete(curr, true)
end
Hopefully that isn’t too complicated; it first picks the nth page, in this case the first, before marking it complete. Yes, we could push that into one line but would forsake readability. If we run the wizard, we should be able to jump through the pages!
How Do I Love Thee? Let Me Count The Ways
True, there’s not much to the pages. Let’s change that by adding a spinner or two to the page. If you’re new to GTK+ design, everything is placed in a container widget, usually a horizontal or vertical ‘box’. This box acts like a stack in which objects are… well, stacked. Each slot can house only one object, though.
At present, each page is made up of a label. Let’s delete the second one to reveal an empty, grey area. After selecting the horizontal box from the palette, click in this grey area to place it. We’ll use the default 3 slots in the box, inside the first and last we can put a label. Change the text of these to something like:
- Select from the spinners the first and last lines to display.
- Click ‘Next’ to show the poem.
Perhaps a slight give-away as to what the final page will contain!
Boxes can be put inside boxes; by placing a vertical box in the second slot, we will house two spinners. You can play with their and any other object’s appearance with the ‘Packing’ tab in the properties. Lets set the upper and lower limits of the counter to zero and fourteen, as the lower and upper limit respectively.
The result is just around the corner (quite literally) as we create the lines of the poem to display. There are a number of ways to do this but we shall use a simple one: remove the label and replace it with another widget, a text view area. Set the text on this to the whole poem. Just copy the following in to the text view properties editor:
How do I love thee? Let me count the ways.
I love thee to the depth and breadth and height
My soul can reach, when feeling out of sight
For the ends of Being and ideal Grace.
I love thee to the level of everyday’s
Most quiet need, by sun and candle-light.
I love thee freely, as men strive for Right;
I love thee purely, as they turn from Praise.
I love thee with a passion put to use
In my old griefs, and with my childhood’s faith.
I love thee with a love I seemed to lose
With my lost saints, —- I love thee with the breath,
Smiles, tears, of all my life! —- and, if God choose,
I shall but love thee better after death.
Yes, that is Ms. Browning’s famous poem. This should size the application window to a suitably usable format now.
Our final addition to the program puts the spinners into action: add into the prepare_page method the following:
poem = @glade["textview1"].buffer.text.split("\n")
case @glade["assistant1"].current_page
when 2
poem_lines = " "
for num in (@glade["spinbutton1"].value_as_int - 1)..(@glade["spinbutton2"].value_as_int - 1) do
poem_lines << "\n" << poem[num]
end
@glade["textview1"].buffer.set_text(poem_lines)
end
This includes a correction, value_as_int - 1, as arrays start from zero!
Conclusions
So, there we have it. You should be able to run through the program, pick which lines of a poem we should display and, well, display them. Not a lot in itself but all the set-up and groundwork is done for further development. We are picking up quite a lot along the way about the Ruby & GTK+ relationship:
- Within a GTK+ project one can have many windows, each are independent. This allows for designers to concentrate on the GUI without interference from developers because designers need not code, nor developers need design.
- All that one expects from an interface in programming terms is provided by the GTK+ objects and events, and Ruby interface. This gives flexibility and power to applications.
- There exist short-cuts such as @glade[“”] for the @glade.get_widget method, that make for very easy reference of GUI objects, thus Ruby/GTK+ programming quite enjoyable.
In this post, we have added events to our basic GTK+ application by using Glade³ to assign a method to each, aligning them to Ruby code ‘callbacks’. In the process we have interacted with GUI objects and done some simple processing and activities based on the results. This is only the beginning, perhaps we could improve it by fixing the backward-button-clicking bug, adding other widgets and trying to manipulate them.



