Chapter 7. Gtk2::Button

Objective

This lesson will look at the Gtk2::Button class. We will also use one of Gtk2::Button's subclasses called Gtk2::CheckButton. This in itself is a subclass of Gtk2::ToggleButton. So we have Gtk2::Button->Gtk2::ToggleButton->Gtk2::CheckButton in the class hierarchy.

This lesson will also introduce three new widget classes. They are Gtk2::Frame, Gtk2::ScrolledWindow and Gtk2::Image. Last but not least, we will introduce the reader to the Gtk2::Stock items and the cursor (Gtk2::Gdk::Cursor).

Table 7-1. Gtk2 object classes used

Gtk2 Class Name
Gtk2::Window
Gtk2::VBox
Gtk2::Button
Gtk2::CheckButton
Gtk2::Frame
Gtk2::Image
Gtk2::ScrolledWindow
Gtk2::Gdk::Cursor
Gtk2::Stock

General discussion on some of the widget classes

Gtk2::Button

The Gtk2::Button is a subclass of Gtk2::Bin, so we can add only one child widget to it. By default, the text specified with the Gtk2::Button ->new() method, will be added as a Gtk2::Label class object. The newer versions of Gtk2-Perl allows you to add a Gtk2::Image class object with the Gtk2::Button ->set_image method.

This is a nice feature to quickly create a picture button, or a button with a picture and a label. This saves time, as previously you first had to create a Gtk2::HBox class object, then add a Gtk2::Image and Gtk2::Label instance, after that, add the Gtk2::HBox to the Gtk2::Button class object to create a picture button with a label next to it.

We can set the cursor with the set_cursor method when it enter and leave the button. This simulates the effect of a hyper link, as we will see in the sample program. The button also feature the mnemonic functionality that was discussed as part of Chapter 6.

Gtk2::Frame

This class is one of those cosmetic classes, it is a Gtk2::Bin subclass, so you can (just like Gtk2::Window) add only one child widget to it.

Other cosmetic classes include Gtk2::HSeparator and Gtk2::VSeparator.

The Gtk2::Frame does not have much features. You can set its outline with the $frame->set_shadow_type ($type). Another point worth mentioning is the label that traditionally accompany the Gtk2::Frame.( widget = Gtk2::Frame->new ($label=undef) or $frame->set_label ($label=undef) ) This is actually only a default. You can add any widget to the frame where the label usually resides. This is done by the $frame->set_label_widget ($label_widget) method.

This feature is also available on the tabs of Gtk2::NoteBook. This allows you to add a Gtk2::HBox containing a label and a close button for instance to each tab.

In our sample program we add a Gtk2::CheckButton to it. We will manipulate the appearance of the checkbutton as it gets clicked.

Gtk2::Image

This class will be looked at in depth later on. In our sample program, we will create an instance of it by getting its data from a file.

Gtk2::ScrolledWindow

When one of your widget's length may change or you don't know what its initial size may be, or it is simply to long to fit onto your screen, you can put this long or wide widget into a Gtk2::ScrolledWindow.

As you might have guessed, this is also a Gtk2::Container subclass. There are basically three methods of importance.

  1. $scrolled_window->set_policy ($hscrollbar_policy, $vscrollbar_policy) This can take the option of always , automatic or never. The rule of thumb is to set the side you want to scroll to automatic and the one you don't want to scroll to never.

  2. $scrolled_window->set_shadow_type ($type) This is used to make the scrolled window stand more out using a choice between none , in, etched-in and etched-out.

  3. $scrolled_window->add_with_viewport ($child) When you want to add a NON-SCROLLING widget, you do not use the Gtk2::Container's add method. This is the method you should use to add the NON-SCROLLING child widget. [1]

Gtk2::Gdk::Cursor

The cursor may change depending over which widget it is hovering. The Gtk2::Entry widget is an example where it will change. You can also specify what it should be.

In our sample program, we simulate the feel of a web browser by changing the cursor to a hand as soon as we enter the checkbutton's area, and change it back again as when we leave the checkbutton's area with the mouse.

$check_button->signal_connect('enter' => sub {$check_button->window->set_cursor($hand_cursor);});
You will notice that we call the window property of $check_button. This is Gtk2::Gdk::Window that we reference. We then use the set_cursor method to set the cursor. To get the cursor back to normal, you do not have to remember what it was previously, just set it to undef.

Thus, to set a cursor of a widget, we have to call its window property.

	$check_button->signal_connect('leave' => sub {$check_button->window->set_cursor(undef);});

Warning

Please node that Gtk2::Gdk::Window is different from Gtk2::Window, as this can confuse a new user to the toolkit.

Tip

For Gtk2's own enums and flags, you can look in the Gtk2::enums manpage. The cursors are listed under Gtk2::Gdk::CursorType.

Interpreting errors

If you supplied a bogus cursor value, it will cause your program to spit out a list of possible values to choose from. my $hand_cursor = Gtk2::Gdk::Cursor->new ('hand'); was a typo I made (should be hand1 or hand2) as a result, the program returned a list of values to assist me with.(the same goes for many class methods that require a constant as argument.)

Gtk2::Stock

Stock items are standard icons with labels that comes with Gtk+. A typical example is the "Ok" and "Cancel" buttons. This is powerful because the label change according to you language settings, making internationalization easier.

Stock items are special in the sense that, depending where it gets called, it may include a icon and a label, or just an icon. In our sample program, we call it to create a stock button. This includes the label to. If we create a Gtk2::Image from stock, we will not get the label with it.

The screenshot

Figure 7-1. Gtk2::Button

FAQ

7.1. Who are those dudes featuring in the button?
7.2. What are they doing?

7.1. Who are those dudes featuring in the button?

They are them dudes from the movie "Dude, where's my car?", dude!

7.2. What are they doing?

They got them self into an endless conversation loop.... and you thought it can only happen in programming ;-)

7.1. The Code

The program can be found here: 'Button Demo'

 1 #! /usr/bin/perl -w
 2 use strict;
 3 
 4 use Glib qw/TRUE FALSE/;
 5 use Gtk2 '-init';
 6  
 7 #standard window creation, placement, and signal connecting
 8 my $window = Gtk2::Window->new('toplevel');
 9 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
10 $window->set_border_width(5);
11 $window->set_position('center_always');
12 
13 #this vbox will geturn the bulk of the gui
14 my $vbox = &ret_vbox();
15 
16 #add and show the vbox
17 $window->add($vbox);
18 $window->show();
19 
20 #our main event-loop
21 Gtk2->main();
22 
23 
24 sub ret_vbox {
25 
26 my $hand_cursor = Gtk2::Gdk::Cursor->new ('hand2');
27 #create a Gtk2::VBox to pack a Gtk2::Frame in. The frame will contain
28 #a Gtk2::ScrolledWindow, which in turn will contain a Gtk2::VBox full
29 #of Gtk2::Buttons
30 my $sw;
31 my $vbox = Gtk2::VBox->new(FALSE,5);
32 
33 my $frame = Gtk2::Frame->new();
34 		#to prove that a Gtk2::Frame can contain somethethig else
35 		# than a label
36 		my $check_button = Gtk2::CheckButton->new ("Click Here!");
37 		
38     		$check_button->set_active (TRUE);
39 		$check_button->signal_connect (toggled => sub {
40         		my $self = shift;
41 			if ($self->get_active){
42 				# 'activate' the scrolled window and chance the checkbutton's
43 				# appearance if the user checks the check button.
44 				my $img_dude = Gtk2::Image->new_from_file("./pix/sweet.jpg");
45 				#add a touch of detail
46 				$window->set_icon_from_file ("./pix/dude.jpg"); 
47 				$sw->set_sensitive (TRUE);
48 				$check_button->set_label("Sweet, and what about mine?");
49 				$check_button->set_property('image'=>$img_dude);
50 				
51 			}else{
52 				# 'gray out' the scrolled window and chance the checkbutton's 
53 				# appearance if the user un-checks the check button.
54 				my $img_sweet = Gtk2::Image->new_from_file("./pix/dude.jpg");
55 				#add a touch of detail
56 				$window->set_icon_from_file ("./pix/sweet.jpg");
57         			$sw->set_sensitive (FALSE);
58 				$check_button->set_label("Dude, what does mine say?");
59 				$check_button->set_property('image'=>$img_sweet);
60 			}
61     		});
62 		$check_button->show;
63 		$check_button->signal_connect('enter' => sub {$check_button->window->set_cursor($hand_cursor);});
64 		$check_button->signal_connect('leave' => sub {$check_button->window->set_cursor(undef);});
65 		
66 	$frame->set_label_widget ($check_button);	
67 	$frame->set_shadow_type ('out');
68 	#method of Gtk2::Container
69 	$frame->set_border_width(10);
70 	
71 		$sw = Gtk2::ScrolledWindow->new (undef, undef);
72     		$sw->set_shadow_type ('etched-out');
73 		$sw->set_policy ('never', 'automatic');
74 		#This is a method of the Gtk2::Widget class,it will force a minimum 
75 		#size on the widget. Handy to give intitial size to a 
76 		#Gtk2::ScrolledWindow class object
77 		$sw->set_size_request (300, 300);
78 		#method of Gtk2::Container
79 		$sw->set_border_width(10);
80 		
81 			#create a vbox that will contain all the stock buttons
82 			my $vbox_stock = Gtk2::VBox->new(FALSE,5);
83 			foreach my $val(sort Gtk2::Stock->list_ids){
84 				my $btn_stock = Gtk2::Button->new_from_stock($val);
85 				$vbox_stock->pack_start($btn_stock,FALSE,FALSE,4);
86 			}
87 		#add the vbox with all the stock buttons	
88 		$sw->add_with_viewport($vbox_stock);
89 	
90 	$frame->add($sw); 
91 
92 $vbox->pack_start($frame,TRUE,TRUE,4);
93 $vbox->show_all();
94 return $vbox;
95 }

Some lines of code that needs further explanation

Notes

[1]

Some widgets are "natively scrollable" -- that is, they support the set_scroll_adjustments signal, and know how to scroll themselves. Gtk2::TreeView and Gtk2::TextView are examples of scrolling widgets.

$scrolled_window->add_with_viewport ($child) is used to add non-scrolling widgets to a Gtk2::ScrolledWindow. Behind the scenes, it creates a Gtk2::Viewport ($viewport), add $child to it, then doing $scrolled_window->add ($viewport). An Gtk2::HBox doesn't know how to scroll itself, so you must use a Gtk2::Viewport to scroll it.

If you use $scrolled_window->add_with_viewport ($child) on a scrollable widget, the widget will not work correctly. For example, if you use $scrolled_window->add_with_viewport ($child) to add a Gtk2::TreeView to a Gtk2::ScrolledWindow, the column headings will scroll away! You must use $scrolled_window->add($child) to put a scrollable widget into a Gtk2::ScrolledWindow.