Showing posts with label Ruby GTK. Show all posts
Showing posts with label Ruby GTK. Show all posts

Monday, April 15, 2013

Step By Step Ruby GTK tutorial

Ruby GTK tutorial

This is Ruby GTK tutorial. In this tutorial, you will learn the basics of GUI programming with GTK in Ruby language. The tutorial is suitable for beginners and intermediate programmers.

GTK

The GTK is a library for creating graphical user interfaces. The library is created in C programming language. The GTK library is also called the GIMP Toolkit. Originally, the library was created while developing the GIMP image manipulation program. Since then, the GTK became one of the most popular toolkits under Linux and BSD Unix. Today, most of the GUI software in the open source world is created in Qt or in GTK. Language bindings exist for C++, Python, Perl, Java, C#, JavaScript, PHP and other programming languages.

Nibbles Clone Game in Ruby GTK

Nibbles

In this part of the Ruby GTK programming tutorial, we will create a Nibbles game clone.
Nibbles is an older classic video game. It was first created in late 70s. Later it was brought to PCs. In this game the player controls a snake. The objective is to eat as many apples as possible. Each time the snake eats an apple, its body grows. The snake must avoid the walls and its own body.

Development

The size of each of the joints of a snake is 10px. The snake is controlled with the cursor keys. Initially, the snake has three joints. The game starts immediately. When the game is finished, we display "Game Over" message in the center of the window.
board.rb
WIDTH = 300
HEIGHT = 270
DOT_SIZE = 10
ALL_DOTS = WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE)
RAND_POS = 26

$x = [0] * ALL_DOTS
$y = [0] * ALL_DOTS

class Board < Gtk::DrawingArea

def initialize
super

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(0, 0, 0)

signal_connect "expose-event" do
on_expose
end

init_game
end

def on_timer

if @inGame
check_apple
check_collision
move
queue_draw
return true
else
return false
end
end

def init_game

@left = false
@right = true
@up = false
@down = false
@inGame = true
@dots = 3

for i in (0..@dots)
$x[i] = 50 - i * 10
$y[i] = 50
end

begin
@dot = Cairo::ImageSurface.from_png "dot.png"
@head = Cairo::ImageSurface.from_png "head.png"
@apple = Cairo::ImageSurface.from_png "apple.png"
rescue Exception => e
puts "cannot load images"
exit
end

locate_apple
GLib::Timeout.add(100) { on_timer }

end


def on_expose

cr = window.create_cairo_context

if @inGame
draw_objects cr
else
game_over cr
end
end

def draw_objects cr

cr.set_source_rgb 0, 0, 0
cr.paint

cr.set_source @apple, @apple_x, @apple_y
cr.paint

for z in (0..@dots)
if z == 0
cr.set_source @head, $x[z], $y[z]
cr.paint
else
cr.set_source @dot, $x[z], $y[z]
cr.paint
end
end
end

def game_over cr

w = allocation.width / 2
h = allocation.height / 2

cr.set_font_size 15
te = cr.text_extents "Game Over"

cr.set_source_rgb 65535, 65535, 65535

cr.move_to w - te.width/2, h
cr.show_text "Game Over"

end


def check_apple

if $x[0] == @apple_x and $y[0] == @apple_y
@dots = @dots + 1
locate_apple
end
end

def move

z = @dots

while z > 0
$x[z] = $x[(z - 1)]
$y[z] = $y[(z - 1)]
z = z - 1
end

if @left
$x[0] -= DOT_SIZE
end

if @right
$x[0] += DOT_SIZE
end

if @up
$y[0] -= DOT_SIZE
end

if @down
$y[0] += DOT_SIZE
end

end

def check_collision

z = @dots

while z > 0
if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
@inGame = false
end
z = z - 1
end

if $y[0] > HEIGHT - DOT_SIZE
@inGame = false
end

if $y[0] < 0
@inGame = false
end

if $x[0] > WIDTH - DOT_SIZE
@inGame = false
end

if $x[0] < 0
@inGame = false
end

end

def locate_apple

r = rand(RAND_POS)
@apple_x = r * DOT_SIZE
r = rand(RAND_POS)
@apple_y = r * DOT_SIZE
end

def on_key_down event

key = event.keyval

if key == Gdk::Keyval::GDK_Left and not @right
@left = true
@up = false
@down = false
end

if key == Gdk::Keyval::GDK_Right and not @left
@right = true
@up = false
@down = false
end

if key == Gdk::Keyval::GDK_Up and not @down
@up = true
@right = false
@left = false
end

if key == Gdk::Keyval::GDK_Down and not @up
@down = true
@right = false
@left = false
end
end
end
First we will define some globals used in our game.
The WIDTH and HEIGHT constants determine the size of the Board. The DOT_SIZE is the size of the apple and the dot of the snake. The ALL_DOTS constant defines the maximum number of possible dots on the Board. The RAND_POS constant is used to calculate a random position of an apple. The DELAY constant determines the speed of the game.
$x = [0] * ALL_DOTS
$y = [0] * ALL_DOTS
These two arrays store x, y coordinates of all possible joints of a snake.
The init_game method initializes variables, loads images and starts a timeout function.
if @inGame
draw_objects cr
else
game_over cr
end
Inside the on_expose method, we check the @inGamevariable. If it is true, we draw our objects. The apple and the snake joints. Otherwise we display "Game over" text.
def draw_objects cr

cr.set_source_rgb 0, 0, 0
cr.paint

cr.set_source @apple, @apple_x, @apple_y
cr.paint

for z in (0..@dots)
if z == 0
cr.set_source @head, $x[z], $y[z]
cr.paint
else
cr.set_source @dot, $x[z], $y[z]
cr.paint
end
end
end
The draw_objects method draws the apple and the joints of the snake. The first joint of a snake is its head, which is represented by a red circle.
def check_apple

if $x[0] == @apple_x and $y[0] == @apple_y
@dots = @dots + 1
locate_apple
end
end
The check_apple method checks, if the snake has hit the apple object. If so, we add another snake joint and call the locate_apple method, which randomly places a new apple object.
In the move method we have the key algorithm of the game. To understand it, look at how the snake is moving. You control the head of the snake. You can change its direction with the cursor keys. The rest of the joints move one position up the chain. The second joint moves where the first was, the third joint where the second was etc.
while z > 0
$x[z] = $x[(z - 1)]
$y[z] = $y[(z - 1)]
z = z - 1
end
This code moves the joints up the chain.
if @left
$x[0] -= DOT_SIZE
end
Move the head to the left.
In the check_collision method, we determine if the snake has hit itself or one of the walls.
while z > 0
if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
@inGame = false
end
z = z - 1
end
Finish the game, if the snake hits one of its joints with the head.
if $y[0] > HEIGHT - DOT_SIZE
@inGame = false
end
Finish the game, if the snake hits the bottom of the Board.
The locate_apple method locates an apple randomly on the board.
r = rand(RAND_POS)
We get a random number from 0 to RAND_POS - 1.
@apple_x = r * DOT_SIZE
...
@apple_y = r * DOT_SIZE
These line set the x, y coordinates of the apple object.
if @inGame
check_apple
check_collision
move
queue_draw
return true
else
return false
end
Every 140 ms, the on_timer method is called. If we are in the game, we call three methods, that build the logic of the game. Otherwise we return false, which stops the timer event.
In the on_key_down method of the Board class, we determine the keys that were pressed.
if key == Gdk::Keyval::GDK_Left and not @right
@left = true
@up = false
@down = false
end
If we hit the left cursor key, we set left variable to true. This variable is used in the movemethod to change coordinates of the snake object. Notice also, that when the snake is heading to the right, we cannot turn immediately to the left.
nibbles.rb
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This is a simple nibbles game
# clone
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'
require 'board'

class RubyApp > Gtk::Window
def initialize
super

set_title "Nibbles"
signal_connect "destroy" do
Gtk.main_quit
end

@board = Board.new
signal_connect "key-press-event" do |w, e|
on_key_down(w, e)
end

add @board

set_default_size 300, 270
set_window_position Gtk::Window::POS_CENTER
show_all
end

def on_key_down widget, event

key = event.keyval
@board.on_key_down event
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In this class, we set up the Nibbles game.
def on_key_down widget, event 

key = event.keyval
@board.on_key_down event
end
In this class, we catch the key press events. And delegate the processing to the on_key_down method of the board class.
Nibbles
Figure: Nibbles
This was the Nibbles computer game programmed with the GTK library and the Ruby programming language.

Custom widget in Ruby GTK

Custom widget

Most toolkits usually provide only the most common widgets like buttons, text widgets, sliders etc. No toolkit can provide all possible widgets. Programmers must create such widgets by themselves. They do it by using the drawing tools provided by the toolkit. There are two possibilities. A programmer can modify or enhance an existing widget. Or he can create a custom widget from scratch.

Burning widget

This is an example of a widget, that we create from scratch. This widget can be found in various media burning applications, like Nero Burning ROM.
custom.rb
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example creates a burning
# custom widget
#
# author: jan bodnar
# website: zetcode.com
# last edited: June 2009


require 'gtk2'

class Burning < Gtk::DrawingArea

def initialize(parent)
@parent = parent

super()

@num = [ "75", "150", "225", "300",
"375", "450", "525", "600", "675" ]

set_size_request 1, 30
signal_connect "expose-event" do
expose
end
end


def expose

cr = window.create_cairo_context
draw_widget cr

end

def draw_widget cr

cr.set_line_width 0.8

cr.select_font_face("Courier",
Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL)
cr.set_font_size 11

width = allocation.width

@cur_width = @parent.get_cur_value

step = (width / 10.0).round

till = (width / 750.0) * @cur_width
full = (width / 750.0) * 700

if @cur_width >= 700

cr.set_source_rgb(1.0, 1.0, 0.72)
cr.rectangle(0, 0, full, 30)
cr.clip
cr.paint
cr.reset_clip

cr.set_source_rgb(1.0, 0.68, 0.68)
cr.rectangle(full, 0, till-full, 30)
cr.clip
cr.paint
cr.reset_clip

else
cr.set_source_rgb 1.0, 1.0, 0.72
cr.rectangle 0, 0, till, 30
cr.clip
cr.paint
cr.reset_clip
end


cr.set_source_rgb(0.35, 0.31, 0.24)

for i in (1..@num.length)
cr.move_to i*step, 0
cr.line_to i*step, 5
cr.stroke

te = cr.text_extents @num[i-1]
cr.move_to i*step-te.width/2, 15
cr.text_path @num[i-1]
cr.stroke
end
end
end


class RubyApp < Gtk::Window
def initialize
super

set_title "Burning"
signal_connect "destroy" do
Gtk.main_quit
end

set_size_request 350, 200
set_window_position Gtk::Window::POS_CENTER

@cur_value = 0

vbox = Gtk::VBox.new false, 2

scale = Gtk::HScale.new
scale.set_range 0, 750
scale.set_digits 0
scale.set_size_request 160, 35
scale.set_value @cur_value

scale.signal_connect "value-changed" do |w|
on_changed(w)
end

fix = Gtk::Fixed.new
fix.put scale, 50, 50

vbox.pack_start fix

@burning = Burning.new(self)
vbox.pack_start @burning, false, false, 0

add vbox
show_all
end

def on_changed widget

@cur_value = widget.value
@burning.queue_draw
end

def get_cur_value
return @cur_value
end
end

Gtk.init
window = RubyApp.new
Gtk.main
We put a DrawingArea on the bottom of the window and draw the entire widget manually. All the important code resides in the draw_widget which is called from the expose method of the Burning class. This widget shows graphically the total capacity of a medium and the free space available to us. The widget is controlled by a scale widget. The minimum value of our custom widget is 0, the maximum is 750. If we reach value 700, we began drawing in red colour. This normally indicates overburning.
@num = [ "75", "150", "225", "300", 
"375", "450", "525", "600", "675" ]
These numbers are shown on the burning widget. They show the capacity of the medium.
@cur_width = @parent.get_cur_value
From the parent widget, we get the current value of the scale widget.
till = (width / 750.0) * @cur_width
full = (width / 750.0) * 700
We use the width variable to do the transformations. Between the values of the scale and the custom widget's measures. Note that we use floating point values. We get greater precision in drawing. The till parameter determines the total size to be drawn. This value comes from the slider widget. It is a proportion of the whole area. The full parameter determines the point, where we begin to draw in red color.
cr.set_source_rgb(1.0, 1.0, 0.72)
cr.rectangle(0, 0, full, 30)
cr.clip
cr.paint
cr.reset_clip
We draw a yellow rectangle up to point, where the medium is full.
te = cr.text_extents @num[i-1]
cr.move_to i*step-te.width/2, 15
cr.text_path @num[i-1]
cr.stroke
This code here draws the numbers on the burning widget. We calculate the text extents to position the text correctly.
def on_changed widget

@cur_value = widget.value
@burning.queue_draw
end
We get the value from the scale widget, store it in the @cur_value variable for later use. We redraw the burning widget.
Burning widget
Figure: Burning widget
In this chapter, we created a custom widget in GTK and Ruby programming language.

Painting with Cairo in Ruby GTK

Painting with Cairo

In this part of the Ruby GTK tutorial, we will do some painting with the Cairo library.
Cairo is a library for creating 2D vector graphics. We can use it to draw our own widgets, charts or various effects or animations.

Colors

In the first example, we will work with colors. A color is an object representing a combination of Red, Green, and Blue (RGB) intensity values. Cairo valid RGB values are in the range 0 to 1.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program shows how to work
# with colors in Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Colors"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 360, 100
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

@darea = Gtk::DrawingArea.new

@darea.signal_connect "expose-event" do
on_expose
end

add(@darea)

end

def on_expose

cr = @darea.window.create_cairo_context
draw_colors cr

end

def draw_colors cr

cr.set_source_rgb 0.2, 0.23, 0.9
cr.rectangle 10, 15, 90, 60
cr.fill

cr.set_source_rgb 0.9, 0.1, 0.1
cr.rectangle 130, 15, 90, 60
cr.fill

cr.set_source_rgb 0.4, 0.9, 0.4
cr.rectangle 250, 15, 90, 60
cr.fill
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In our example, we will draw three rectangles and fill them with three different colors.
@darea = Gtk::DrawingArea.new 
We will be doing our drawing operations on the DrawingArea widget.
@darea.signal_connect "expose-event" do  
on_expose
end
When the window needs to be redrawn, the the expose-event is triggered. In response to this event, we call the on_expose method.
 cr = @darea.window.create_cairo_context  
We create the cairo context object from the GdkWindow of the drawing area. The context is an object onto which we do all our drawings.
draw_colors cr
The actual drawing is delegated to the draw_colors method.
cr.set_source_rgb 0.2, 0.23, 0.9
The set_source_rgb method sets a color for the cairo context. The three parameters of the method are the color intensity values.
cr.rectangle 10, 15, 90, 60
We draw a rectangle. The first two parameters are the x, y coordinates of the top left corner of the rectangle. The last two parameters are the width and height of the rectangle.
 cr.fill
We fill the inside of the rectangle with the current color.
Colors
Figure: Colors

Basic shapes

The next example draws some basic shapes onto the window.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This code example draws basic shapes
# with the Cairo library
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Basic shapes"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 390, 240
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

@darea = Gtk::DrawingArea.new

@darea.signal_connect "expose-event" do
on_expose
end

add(@darea)
end

def on_expose

cr = @darea.window.create_cairo_context
draw_shapes cr
end

def draw_shapes cr

cr.set_source_rgb 0.6, 0.6, 0.6

cr.rectangle 20, 20, 120, 80
cr.rectangle 180, 20, 80, 80
cr.fill

cr.arc 330, 60, 40, 0, 2*Math::PI
cr.fill

cr.arc 90, 160, 40, Math::PI/4, Math::PI
cr.fill

cr.translate 220, 180
cr.scale 1, 0.7
cr.arc 0, 0, 50, 0, 2*Math::PI
cr.fill
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. We draw outlines in blue color, insides in white.
cr.rectangle 20, 20, 120, 80
cr.rectangle 180, 20, 80, 80
cr.fill
These lines draw a rectangle and a square.
cr.arc 330, 60, 40, 0, 2*Math::PI
cr.fill
Here the arc method draws a full circle.
cr.translate 220, 180
cr.scale 1, 0.7
cr.arc 0, 0, 50, 0, 2*Math::PI
cr.fill
The translate method moves the object to a specific point. If we want to draw an oval, we do some scaling first. Here the scale method shrinks the y axis.
Basic shapes
Figure: Basic shapes

Transparent rectangles

Transparency is the quality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.
In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. (wikipedia.org, answers.com)
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program shows transparent
# rectangles using Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Transparent rectangles"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 590, 90
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

@darea = Gtk::DrawingArea.new

@darea.signal_connect "expose-event" do
on_expose
end

add(@darea)

end

def on_expose

cr = @darea.window.create_cairo_context

for i in (1..10)
cr.set_source_rgba 0, 0, 1, i*0.1
cr.rectangle 50*i, 20, 40, 40
cr.fill
end
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In the example we will draw ten rectangles with different levels of transparency.
cr.set_source_rgba 0, 0, 1, i*0.1
The last parameter of the set_source_rgba method is the alpha transparency.
Transparent rectangles
Figure: Transparent rectangles

Donut

In the following example we create a complex shape by rotating a bunch of ellipses.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program creates a donut
# with Cairo library
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Donut"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 350, 250
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

@darea = Gtk::DrawingArea.new

@darea.signal_connect "expose-event" do
on_expose
end

add(@darea)

end

def on_expose

cr = @darea.window.create_cairo_context
cr.set_line_width 0.5

w = allocation.width
h = allocation.height

cr.translate w/2, h/2
cr.arc 0, 0, 120, 0, 2*Math::PI
cr.stroke

for i in (1..36)
cr.save
cr.rotate i*Math::PI/36
cr.scale 0.3, 1
cr.arc 0, 0, 120, 0, 2*Math::PI
cr.restore
cr.stroke
end
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In this example, we create a donut. The shape resembles a cookie, hence the name donut.
cr.translate w/2, h/2
cr.arc 0, 0, 120, 0, 2*Math::PI
cr.stroke
In the beginning there is an ellipse.
for i in (1..36)
cr.save
cr.rotate i*Math::PI/36
cr.scale 0.3, 1
cr.arc 0, 0, 120, 0, 2*Math::PI
cr.restore
cr.stroke
end
After several rotations, there is a donut.
Donut
Figure: Donut

Drawing text

In the next example, we draw some text on the window.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program draws text
# using Cairo
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Soulmate"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 370, 240
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

@darea = Gtk::DrawingArea.new

@darea.signal_connect "expose-event" do
on_expose
end

add(@darea)

end

def on_expose

cr = @darea.window.create_cairo_context

cr.set_source_rgb 0.1, 0.1, 0.1

cr.select_font_face "Purisa", Cairo::FONT_SLANT_NORMAL,
Cairo::FONT_WEIGHT_NORMAL
cr.set_font_size 13

cr.move_to 20, 30
cr.show_text "Most relationships seem so transitory"
cr.move_to 20, 60
cr.show_text "They're all good but not the permanent one"
cr.move_to 20, 120
cr.show_text "Who doesn't long for someone to hold"
cr.move_to 20, 150
cr.show_text "Who knows how to love without being told"
cr.move_to 20, 180
cr.show_text "Somebody tell me why I'm on my own"
cr.move_to 20, 210
cr.show_text "If there's a soulmate for everyone"
end
end

Gtk.init
window = RubyApp.new
Gtk.main
We display part of the lyrics from the Natasha Bedingfields Soulmate song.
cr.select_font_face "Purisa", Cairo::FONT_SLANT_NORMAL, 
Cairo::FONT_WEIGHT_NORMAL
Here we specify the font, that we use. Purisa normal.
cr.set_font_size 13 
We specify the size of the font.
cr.move_to 20, 30
We move to the point, where we will draw the text.
cr.show_text "Most relationships seem so transitory"
The show_text method draws text onto the window.
Soulmate
Figure: Soulmate
In this chapter of the Ruby GTK tutorial, we were painting with Cairo library.

Dialogs in Ruby GTK

Dialogs

In this part of the Ruby GTK programming tutorial, we will introduce dialogs.
Dialog windows or dialogs are an indispensable part of most modern GUI applications. A dialog is defined as a conversation between two or more persons. In a computer application a dialog is a window which is used to "talk" to the application. A dialog is used to input data, modify data, change the application settings etc. Dialogs are important means of communication between a user and a computer program.

Message boxes

Message dialogs are convenient dialogs that provide messages to the user of the application. The message consists of textual and image data.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows message
# dialogs
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Messages"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 100
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

table = Gtk::Table.new 2, 2, true

info = Gtk::Button.new "Information"
warn = Gtk::Button.new "Warning"
ques = Gtk::Button.new "Question"
erro = Gtk::Button.new "Error"

info.signal_connect "clicked" do
on_info
end

warn.signal_connect "clicked" do
on_warn
end

ques.signal_connect "clicked" do
on_ques
end

erro.signal_connect "clicked" do
on_erro
end

table.attach info, 0, 1, 0, 1
table.attach warn, 1, 2, 0, 1
table.attach ques, 0, 1, 1, 2
table.attach erro, 1, 2, 1, 2

add table

end

def on_info
md = Gtk::MessageDialog.new(self,
Gtk::Dialog::DESTROY_WITH_PARENT, Gtk::MessageDialog::INFO,
Gtk::MessageDialog::BUTTONS_CLOSE, "Download completed")
md.run
md.destroy
end


def on_erro
md = Gtk::MessageDialog.new(self, Gtk::Dialog::MODAL |
Gtk::Dialog::DESTROY_WITH_PARENT, Gtk::MessageDialog::ERROR,
Gtk::MessageDialog::BUTTONS_CLOSE, "Error loading file")
md.run
md.destroy
end


def on_ques
md = Gtk::MessageDialog.new(self,
Gtk::Dialog::DESTROY_WITH_PARENT, Gtk::MessageDialog::QUESTION,
Gtk::MessageDialog::BUTTONS_CLOSE, "Are you sure to quit?")
md.run
md.destroy
end

def on_warn
md = Gtk::MessageDialog.new(self,
Gtk::Dialog::DESTROY_WITH_PARENT, Gtk::MessageDialog::WARNING,
Gtk::MessageDialog::BUTTONS_CLOSE, "Unallowed operation")
md.run
md.destroy
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In our example, we will show four kinds of message dialogs. Information, Warning, Question and Error message dialogs.
info = Gtk::Button.new "Information"
warn = Gtk::Button.new "Warning"
ques = Gtk::Button.new "Question"
erro = Gtk::Button.new "Error"
We have four buttons. Each of these buttons will show a different kind of message dialog.
def on_info
md = Gtk::MessageDialog.new(self,
Gtk::Dialog::DESTROY_WITH_PARENT, Gtk::MessageDialog::INFO,
Gtk::MessageDialog::BUTTONS_CLOSE, "Download completed")
md.run
md.destroy
end
If we click on the info button, the Information dialog is displayed. The Gtk::MessageDialog::INFO specifies the type of the dialog. The Gtk::MessageDialog::BUTTONS_CLOSE specifies the button to be displayed in the dialog. The last parameter is the message dislayed. The dialog is displayed with the run method. The programmer must also call either the destroy or the hide method.
Information message dialog   Warning message dialog   Question message dialog   Error message dialog

AboutDialog

The AboutDialog displays information about the application. AboutDialogcan display a logo, the name of the application, version, copyright, website or licence information. It is also possible to give credits to the authors, documenters, translators and artists.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example demonstrates the
# AboutDialog dialog
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "About dialog"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 300, 150
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

button = Gtk::Button.new "About"
button.set_size_request 80, 30

button.signal_connect "clicked" do
on_clicked
end

fix = Gtk::Fixed.new
fix.put button, 20, 20

add fix

end

def on_clicked
about = Gtk::AboutDialog.new
about.set_program_name "Battery"
about.set_version "0.1"
about.set_copyright "(c) Jan Bodnar"
about.set_comments "Battery is a simple tool for battery checking"
about.set_website "http://www.zetcode.com"
about.set_logo Gdk::Pixbuf.new "battery.png"
about.run
about.destroy
end
end

Gtk.init
window = RubyApp.new
Gtk.main
The code example uses a AboutDialog with some of its features.
about = Gtk::AboutDialog.new
We create an AboutDialog.
about.set_program_name "Battery"
about.set_version "0.1"
about.set_copyright "(c) Jan Bodnar"
Here we specify the name, the version and the copyright.
about.set_logo Gdk::Pixbuf.new "battery.png"
This line creates a logo.
AboutDialog
Figure: AboutDialog

FontSelectionDialog

The FontSelectionDialog is a dialog for selecting fonts. It is typically used in applications, that do some text editing or formatting.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example works with the
# FontSelectionDialog
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "FontSelectionDialog"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 300, 150
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

set_border_width 10
@label = Gtk::Label.new "The only victory over love is flight."
button = Gtk::Button.new "Select font"

button.signal_connect "clicked" do
on_clicked
end

fix = Gtk::Fixed.new
fix.put button, 100, 30
fix.put @label, 30, 90
add fix

end

def on_clicked
fdia = Gtk::FontSelectionDialog.new "Select font name"
response = fdia.run

if response == Gtk::Dialog::RESPONSE_OK
font_desc = Pango::FontDescription.new fdia.font_name
if font_desc
@label.modify_font font_desc
end
end
fdia.destroy
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In the code example, we have a button and a label. We show the FontSelectionDialog by clicking on the button.
fdia = Gtk::FontSelectionDialog.new "Select font name"
We create the FontSelectionDialog.
if response == Gtk::Dialog::RESPONSE_OK
font_desc = Pango::FontDescription.new fdia.font_name
if font_desc
@label.modify_font font_desc
end
end
If we click on the OK button, the font of the label widget changes to the one, that we selected in the dialog.
FontSelectionDialog
Figure: FontSelectionDialog

ColorSelectionDialog

ColorSelectionDialog is a dialog for selecting a color.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example works with the
# ColorSelectionDialog
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "ColorSelectionDialog"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 350, 150
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

set_border_width 10
@label = Gtk::Label.new "The only victory over love is flight."
button = Gtk::Button.new "Select color"

button.signal_connect "clicked" do
on_clicked
end

fix = Gtk::Fixed.new
fix.put button, 100, 30
fix.put @label, 30, 90
add fix
end

def on_clicked
cdia = Gtk::ColorSelectionDialog.new "Select color"
response = cdia.run

if response == Gtk::Dialog::RESPONSE_OK
colorsel = cdia.colorsel
color = colorsel.current_color
@label.modify_fg Gtk::STATE_NORMAL, color
end

cdia.destroy
end
end

Gtk.init
window = RubyApp.new
Gtk.main
The example is very similar to the previous one. This time we change the color of the label.
cdia = Gtk::ColorSelectionDialog.new "Select color"
We create the ColorSelectionDialog.
if response == Gtk::Dialog::RESPONSE_OK
colorsel = cdia.colorsel
color = colorsel.current_color
@label.modify_fg Gtk::STATE_NORMAL, color
end
If the user pressed OK, we get the color value and modify the label's color.
ColorSelectionDialog
Figure: ColorSelectionDialog
In this part of the Ruby GTK tutorial, we presented dialogs.

Menus And toolbars in Ruby GTK

Menus And toolbars

In this part of the Ruby GTK programming tutorial, we will work with menus & toolbars.
A menubar is one of the most common parts of the GUI application. It is a group of commands located in various menus. While in console applications you have to remember all those arcane commands, here we have most of the commands grouped into logical parts. These are accepted standards that further reduce the amount of time spending to learn a new application.

Simple menu

In our first example, we will create a menubar with one file menu. The menu will have only one menu item. By selecting the item the application quits.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows a simple menu
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Simple menu"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(6400, 6400, 6440)

mb = Gtk::MenuBar.new

filemenu = Gtk::Menu.new
filem = Gtk::MenuItem.new "File"
filem.set_submenu filemenu

exit = Gtk::MenuItem.new "Exit"
exit.signal_connect "activate" do
Gtk.main_quit
end

filemenu.append exit

mb.append filem

vbox = Gtk::VBox.new false, 2
vbox.pack_start mb, false, false, 0

add vbox
end
end

Gtk.init
window = RubyApp.new
Gtk.main
This is a small example with minimal menubar functionality.
mb = Gtk::MenuBar.new
MenuBar widget is created. This is a container for the menus.
filemenu = Gtk::Menu.new
filem = Gtk::MenuItem.new "File"
filem.set_submenu filemenu
Toplevel MenuItem is created.
exit = Gtk::MenuItem.new "Exit"
exit.signal_connect "activate" do
Gtk.main_quit
end

filemenu.append exit
Exit MenuItem is created and appended to the File MenuItem.
mb.append filem
Toplevel MenuItem is appended to the MenuBarwidget.
vbox = Gtk::VBox.new false, 2
vbox.pack_start mb, false, false, 0
Unlike in other toolkits, we have to take care of the layout management of the menubar ourselves. We put the menubar into the vertical box.
Simple menu
Figure: Simple menu

Submenu

Our final example demonstrates how to create a submenu.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows a submenu
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Submenu"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(6400, 6400, 6440)

mb = Gtk::MenuBar.new

filemenu = Gtk::Menu.new
filem = Gtk::MenuItem.new "File"
filem.set_submenu filemenu

mb.append filem

imenu = Gtk::Menu.new

importm = Gtk::MenuItem.new "Import"
importm.set_submenu imenu

inews = Gtk::MenuItem.new "Import news feed..."
ibookmarks = Gtk::MenuItem.new "Import bookmarks..."
imail = Gtk::MenuItem.new "Import mail..."

imenu.append inews
imenu.append ibookmarks
imenu.append imail

filemenu.append importm

exit = Gtk::MenuItem.new "Exit"
exit.signal_connect "activate" do
Gtk.main_quit
end

filemenu.append exit

vbox = Gtk::VBox.new false, 2
vbox.pack_start mb, false, false, 0

add vbox
end
end

Gtk.init
window = RubyApp.new
Gtk.main
Submenu creation.
imenu = Gtk::Menu.new
A submenu is a Menu.
importm = Gtk::MenuItem.new "Import"
importm.set_submenu imenu
It is a submenu of a menu item, which belogs to toplevel file menu.
inews = Gtk::MenuItem.new "Import news feed..."
ibookmarks = Gtk::MenuItem.new "Import bookmarks..."
imail = Gtk::MenuItem.new "Import mail..."

imenu.append inews
imenu.append ibookmarks
imenu.append imail
Submenu has its own menu items.
Submenu
Figure: Submenu

Image menu

In the next example, we will further explore the menus. We will add images and accelerators to our menu items. Accelerators are keyboard shortcuts for activating a menu item.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows a menu with
# images, accelerators and a separator
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Image menu"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(6400, 6400, 6440)

mb = Gtk::MenuBar.new

filemenu = Gtk::Menu.new
filem = Gtk::MenuItem.new "File"
filem.set_submenu filemenu

agr = Gtk::AccelGroup.new
add_accel_group agr

newi = Gtk::ImageMenuItem.new Gtk::Stock::NEW, agr
key, mod = Gtk::Accelerator.parse "N"
newi.add_accelerator("activate", agr, key,
mod, Gtk::ACCEL_VISIBLE)
filemenu.append newi

openm = Gtk::ImageMenuItem.new Gtk::Stock::OPEN, agr
key, mod = Gtk::Accelerator.parse "O"
openm.add_accelerator("activate", agr, key,
mod, Gtk::ACCEL_VISIBLE)
filemenu.append openm

sep = Gtk::SeparatorMenuItem.new
filemenu.append sep

exit = Gtk::ImageMenuItem.new Gtk::Stock::QUIT, agr
key, mod = Gtk::Accelerator.parse "Q"
exit.add_accelerator("activate", agr, key,
mod, Gtk::ACCEL_VISIBLE)

exit.signal_connect "activate" do
Gtk.main_quit
end
filemenu.append exit

mb.append filem

vbox = Gtk::VBox.new false, 2
vbox.pack_start mb, false, false, 0

add vbox
end
end

Gtk.init
window = RubyApp.new
Gtk.main
Our example shows a toplevel menu item with three sublevel menu items. Each of the menu items has a image and an accelerator. The accelerator for the quit menu item is active.
agr = Gtk::AccelGroup.new
add_accel_group agr
To work with accelerators, we create a global AccelGroupobject. It will be used later.
newi = Gtk::ImageMenuItem.new Gtk::Stock::NEW, agr
key, mod = Gtk::Accelerator.parse "N"
newi.add_accelerator("activate", agr, key,
mod, Gtk::ACCEL_VISIBLE)
filemenu.append newi
ImageMenuItem is created. The image comes from the stock of images. We create also a Ctrl+N accelerator.
sep = Gtk::SeparatorMenuItem.new
filemenu.append sep
These lines create a separator. It is used to put menu items into logical groups.
Image menu
Figure: Image menu
Menus group commands that we can use in application. Toolbars provide a quick access to the most frequently used commands.

Simple toolbar

Next we create a simple toolbar.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows a toolbar
# widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Toolbar"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

toolbar = Gtk::Toolbar.new
toolbar.set_toolbar_style Gtk::Toolbar::Style::ICONS

newtb = Gtk::ToolButton.new Gtk::Stock::NEW
opentb = Gtk::ToolButton.new Gtk::Stock::OPEN
savetb = Gtk::ToolButton.new Gtk::Stock::SAVE
sep = Gtk::SeparatorToolItem.new
quittb = Gtk::ToolButton.new Gtk::Stock::QUIT

toolbar.insert 0, newtb
toolbar.insert 1, opentb
toolbar.insert 2, savetb
toolbar.insert 3, sep
toolbar.insert 4, quittb

quittb.signal_connect "clicked" do
Gtk.main_quit
end

vbox = Gtk::VBox.new false, 2
vbox.pack_start toolbar, false, false, 0

add(vbox)
end
end

Gtk.init
window = RubyApp.new
Gtk.main

The example shows a toolbar and four tool buttons.
toolbar = Gtk::Toolbar.new
A Toolbar widget is created.
toolbar.set_toolbar_style Gtk::Toolbar::Style::ICONS
On toolbar, we show only icons. No text.
newtb = Gtk::ToolButton.new Gtk::Stock::NEW
A ToolButton with an image from stock is created. The image comes from the built-in stock of images.
sep = Gtk::SeparatorToolItem.new
This is a separator. It can be used to put toolbar buttons into logical groups.
toolbar.insert 0, newtb
toolbar.insert 1, opentb
...
Toolbar buttons are inserted into the toolbar widget.
Toolbar
Figure: Toolbar

Undo redo

The following example demonstrates, how we can deactivate toolbar buttons on the toolbar. It is a common practise in GUI programming. For example the save button. If we save all changes of our document to the disk, the save button is deactivated in most text editors. This way the application indicates to the user, that all changes are already saved.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example shows how to
# activate/deactivate a ToolButton
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window


def initialize
super

set_title "Undo redo"
signal_connect "destroy" do
Gtk.main_quit
end

@count = 2

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

toolbar = Gtk::Toolbar.new
toolbar.set_toolbar_style Gtk::Toolbar::Style::ICONS

@undo = Gtk::ToolButton.new Gtk::Stock::UNDO
@redo = Gtk::ToolButton.new Gtk::Stock::REDO
sep = Gtk::SeparatorToolItem.new
quit = Gtk::ToolButton.new Gtk::Stock::QUIT

toolbar.insert 0, @undo
toolbar.insert 1, @redo
toolbar.insert 2, sep
toolbar.insert 3, quit

@undo.signal_connect "clicked" do
on_undo
end

@redo.signal_connect "clicked" do
on_redo
end

quit.signal_connect "clicked" do
Gtk.main_quit
end

vbox = Gtk::VBox.new false, 2
vbox.pack_start toolbar, false, false, 0

self.add vbox

end

def on_undo

@count = @count - 1

if @count <= 0
@undo.set_sensitive false
@redo.set_sensitive true
end
end


def on_redo
@count = @count + 1

if @count >= 5
@redo.set_sensitive false
@undo.set_sensitive true
end
end
end

Gtk.init
window = RubyApp.new
Gtk.main
Our example creates undo and redo buttons from the GTK stock resources. After several clicks each of the buttons is deactivated. The buttons are grayed out.
@count = 2
The @count variable decides, which button is activated or deactivated.
@undo = Gtk::ToolButton.new Gtk::Stock::UNDO
@redo = Gtk::ToolButton.new Gtk::Stock::REDO
We have two tool buttons. Undo and redo tool buttons. Images come from the stock resources.
@undo.signal_connect "clicked" do
on_undo
end
Clicking on the undo button, we trigger the on_undo method.
if @count <= 0
@undo.set_sensitive false
@redo.set_sensitive true
end
To activate or deactivate a widget, we use the set_sensitive method
Undo redo
Figure: Undo redo
In this chapter of the Ruby GTK tutorial, we showed, how to work with menus & toolbars.

Widgets in Ruby GTK

Widgets

In this part of the Ruby GTK programming tutorial, we will introduce some widgets.
Widgets are basic building blocks of a GUI application. Over the years, several widgets became a standard in all toolkits on all OS platforms. For example a button, a check box or a scroll bar. The GTK toolkit's philosophy is to keep the number of widgets at a minimum level. More specialized widgets are created as custom GTK widgets.

CheckButton

CheckButton is a widget, that has two states. On and Off. The On state is visualised by a check mark. It is used to denote some boolean property.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program toggles the title of the
# window with the CheckButton widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: April 2009

require 'gtk2'

class RubyApp < Gtk::Window
def initialize
super

set_title "CheckButton"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER
show_all
end


def init_ui

fixed = Gtk::Fixed.new
add fixed

cb = Gtk::CheckButton.new "Show title"
cb.set_active true
cb.set_can_focus false
cb.signal_connect("clicked") do |w|
on_clicked(w)
end

fixed.put cb, 50, 50

end

def on_clicked sender

if sender.active?
self.set_title "Check Button"
else
self.set_title ""
end
end
end

Gtk.init
window = RubyApp.new
Gtk.main
We will display a title in the titlebar of the window, depending on the state of the CheckButton.
cb = Gtk::CheckButton.new "Show title"
CheckButton widget is created.
cb.set_active true
The title is visible by default, so we check the check button by default.
if sender.active?
self.set_title "Check Button"
else
self.set_title ""
end
We show the title, if the button is checked.
CheckButton
Figure: CheckButton

Label

The Label widget shows text.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example demonstrates the Label widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'

$lyrics = %{Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray

cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore

I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good}


class RubyApp < Gtk::Window

def initialize
super

set_title "You know I'm no Good"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

set_border_width 10
label = Gtk::Label.new $lyrics
add label

end
end

Gtk.init
window = RubyApp.new
Gtk.main

The code example shows some lyrics on the window.
 $lyrics = %{Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
...
We create a multi line text.
set_border_width 10
The Label is surrounded by some empty space.
label = Gtk::Label.new $lyrics
add label
The Label widget is created and added to the window.
Label Widget
Figure: Label Widget

Entry

The Entry is a single line text entry field. This widget is used to enter textual data.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example demonstrates the Entry widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Entry"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

fixed = Gtk::Fixed.new

label = Gtk::Label.new "..."
fixed.put label, 60, 40

entry = Gtk::Entry.new
fixed.put entry, 60, 100

entry.signal_connect "key-release-event" do |w, e|
on_key_release(w, e, label)
end

add(fixed)
end

def on_key_release sender, event, label
label.set_text sender.text
end
end

Gtk.init
window = RubyApp.new
Gtk.main
This example shows an entry widget and a label. The text that we key in the entry is displayed immediately in the label widget.
entry = Gtk::Entry.new
Entry widget is created.
entry.signal_connect "key-release-event" do |w, e|
on_key_release(w, e, label)
end
We plug the on_key_release method to the key-release-event of the Entry widget.
def on_key_release sender, event, label
label.set_text sender.text
end
We get the text from the Entry widget and set it to the label.
Entry Widget
Figure: Entry Widget

Image

The Image widget shows an image.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example demonstrates the Image widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Red Rock"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

set_border_width 2

begin
image = Gtk::Image.new "redrock.png"
rescue
puts "cannot load image"
exit
end

add image
end

end

Gtk.init
window = RubyApp.new
Gtk.main
In our example, we show an image on the window.
set_border_width 2
We put some empty border around the image.
begin
image = Gtk::Image.new "redrock.png"
rescue
puts "cannot load image"
exit
end
The Image widget is created. IO operations are error prone, so we handle the possible exceptions.
add image
Widget is added to the container.
Image widget
Figure: Image widget

ComboBox

ComboBox is a widget that allows the user to choose from a list of options.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This example demonstrates the ComboBox widget
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "ComboBox"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

fixed = Gtk::Fixed.new
label = Gtk::Label.new '-'
fixed.put label, 50, 140

cb = Gtk::ComboBox.new
cb.signal_connect "changed" do |w, e|
on_changed(w, e, label)
end

cb.append_text 'Ubuntu'
cb.append_text 'Mandriva'
cb.append_text 'Redhat'
cb.append_text 'Gento'
cb.append_text 'Mint'

fixed.put cb, 50, 30

add fixed

end

def on_changed sender, event, label
label.set_label sender.active_text
end
end

Gtk.init
window = RubyApp.new
Gtk.main
The example shows a combo box and a label. The combo box has a list of five options. These are the names of Linux Distros. The label widget shows the selected option from the combo box.
cb = Gtk::ComboBox.new
The ComboBox widget is created.
cb.append_text 'Ubuntu'
cb.append_text 'Mandriva'
cb.append_text 'Redhat'
cb.append_text 'Gento'
cb.append_text 'Mint'
It is filled with data.
def on_changed sender, event, label
label.set_label sender.active_text
end
Inside the on_changed method, we get the selected text out of the combo box and set it to the label.
ComboBox
Figure: ComboBox
In this chapter of the Ruby GTK tutorial, we showed some basic widgets.

Layout management in Ruby GTK

Layout management

In this chapter we will show how to lay out our widgets in windows or dialogs.
When we design the GUI of our application, we decide what widgets we will use and how we will organize those widgets in the application. To organize our widgets, we use specialized non visible widgets called layout containers. In this chapter, we will mention Alignment, Fixed, VBox and Table.

Fixed

The Fixed container places child widgets at fixed positions and with fixed sizes. This container performs no automatic layout management. In most applications, we don't use this container. There are some specialized areas, where we use it. For example games, specialized applications that work with diagrams, resizable components that can be moved (like a chart in a spreadsheet application), small educational examples.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# In this program, we lay out widgets
# using absolute positioning
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Fixed"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 300, 280
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(6400, 6400, 6440)

begin
bardejov = Gdk::Pixbuf.new "bardejov.jpg"
rotunda = Gdk::Pixbuf.new "rotunda.jpg"
mincol = Gdk::Pixbuf.new "mincol.jpg"
rescue IOError => e
puts e
puts "cannot load images"
exit
end

image1 = Gtk::Image.new bardejov
image2 = Gtk::Image.new rotunda
image3 = Gtk::Image.new mincol

fixed = Gtk::Fixed.new

fixed.put image1, 20, 20
fixed.put image2, 40, 160
fixed.put image3, 170, 50

add fixed

end
end

Gtk.init
window = RubyApp.new
Gtk.main
In our example, we show three small images on the window. We explicitely specify the x, y coordinates, where we place these images.
modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(6400, 6400, 6440)
For better visual experience, we change the background color to dark gray.
bardejov = Gdk::Pixbuf.new "bardejov.jpg"
We load the image from the disk to the Pixbuf object.
image1 = Gtk::Image.new bardejov
image2 = Gtk::Image.new rotunda
image3 = Gtk::Image.new mincol
The Image is a widget, that is used to display images. It takes Pixbuf object in the constructor.
fixed = Gtk::Fixed.new
We create the Fixed container.
fixed.put image1, 20, 20
We place the first image at x=20, y=20 coordinates.
 add fixed
Finally, we add the Fixed container to the Window.
Fixed
Figure: Fixed

Buttons

The Alignment container controls the alignment and the size of its child widget.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# In this program, we position two buttons
# in the bottom right corner of the window.
# We use horizontal and vertical boxes.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Buttons"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 260, 150
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

vbox = Gtk::VBox.new false, 5
hbox = Gtk::HBox.new true, 3

valign = Gtk::Alignment.new 0, 1, 0, 0
vbox.pack_start valign

ok = Gtk::Button.new "OK"
ok.set_size_request 70, 30
close = Gtk::Button.new "Close"

hbox.add ok
hbox.add close

halign = Gtk::Alignment.new 1, 0, 0, 0
halign.add hbox

vbox.pack_start halign, false, false, 3

add vbox
end
end

Gtk.init
window = RubyApp.new
Gtk.main
In the code example, we place two buttons into the right bottom corner of the window. To accomplish this, we use one horizontal box and one vertical box and two alignment containers.
valign = Gtk::Alignment.new 0, 1, 0, 0
This will put the child widget to the bottom.
vbox.pack_start valign
Here we place the Alignment widget into the vertical box.
hbox = Gtk::HBox.new true, 3 
...
ok = Gtk::Button.new "OK"
ok.set_size_request 70, 30
close = Gtk::Button.new "Close"

hbox.add ok
hbox.add close
We create a horizontal box and put two buttons inside it.
halign = Gtk::Alignment.new 1, 0, 0, 0
halign.add hbox

vbox.pack_start halign, false, false, 3
This will create an alignment container that will place its child widget to the right. We add the horizontal box into the alignment container and pack the alignment container into the vertical box. We must keep in mind that the alignment container takes only one child widget. That's why we must use boxes.
Buttons
Figure: Buttons

Calculator skeleton

The Table widget arranges widgets in rows and columns.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# In this program we create a skeleton of
# a calculator. We use the Table widget.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Calculator"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 300, 250
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

vbox = Gtk::VBox.new false, 2

mb = Gtk::MenuBar.new
filemenu = Gtk::Menu.new
file = Gtk::MenuItem.new "File"
file.set_submenu filemenu
mb.append file

vbox.pack_start mb, false, false, 0

table = Gtk::Table.new 5, 4, true

table.attach Gtk::Button.new("Cls"), 0, 1, 0, 1
table.attach Gtk::Button.new("Bck"), 1, 2, 0, 1
table.attach Gtk::Label.new, 2, 3, 0, 1
table.attach Gtk::Button.new("Close"), 3, 4, 0, 1

table.attach Gtk::Button.new("7"), 0, 1, 1, 2
table.attach Gtk::Button.new("8"), 1, 2, 1, 2
table.attach Gtk::Button.new("9"), 2, 3, 1, 2
table.attach Gtk::Button.new("/"), 3, 4, 1, 2

table.attach Gtk::Button.new("4"), 0, 1, 2, 3
table.attach Gtk::Button.new("5"), 1, 2, 2, 3
table.attach Gtk::Button.new("6"), 2, 3, 2, 3
table.attach Gtk::Button.new("*"), 3, 4, 2, 3

table.attach Gtk::Button.new("1"), 0, 1, 3, 4
table.attach Gtk::Button.new("2"), 1, 2, 3, 4
table.attach Gtk::Button.new("3"), 2, 3, 3, 4
table.attach Gtk::Button.new("-"), 3, 4, 3, 4

table.attach Gtk::Button.new("0"), 0, 1, 4, 5
table.attach Gtk::Button.new("."), 1, 2, 4, 5
table.attach Gtk::Button.new("="), 2, 3, 4, 5
table.attach Gtk::Button.new("+"), 3, 4, 4, 5

vbox.pack_start Gtk::Entry.new, false, false, 0

vbox.pack_end table, true, true, 0

add vbox

end
end

Gtk.init
window = RubyApp.new
Gtk.main
We use the Table widget to create a calculator skeleton.
table = Gtk::Table.new 5, 4, true
We create a table widget with 5 rows and 4 columns. The third parameter is the homogenous parameter. If set to true, all the widgets in the table are of same size. The size of all widgets is equal to the largest widget in the table container.
table.attach Gtk::Button.new("Cls"), 0, 1, 0, 1
We attach a button to the table container. To the top-left cell of the table. The first two parameters are the left and right sides of the cell, the last two parameters are the top and left sides of the cell.
vbox.pack_end table, true, true, 0
We pack the table widget into the vertical box.
Calculator skeleton
Figure: Calculator skeleton

Windows

Next we will create a more advanced example. We show a window, that can be found in the JDeveloper IDE.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This is a more complicated layout example.
# We use Alignment and Table widgets.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'


class RubyApp < Gtk::Window

def initialize
super

set_title "Windows"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

set_default_size 300, 250
set_window_position Gtk::Window::POS_CENTER

show_all
end

def init_ui

set_border_width 15

table = Gtk::Table.new 8, 4, false
table.set_column_spacings 3

title = Gtk::Label.new "Windows"

halign = Gtk::Alignment.new 0, 0, 0, 0
halign.add title

table.attach(halign, 0, 1, 0, 1, Gtk::FILL,
Gtk::FILL, 0, 0)

frame = Gtk::Frame.new
table.attach(frame, 0, 2, 1, 3, Gtk::FILL | Gtk::EXPAND,
Gtk::FILL | Gtk::EXPAND, 1, 1)

activate = Gtk::Button.new "Activate"
activate.set_size_request 50, 30
table.attach(activate, 3, 4, 1, 2, Gtk::FILL,
Gtk::SHRINK, 1, 1)

valign = Gtk::Alignment.new 0, 0, 0, 0
close = Gtk::Button.new "Close"
close.set_size_request 70, 30
valign.add close
table.set_row_spacing 1, 3
table.attach(valign, 3, 4, 2, 3, Gtk::FILL,
Gtk::FILL | Gtk::EXPAND, 1, 1)

halign2 = Gtk::Alignment.new 0, 1, 0, 0
help = Gtk::Button.new "Help"
help.set_size_request 70, 30
halign2.add help
table.set_row_spacing 3, 6
table.attach(halign2, 0, 1, 4, 5, Gtk::FILL,
Gtk::FILL, 0, 0)

ok = Gtk::Button.new "OK"
ok.set_size_request 70, 30
table.attach(ok, 3, 4, 4, 5, Gtk::FILL,
Gtk::FILL, 0, 0)

add table
end
end

Gtk.init
window = RubyApp.new
Gtk.main
The code example shows, how we can create a similar window in Ruby GTK.
table = Gtk::Table.new 8, 4, false
table.set_column_spacings 3
The example is based on the Table container. There will be 3px space between columns.
title = Gtk::Label.new "Windows"

halign = Gtk::Alignment.new 0, 0, 0, 0
halign.add title

table.attach(halign, 0, 1, 0, 1, Gtk::FILL,
Gtk::FILL, 0, 0)
This code creates a label, that is aligned to the left. The label is placed in the first row of the Table container.
frame = Gtk::Frame.new
table.attach(frame, 0, 2, 1, 3, Gtk::FILL | Gtk::EXPAND,
Gtk::FILL | Gtk::EXPAND, 1, 1)
The frame view widget spans two rows and two columns.
valign = Gtk::Alignment.new 0, 0, 0, 0
close = Gtk::Button.new "Close"
close.set_size_request 70, 30
valign.add close
table.set_row_spacing 1, 3
table.attach(valign, 3, 4, 2, 3, Gtk::FILL,
Gtk::FILL | Gtk::EXPAND, 1, 1)
We put the close button next to the frame widget into the fourth column. (we count from zero) We add the button into the alignment widget, so that we can align it to the top.
Windows
Figure: Windows
In this part of the Ruby GTK tutorial, we mentioned layout management of widgets.

Introduction to Ruby GTK

Introduction to Ruby GTK

In this part of the Ruby GTK programming tutorial, we will introduce the GTK library and create our first programs using the Ruby programming language.
The purpose of this tutorial is to get you started with the GTK and Ruby. Images for the Nibbles game can be downloaded here.

About

GTK is one of the leading toolkits for creating graphical user interfaces. Ruby is a popular scripting language.

Simple example

In the first example, we create a simple window. The window is centered on the screen.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program centers a window on
# the screen
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: April 2009

require 'gtk2'

class RubyApp < Gtk::Window

def initialize
super

set_title "Center"
signal_connect "destroy" do
Gtk.main_quit
end

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show
end
end

Gtk.init
window = RubyApp.new
Gtk.main
This example shows a 250x200 px window in the centre of the screen.
require 'gtk2'
The require keyword imports necessery types that we will use in the application.
class RubyApp < Gtk::Window
The example inherits from a Window. The Window is a toplevel container.
set_title "Center"
We set a title for the window.
signal_connect "destroy" do 
Gtk.main_quit
end
The destroy event is triggered, when we click on the close button in the titlebar. Or press Alt + F4. The method main_quit quits the application for good.
set_default_size 250, 200
We set a default size for the application window.
set_window_position Gtk::Window::POS_CENTER
This line centers the window on the screen.
 show
When everything is ready, we show the window on the screen.
Gtk.init
window = RubyApp.new
Gtk.main
These three lines set up the application.

Creating a Tooltip

The second example will show a tooltip. A tooltip is a small rectangular window, which gives a brief information about an object. It is usually a GUI component. It is part of the help system of the application.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This code shows a tooltip on
# a window and a button
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'

class RubyApp < Gtk::Window

def initialize
super

set_title "Tooltips"
signal_connect "destroy" do
Gtk.main_quit
end

fixed = Gtk::Fixed.new
add fixed

button = Gtk::Button.new "Button"
button.set_size_request 80, 35
button.set_tooltip_text "Button widget"

fixed.put button, 50, 50

set_tooltip_text "Window widget"
set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER

show_all

end
end

Gtk.init
window = RubyApp.new
Gtk.main
The example creates a window. If we hover a mouse pointer over the area of the window, a tooltip pops up.
button.set_tooltip_text "Button widget"
We set a tooltip with the set_tooltip_text method.
Tooltip
Figure: Tooltip

Quit button

In the last example of this section, we will create a quit button. When we press this button, the application terminates.
#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This program creates a quit
# button. When we press the button,
# the application terminates.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'gtk2'

class RubyApp < Gtk::Window

def initialize
super

set_title "Quit button"
signal_connect "destroy" do
Gtk.main_quit
end

init_ui

show_all
end

def init_ui

fixed = Gtk::Fixed.new
add fixed

button = Gtk::Button.new "Quit"
button.set_size_request 80, 35
button.signal_connect "clicked" do
Gtk.main_quit
end

fixed.put button, 50, 50

set_default_size 250, 200
set_window_position Gtk::Window::POS_CENTER
end
end

Gtk.init
window = RubyApp.new
Gtk.main
We use a Button widget. This is a very common widget. It shows a text label, image or both.
init_ui
We delegate the creation of the user interface to the init_ui method.
show_all
We have two options. Either to call show on all widgets, or to call show_all, which shows the container and all its children.
button = Gtk::Button.new "Quit"
Here we create a button widget.
button.set_size_request 80, 35 
We set a size for a button.
button.signal_connect "clicked" do 
Gtk.main_quit
end
We plug the main_quit method to the button clicked event.
fixed.put button, 50, 50 
We put the quit button into the fixed container at x=50, y=50.
Quit button
Figure: Quit button
This section was an introduction to the GTK library with the Ruby language.