Skip to content

SWT JRuby bootstrap guide

KC Erb edited this page Oct 16, 2015 · 6 revisions

JRuby + SWT Introduction

The Standard Widget Toolkit (SWT) is a free and open-source graphical library written in Java. It provides a native implementation of most windowing widgets, and for this reason, performs better than other Java libraries like AWT or Swing. A famous project using SWT for its Graphical User Interface is Eclipse.

With JRuby, we don't need to code in Java to get the benefits of a portable, yet native, cross-platform GUI. We can use Ruby. This little guide is intended to bootstrap you into SWT programing with JRuby.

Installing SWT

Get JRuby

This guide uses JRuby 1.7.18 on OSX (jruby 1.7.18 (1.9.3p551) 2014-12-22 625381c on Java HotSpot(TM) 64-Bit Server VM 1.6.0_65-b14-466.1-11M4716 +jit [darwin-x86_64])

Get the swt gem

In order to use SWT, you need to require it. An easy way to do it is to install the swt gem, created by danlucraft.

$ gem install swt

Let's make sure everything is okay

Before going further, let's make sure the system is working correctly. To do that, fire-up your favorite editor and try to require java and swt. Let's call that file testing_swt.rb

require 'java'
require 'swt'

You need to execute it with JRuby like this:

$ jruby testing_swt.rb

At that point, you shouldn't see anything happening: that means it's working!

A little SWT program

The way an SWT program works is like this: there's an event loop that waits for an event; it dispatches that event to the appropriate handler or it sleeps.

In SWT parlance, the object responsible for waiting and dispatching events is called a Display. Each SWT program needs a display.

require 'java'
require 'swt'

# Each Swt application need a display to interact with the operating system.
display = Swt::Widgets::Display.new

Now go ahead and run this program. If you are on Windows or Linux you'll probably just see a brief flash and nothing. If you are on OSX however, you will probably get an error like this:

***WARNING: Display must be created on main thread due to Cocoa restrictions.
java/lang/reflect/Constructor.java:513:in `newInstance': org.eclipse.swt.SWTException: Invalid thread access
	from local_tests/testing_swt.rb:5:in `(root)'
	from local_tests/local_tests/testing_swt.rb:5:in `(root)'

In order to put the display on a new thread, just run the program like this

$ jruby -J-XstartOnFirstThread testing_swt.rb

If you don't want to be bothered with passing that option in every time, then you can set the JRUBY_OPTS environment variable like this:

$ export JRUBY_OPTS=-J-XstartOnFirstThread

and then run the program normally.

So now, we still don't have any window. Let's create one! In SWT, a window is called a Shell. There can be as many shells as you want. In order to create one, you need to associate it with a display.

# Let's create a new window. It's called "Shell" in Swt vocabulary.
# Note that we pass it a display.
shell = Swt::Widgets::Shell.new(display)

Nice. Before adding any widgets inside, we need to talk about Layouts. In SWT, items are added to Containers which are able to carry other elements, such as 'Composite', or 'Group'. Your shell is a container: you can add items to it.

In SWT, a Layout Manager is responsible for deciding how items are added to a container. There are various Layout managers, and you can find the complete list in the SWT API.

What we want to add to our shell is a Label and a Button. Let's use the GridLayout with two columns to do that. As its name implies, the GridLayout will split up your shell into a grid.

# Each shell requires a layout. It's there to organize the widgets in the shell.
layout = Swt::Layout::GridLayout.new(2, false)
shell.setLayout(layout)

Next, we add the Label and the button:

# Let's create a label and add it to the parent container (the shell)
label = Swt::Widgets::Label.new(shell, Swt::SWT::NONE)
label.text = "This is a label"

button = Swt::Widgets::Button.new(shell, Swt::SWT::PUSH)
button.text = "Click Me"

As you can see, the parent of the element (its container) is passed to the element in the constructor. The second argument is the style.

What would be cool would be to change the content of the label once the button is clicked. We can add a listener to the button to do that.

button.add_selection_listener do
  label.text = "clicked!"
end

Now let's display the shell:

# Ready to display the shell!
shell.open

Great! But as it stands, the program won't run... Or at least, it wouldn't stay on screen for long, since there is no infinite loop keeping it on. We need to take care of this.

# We need an event loop now.
while !shell.isDisposed

  # The application sleeps unless there's a new event.
  display.sleep unless display.read_and_dispatch
end

display.dispose

Now, execute this with

$ jruby testing_swt.rb

and voilà!

For the complete source code, here is the gist.

Some resources