-
Notifications
You must be signed in to change notification settings - Fork 6
HowTo : A basic application
This document shows how to create a simple wxRuby application that can be used as a template.
While this app does nothing useful, it demonstrates a couple basic concepts and explains how to write a valid, working, wxRuby application. Trying to run this application is also a good way of checking that wxRuby is correctly installed on your system.
To create an application with wxRuby you first need to require the wxRuby modules:
require 'wx'
This code uses the all-in-one approach for loading the wxRuby modules. It is also possible to require separate modules but we will not cover that here (see the wxRuby Modules document for more information).
Next would be the application code and a main entry point. With wxRuby (as with wxWidgets) the entry point is mostly just a simple call to start the applications event loop (as we're talking about event based GUI applications here). In wxRuby the Wx::App class provides some typically Ruby-style magic to make this as easy as possible.
Using this the simplest Hello World application could be:
require 'wx'
Wx::App.run { puts 'Hello world!' }
As you can see there is no obligation to create an instance of the Wx::App class in wxRuby for
(admittedly extremely) simple applications. Calling the Wx::App.run class method with a block will suffice.
The class method will create an instance of the generic Wx::App class under the hood and use the
provided block as the #on_init
callback. As the code inside the block returns a false-type value (#puts
returns nil
) the application will terminate immediately after writing "Hello world!" to standard
output (actually not even starting the event loop at all).
For more complex applications the approach demonstrated above will quickly become insufficient. So for practically
all real-world applications creating a specialized derived App class is the better option.
This provides the possibility (as with all Ruby classes) to override the constructor (Wx::App#initialize) for
custom initialization, attribute definitions and create customized #on_init
and/or #on_exit
methods like
this:
require 'wx'
class MyApp < Wx::App
def initialize
super
# initialize something ...
end
def on_init
# startup the application ...
end
def on_exit
# cleanup the application ...
puts 'Exiting.'
end
end
When creating #on_init
/#on_exit
methods it is important to understand that those would not be overrides (as is the case
with wxWidgets itself). The base Wx::App class actually does not define these methods so it's also not needed (even not possible)
to call super
in the implementation. The wxRuby application class implementation will call the wxWidget OnInit base implementation
itself and after successful completion check for the existence of an #on_init method (which could also be 'automagicallly'
created from a block passed to #run) and call that if available or terminate the application if not. The
exit sequence of executions are similar but reversed (first a possible #on_exit
method and than the wxWidgets base OnExit).
What remains though is that for a derived application class it is still not necessary to explicitly create a class instance. Simply calling the Wx::App.run class method will suffice.
MyApp.run
The current application instance (as long as the application is active) can always be retrieved by
calling Wx.get_app (note that during the #initialize call this will still return nil
but at that point you can
reference self
).
Many applications start with a main window derived from the Wx::Frame class and provide it with a menu and a status bar in its constructor. Connecting event handlers to respond to events like mouse clicks, menu and/or widget messages usually also happens at construction time.
In order to be able to respond to a menu message menu items must be given a unique identifier which is usually defined
as a constant.
Identifiers for common menu items like 'About' or 'Exit' do not (normally) need to be defined as wxRuby defines a set
of stock identifiers for items like that (like Wx::ID_ABOUT and Wx::ID_EXIT). Using these is usually preferable as these
can be processed in platform specific ways.
Our example class would look like this than:
class MyFrame < Wx::Frame
module ID
Hello = 1
end
def initialize
super(nil, Wx::ID_ANY, 'Hello World')
file_menu = Wx::Menu.new
file_menu.append(ID::Hello, "&Hello...\tCtrl-H",
'Help string shown in status bar for this menu item')
file_menu.append_separator
file_menu.append(Wx::ID_EXIT)
help_menu = Wx::Menu.new
help_menu.append(Wx::ID_ABOUT)
menu_bar = Wx::MenuBar.new
menu_bar.append(file_menu, '&File')
menu_bar.append(help_menu, '&Help')
self.menu_bar = menu_bar
create_status_bar
set_status_text('Welcome to wxRuby!')
# connect event handlers
evt_menu ID::Hello, :on_hello
evt_menu Wx::ID_ABOUT, :on_about
evt_menu Wx::ID_EXIT, :on_exit
end
# ... continued below ...
Notice that we don't need to specify the labels for the standard menu items Wx::ID_ABOUT and Wx::ID_EXIT — they will be given standard labels and standard accelerators correct for the current platform, making our program behaviour more native. For this reason, you should prefer reusing the stock identifiers where possible.
We also connect our event handlers to the events we want them to handle. We do this by calling the event connectors specific to the type of event we want to handle. Depending on the event type we pass a single identifier or range of identifiers to select event type instances to handle and specify the actual handler by passing a method identifier, a method object or a block.
In our example we connect instance methods by specifying the method identifiers for the following standard event handler implementations:
# .. continued from above ...
def on_exit(_evt)
close(true)
end
def on_about(_evt)
Wx.message_box('This is a wxWidgets Hello World example',
'About Hello World', Wx::OK | Wx::ICON_INFORMATION)
end
def on_hello
Wx.log_message('Hello world from wxWidgets!')
end
end # class MyFrame
MyFrame#on_exit
closes the main window by calling Wx::Window#close. The parameter true indicates that other windows
have no veto power such as after asking "Do you really want to close?". If there is no other main window left,
the application will quit.
MyFrame#on_about
will display a small window with some text in it. In this case a typical "About" window with
information about the program.
The implementation of a custom menu command handler may perform whatever task your program needs to do, in this case it simply shows an appropriate message.
NOTE In case of (very) simple event handlers as with :on_exit and :on_about it can be convenient to use Ruby blocks instead of defining actual instance methods like this:
evt_menu Wx::ID_EXIT { close(true) }
Now that we have a custom main window class we still need to instantiate and show that window as the application starts.
This is usually done from the applications #on_init
method like this:
class MyApp < Wx::App
# ...
def on_init
frame = MyFrame.new
frame.show(true)
end
# ...
end
Be aware that the MyApp#on_init
should return a 'thruthy' value (not false
and not nil
) to indicate all was well
and starting the application should continue. As the return value for showing a window that is not shown yet should be
true
if succeeded the code above should function properly.
Here is the complete program to be copied and pasted:
require 'wx'
class MyFrame < Wx::Frame
module ID
Hello = 1
end
def initialize
super(nil, Wx::ID_ANY, 'Hello World')
file_menu = Wx::Menu.new
file_menu.append(ID::Hello, "&Hello...\tCtrl-H",
'Help string shown in status bar for this menu item')
file_menu.append_separator
file_menu.append(Wx::ID_EXIT)
help_menu = Wx::Menu.new
help_menu.append(Wx::ID_ABOUT)
menu_bar = Wx::MenuBar.new
menu_bar.append(file_menu, '&File')
menu_bar.append(help_menu, '&Help')
self.menu_bar = menu_bar
create_status_bar
set_status_text('Welcome to wxRuby!')
# connect event handlers
evt_menu ID::Hello, :on_hello
evt_menu Wx::ID_ABOUT, :on_about
evt_menu Wx::ID_EXIT, :on_exit
end
def on_exit(_evt)
close(true)
end
def on_about(_evt)
Wx.message_box('This is a wxWidgets Hello World example',
'About Hello World', Wx::OK | Wx::ICON_INFORMATION)
end
def on_hello
Wx.log_message('Hello world from wxWidgets!')
end
end # class MyFrame
class MyApp < Wx::App
def initialize
super
# initialize something ...
end
def on_init
frame = MyFrame.new
frame.show(true)
end
def on_exit
# cleanup the application ...
puts 'Exiting.'
end
end
MyApp.run
-
-
Basic Guides
-
Widget Guides
-
Drawing Guides
-
Event Guides
-