Part of a series: Embedding Ruby – Part I
I recently embarked on a quick-turn project with a timeline of 30 days to come up with GUI application that needed to utilize a touchscreen and basic PIN-pad for data entry, and also interface to an RFID reader and a scale. Hardware cost was a main concern for profitability, but the timeline could not budge, due to market pressures. I found some great low-price touch-panel linux machines at Technologic that came with a stripped down version of Linux that ran on a lightweight Freescale ARM processor that fit the bill, so I decided to tap into the power of Linux and Ruby to conquer this task in the short time allotted.
We had developed JRuby applications in the past at Atomic, and that worked out great on a modern-day PC. Although, with the lack of horsepower on this target platform, I didn’t want the extra processing required to run through a Java Virtual Machine to end up resulting in performance issues on this 800MHz 256MB RAM machine.
I initially tried to get Qt rolling with Ruby bindings, but ran into too many installation headaches. I also didn’t require the full power of Qt for the lightweight GUI required for this project, so I decided to give GTK a shot by utilizing the Ruby-GNOME2 framework that provides Ruby bindings for GTK and other GNOME libraries.
Below is a lightweight example that loads a simple prebuilt text editor window from a Glade UI designer file and implements open, save and quit operations via menu items:
Building the window in Glade is pretty trivial. First I set the output format to LibGlade, instead of the default of GtkBuilder, since I had problems getting that format to work with the Ruby bindings.
I started by adding a Window toplevel container, and then added a VBox container with 3 panes. Here is a screenshot:
At this point, I filled in the panes of the VBox container. I added a Menu Bar with default contents in the top slot, followed by a Text View in the middle, and a Status Bar at the bottom. The resultant window, in Glade, looks like:
To allow me to respond to menu item clicks, I selected the File->Open menu item, and went to the Signals tab in the properties view. I then simply added a name for my handler, on_open_clicked, to the GtkMenuItem->activate handler column. I did likewise for File->Save (on_save_clicked) and File->Quit (on_quit_clicked). My UI design was complete, so I saved it as editor_window.glade and was done!
Now, I simply needed to load the Glade file in Ruby, and make it do something. I simply created a new GladeXML object, and the block passed to the constructor wires up the events to the corresponding handler, which are simply methods in the same class with the same name I entered for each event in Glade. Here is my editor.rb file with all the magic to make the basic features work:
require 'gtk2'
require 'libglade2'
class Editor < Gtk::Window
def initialize
super
# Create the window from the Glade file
@glade = GladeXML.new('editor_window.glade') do |handler|
self.method(handler)
end
# Grab a reference to the Window, handle detroy, and queue to show
@window = @glade['window']
@window.signal_connect('destroy'){self.on_quit_clicked}
@window.show_all
# Start GTK processing
Gtk.main()
end
def on_open_clicked
# Display a file open dialog
dialog = Gtk::FileChooserDialog.new("Open File",
@window,
Gtk::FileChooser::ACTION_OPEN,
nil,
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
# Dump the text from the file into the text box
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
buf = @glade.get_widget('textview').buffer
buf.text = File.read(dialog.filename)
end
# Make sure we get rid of the remains
dialog.destroy
end
def on_save_clicked
# Display a file save dialog
dialog = Gtk::FileChooserDialog.new("Save File",
@window,
Gtk::FileChooser::ACTION_OPEN,
nil,
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
[Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
# Save the text box content to the specified file
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
buf = @glade.get_widget('textview').buffer
File.open(dialog.filename, 'w+'){|f| f << buf.text}
end
# Make sure we get rid of the remains
dialog.destroy
end
def on_quit_clicked
# Stop GTK, since we are done
Gtk.main_quit()
end
end
# Create an instance of our editor window to start the show
Editor.new
Here is the corresponding ‘editor_window.glade’ file generated fully in Glade. Not really nice to look at, but included it here for completeness.
True
Text Editor Demo
center
440
250
True
True
vertical
True
True
_File
True
True
gtk-new
True
True
True
gtk-open
True
True
True
gtk-save
True
True
True
gtk-save-as
True
True
True
True
gtk-quit
True
True
True
True
_Edit
True
True
gtk-cut
True
True
True
gtk-copy
True
True
True
gtk-paste
True
True
True
gtk-delete
True
True
True
True
_View
True
True
_Help
True
True
gtk-about
True
True
True
False
0
True
True
1
True
2
False
2
We are still wrapping up this project, but we have had a lot of fun with Ruby, Glade and GTK. Hope you can have some fun with it too.
As of this posting, the XML is malformed on this blog, and < appears instead of < in the blog text. Somewhere, things aren't being escaped quite right.
Samuel,
It looks WordPress clobbered the XML in a previous save. I restored it, so it’s all good once again. Thanks for the heads up!
Greg