Subscribe:

Pages

Control Widgets in wxRuby

Ruby's high-level syntax makes it simple to design and write graphical interfaces in code. In this post, I explore the basic techniques for handling control widgets: how to construct them, retrieve values, and respond to events. There are two broad classes of control: static controls act as simple display devices, such as a label on the screen; non-static controls provide some form of user interaction, such as a button. There are some common principles for how all these control widgets are constructed and operate.

General Principles

Nearly all of the controls are created in a similar way.

Wx::StaticText.new(self, :label => "Password", :style => Wx::ALIGN_RIGHT
) Wx::TextCtrl.new(self, :style => Wx::TE_PASSWORD)

Every control must have a
parent window within which it is placed. This parent window is usually the frame or dialog within which you are placing your controls, self in the above examples. Each control also has some optional styles. Finally, there is some specific information for setting up the control, such as the label to display in a StaticText label, or the style for displaying information within the control, such as the 'password' reference in the TextCtrl.

(Things in the documentation which you can usually forget about are the widget's ID identifier, its position, and size. The ID number is used to identify your widget for the purpose of handling events within C++ code using wxWidgets. But Ruby provides a better way to register events directly with your widgets. The widget's position and size are best left to sizers which layout your controls within a window, for which see below.)

A small note about the 'BoxSizer' which appears in the examples: this is a way to arrange controls in a vertical or horizontal order. Without it, all of the controls will appear on top of one another. I shall cover sizers in more detail in another post.


Static controls


StaticText - a Label


The simplest control to display is a piece of text, to act as a label. For this, wxRuby provides the StaticText class. You must provide two pieces of information, the parent of the control and the text for the label.


StaticBitmap
- an Image

Displaying an image is a two stage process. Assuming your image is stored in a file, you must first create an instance of the Bitmap class from your file: Bitmap.new(filename) Then display it in a StaticBitmap control. The syntax for StaticBitmap requires you to fill out the first three arguments: the third is the bitmap to display, the first is the familiar parent panel, and the second is the identifier number. I said before we are not interested in this number, and wxRuby lets us use Wx::ID_ANY as the parameter so that a new number is assigned internally.


Here is a complete example using both static controls:

require 'wx'

class MyFrame < Wx::Frame
def initialize
super(nil, :title => "Controls 1")

main_sizer = Wx::BoxSizer.new Wx::VERTICAL
main_sizer.add(Wx::StaticText.new(self, :label => "Picture of Mars"))
main_sizer.add(Wx::StaticBitmap.new(self, Wx::ID_ANY, Wx::Bitmap.new("planet5.gif")))

set_sizer main_sizer
end
end

Wx::App.run do
MyFrame.new.show
end


Non-static controls


The setup and display of non-static controls follows the same pattern as the static controls. However, users can interact with non-static controls, perhaps clicking or selecting displayed items, or entering new information. So these controls provide a range of events and accessor methods to track what the user is up to.


Buttons

Buttons are the simplest form of interactive control: they display some text, and react if clicked. The creation and display part for a button is the same as for a StaticText control:


@button = Wx::Button.new(self, :label => "Click me")

How do we make the code react to a click? We associate an action with the button's
event. Every control has one or more events associated with it. These events can be attached to actions, so that something in the code is called whenever the event is triggered. In this case, the button has one event, triggered when the button is clicked. We associate an action, say calling the 'button_clicked' method, with the button as follows:

evt_button(@button) {button_clicked}


Radio box


A radio button is a simple button with a usually round bullet which can be selected, on or off. Unlike checkboxes, radio buttons are organised into groups, and the idea is that one button in the group is always selected, and never more than one. The RadioBox is constructed using an array of strings which it uses to label up a series of radio buttons and display neatly wrapped in a static line. It is also possible to add a label to the complete box. The method get_string_selection is used to retrieve the currently selected string. Notice how the radio_box is stored in an instance variable, so as to be visible to the 'show_value' method.

require 'wx'

class MyFrame < Wx::Frame
def initialize
super(nil, :title => "Controls 4")

@radio_box = Wx::RadioBox.new(
self,
:label => "Language:",
:choices => ["C", "C++", "Lisp", "Ruby", "Scheme"])
button = Wx::Button.new(self, :label => "Show")
evt_button(button) {show_value}

main_sizer = Wx::BoxSizer.new Wx::VERTICAL
main_sizer.add(@radio_box, 0, Wx::ALL, 10)
main_sizer.add(button)

set_sizer main_sizer
end

def show_value
puts @radio_box.get_string_selection
end
end

Wx::App.run do
MyFrame.new.show
end


Listboxes

A listbox is a scrollable display of a list of strings. The listbox can be used to select one or more items, and the control can be set up to permit single selection only (the default) or multiple selection (using style LB_MULTIPLE). The method get_selection returns the index of the current selection, if any, for a single selection listbox, and get_selections returns an array of indices for any selected items in a multiple selection listbox. The following code constructs a multiple-selection listbox and then prints out selected indices when the 'show' button is clicked. Notice how the list_box is stored in an instance variable, so as to be visible to the 'show_choices' method.
require 'wx'

class MyFrame < Wx::Frame
def initialize
super(nil, :title => "Controls 3")

@list_box = Wx::ListBox.new(
self,
:choices => ["C", "C++", "Java", "Lisp", "Ruby", "Scheme"],
:style => Wx::LB_MULTIPLE)

button = Wx::Button.new(self, :label => "Show")
evt_button(button) {show_choices}

main_sizer = Wx::BoxSizer.new Wx::VERTICAL
main_sizer.add(@list_box)
main_sizer.add(button)

set_sizer main_sizer
end

def show_choices
puts @list_box.get_selections
end
end

Wx::App.run do
MyFrame.new.show
end


Calendar control


This control enables the user to select a date. You can catch different events, such as whether the user clicked on a heading, or changed the day, month or year. In this example, I just catch the 'double-click on a single day' event, and show how to extract the day, month and year information from the calendar control.

require 'wx'

class MyFrame < Wx::Frame
def initialize
super(nil, :title => "Controls:Calendar")

cal = Wx::CalendarCtrl.new(self)
evt_calendar(cal) do |event|
puts "Day #{cal.get_date.day}, Month: #{cal.get_date.month}, Year: #{cal.get_date.year}"
end

main_sizer = Wx::BoxSizer.new Wx::VERTICAL
main_sizer.add(cal, 1, Wx::GROW | Wx::ALL, 10)

set_sizer main_sizer
end
end

Wx::App.run do
MyFrame.new.show
end



Finally ...

There are many more controls described in the wxRuby documentation: TextCtrl and RichTextCtrl allow for the display and input of complex formatted text; TreeCtrl enables the display of hierarchical data; and MediaCtrl supports the display of video or sound. They all follow similar principles to the above, so explore the documentation for details!