Menus & toolbars in Ruby GTK

In this part of the Ruby GTK programming tutorial, we will work with menus & toolbars.

A common part in a GUI application is a menubar. A menubar consists of objects called menus. Top-level menus have their labels on the menubar. The menus have menu items—commands that perform a specific action inside the application. Menus can also have submenus, which have their own menu items.

Simple menubar

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 creates a simple menubar.

Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''

require 'gtk3'


class RubyApp < Gtk::Window

    def initialize
        super

        init_ui
    end
    
    def init_ui

        override_background_color :normal, 
            Gdk::RGBA.new(0.2, 0.2, 0.2, 1)
        
        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::Box.new :vertical, 2

        vbox.pack_start mb, :expand => false, 
            :fill => false, :padding => 0

        add vbox
        
        set_title "Simple menubar"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end        

        set_default_size 300, 200
        set_window_position :center
        
        show_all        
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main    

This is a small example with minimal menubar functionality.

mb = Gtk::MenuBar.new

A Gtk::MenuBar widget is created. This is a container for the menus.

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

A toplevel Gtk::MenuItem containing one Gtk::Menu is created.

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

filemenu.append exit

The Exit Gtk::MenuItem is created and appended to the File Gtk::MenuItem.

mb.append filem

A toplevel Gtk::MenuItem is appended to the Gtk::MenuBar widget.

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

We put the menubar into the vertical box.

Simple menu
Figure: Simple menu

Submenu

The following 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: May 2014
'''

require 'gtk3'


class RubyApp < Gtk::Window

    def initialize
        super
        
        init_ui
    end
    
    def init_ui
    
        override_background_color :normal, 
            Gdk::RGBA.new(0.2, 0.2, 0.2, 1)
        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::Box.new :vertical, 2

        vbox.pack_start mb, :expand => false, 
            :fill => false, :padding => 0

        add vbox

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

        set_default_size 350, 250
        set_window_position :center
        show_all        
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main

A submenu is a menu inside another menu.

imenu = Gtk::Menu.new

A submenu is a Gtk::Menu.

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

It is a submenu of a menu item which belogs to the 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

The 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: May 2014
'''

require 'gtk3'


class RubyApp < Gtk::Window

    def initialize
        super
    
        init_ui
    end
    
    def init_ui
    
        override_background_color :normal, 
            Gdk::RGBA.new(0.2, 0.2, 0.2, 1)
        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 :stock_id => Gtk::Stock::NEW, 
            :accel_group => agr
        key, mod = Gtk::Accelerator.parse "N"

        newi.add_accelerator "activate", agr, key,
           mod, Gtk::AccelFlags::VISIBLE
        filemenu.append newi

        openm = Gtk::ImageMenuItem.new :stock_id => Gtk::Stock::OPEN, 
            :accel_group => agr
        key, mod = Gtk::Accelerator.parse "O"
        openm.add_accelerator "activate", agr, key, 
            mod, Gtk::AccelFlags::VISIBLE
        filemenu.append openm

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

        exit = Gtk::ImageMenuItem.new :stock_id => Gtk::Stock::QUIT, 
            :accel_group => agr
        key, mod = Gtk::Accelerator.parse "Q"
        
        exit.add_accelerator "activate", agr, key, 
            mod, :visible

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

        mb.append filem

        vbox = Gtk::Box.new :vertical, 2
        vbox.pack_start mb, :expand => false, :fill => false, 
            :padding => 0

        add vbox
        
        set_title "Image menu"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end        
        
        set_default_size 300, 200
        set_window_position :center
        show_all        
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main

Our example shows a toplevel menu item with three 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 Gtk::AccelGroup object. It will be used later.

newi = Gtk::ImageMenuItem.new :stock_id => Gtk::Stock::NEW, 
    :accel_group => agr
key, mod = Gtk::Accelerator.parse "N"

newi.add_accelerator "activate", agr, key,
    mod, Gtk::AccelFlags::VISIBLE
filemenu.append newi

A Gtk::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 which is used to put menu items into logical groups.

Image menu
Figure: Image menu

Simple toolbar

Menus group commands that we can use in application. Toolbars provide a quick access to the most frequently used commands. Next we create a simple toolbar.

#!/usr/bin/ruby

'''
ZetCode Ruby GTK tutorial

This example creates a simple toolbar.

Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''

require 'gtk3'


class RubyApp < Gtk::Window

    def initialize
        super
        
        init_ui
    end
    
    def init_ui
    
        toolbar = Gtk::Toolbar.new
        toolbar.set_toolbar_style Gtk::Toolbar::Style::ICONS

        newtb = Gtk::ToolButton.new :stock_id => Gtk::Stock::NEW
        opentb = Gtk::ToolButton.new :stock_id => Gtk::Stock::OPEN
        savetb = Gtk::ToolButton.new :stock_id => Gtk::Stock::SAVE
        sep = Gtk::SeparatorToolItem.new
        quittb = Gtk::ToolButton.new :stock_id => Gtk::Stock::QUIT
       
        toolbar.insert newtb, 0
        toolbar.insert opentb, 1
        toolbar.insert savetb, 2
        toolbar.insert sep, 3
        toolbar.insert quittb, 4
        
        quittb.signal_connect "clicked" do
            Gtk.main_quit
        end

        vbox = Gtk::Box.new :vertical, 2
        vbox.pack_start toolbar, :expand => false, 
            :fill => false, :padding => 0

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

        set_default_size 300, 200
        set_window_position :center
        
        show_all        
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main

The example shows a toolbar and four tool buttons.

toolbar = Gtk::Toolbar.new

A Gtk::Toolbar widget is created.

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

On the toolbar we only show icons.

newtb = Gtk::ToolButton.new :stock_id => Gtk::Stock::NEW

A Gtk::ToolButton with an image from the 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 newtb, 0
toolbar.insert opentb, 1
...

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 Gtk::ToolButton.

Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''

require 'gtk3'


class RubyApp < Gtk::Window
    
    def initialize
        super
    
        @count = 2
        
        init_ui
    end
    
    def init_ui
    
        toolbar = Gtk::Toolbar.new
        toolbar.set_toolbar_style Gtk::Toolbar::Style::ICONS

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

        toolbar.insert @undo, 0
        toolbar.insert @redo, 1
        toolbar.insert sep, 2
        toolbar.insert quit, 3
        
        @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::Box.new :vertical, 2
        vbox.pack_start toolbar, :expand => false, 
            :fill => false, :padding => 0

        self.add vbox
        

        set_default_size 300, 200
        set_window_position :center
        
        show_all        
        
        set_title "Undo redo"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end
    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 :stock_id => Gtk::Stock::UNDO
@redo = Gtk::ToolButton.new :stock_id => Gtk::Stock::REDO

We have two tool buttons: undo and redo tool buttons. The 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.