As it was stated before container widgets can contain other widgets. A child widget can be added to container using procedure:
add ( widget : GTK_WIDGET )
Some GTK widgets don't have associated X windows, so they just draw on their parents. Because of this, they cannot receive events and if they are incorrectly sized, they don't clip so you can get messy overwriting etc. If you require more from these widgets, the EventBox is for you.
At first glance, the EventBox widget might appear to be totally useless. It draws nothing on the screen and responds to no events. However, it does serve a function - it provides an X window for its child widget. This is important as many GTK widgets do not have an associated X window. Not having an X window saves memory and improves performance, but also has some drawbacks. A widget without an X window cannot receive events, and does not perform any clipping on its contents. Although the name EventBox emphasizes the event-handling function, the widget can also be used for clipping. (and more, see the example below).
Creation procedure of the class GTK_EVENT_BOX is:
make
A child widget can then be added to this EventBox, because of the inheritance GTK_EVENT_BOX from the class GTK_CONTAINER:
event_box.add(child_widget );
The following example demonstrates both uses of an EventBox - a label is created that is clipped to a small box, and set up so that a mouse-click on the label causes the program to exit. Resizing the window reveals varying amounts of the label.
-- example-start eventbox eventbox.e
class EVENTBOX
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
event_box : GTK_EVENT_BOX;
label : GTK_LABEL;
cursor : GDK_CURSOR;
do
-- Initialize the toolkit, remove gtk-related commandline stuff
vegtk_init
!!window.make(Gtk_window_toplevel);
window.set_title ("Event Box");
signal_connect (window, "destroy",$destroy);
window.set_border_width (10);
-- Create an EventBox and add it to our toplevel window
!!event_box.make;
window.add (event_box);
event_box.show;
-- Create a long label
!!label.make ("Click here to quit, quit, quit, quit, quit");
event_box.add (label);
label.show;
-- Clip it short.
label.set_usize (110, 20);
-- And bind an action to it
event_box.set_events (Gdk_button_press_mask);
signal_connect (event_box, "button_press_event",$destroy);
-- Yet one more thing you need an X window for ...
event_box.realize;
!!cursor.make(Gdk_hand1);
event_box.window.set_cursor(cursor);
window.show;
gtk_main;
end -- make
feature {NONE} -- Implementation
window : GTK_WINDOW;
feature {NONE} -- Callbacks
close_application is
-- This callback quits the program
do
window.destroy;
end
destroy is
do
gtk_main_quit;
end
end -- class EVENTBOX
-- example-end
The alignment widget allows you to place a widget within its window at a position and size relative to the size of the Alignment widget itself. For example, it can be very useful for centering a widget within the window.
The creation procedure of the class GTK_ALIGNMENT is:
make ( xalign : REAL; yalign : REAL; xscale : REAL; yscale : REAL )
All four alignment parameters are floating point numbers which can
range from 0.0 to 1.0. The xalign
and yalign
arguments
affect the position of the widget placed within the Alignment
widget. The xscale
and yscale
arguments effect the amount of
space allocated to the widget.
The follows procedure allows the alignment paramters of an exisiting Alignment widget to be altered.
set ( xalign : REAL; yalign : REAL; xscale : REAL; yscale : REAL ) is
For an example of using an Alignment widget, refer to the example for the Progress Bar widget.
The Fixed container allows you to place widgets at a fixed position within it's window, relative to it's upper left hand corner. The position of the widgets can be changed dynamically.
Creation procedure of the class GTK_FIXED is simple:
make;
There are only two procedures associated with the fixed widget:
put ( widget : GTK_WIDGET; x : INTEGER; y : INTEGER )
move ( widget : GTK_WIDGET; x : INTEGER; y : INTEGER )
put
places widget
in the container at the position specified
by x
and y
.
move
allows the specified widget to be moved to a new position.
The following example illustrates how to use the Fixed Container.
-- example-start fixed fixed.e
class FIXED
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
i : INTEGER;
button : GTK_BUTTON;
window : GTK_WINDOW;
fixed : GTK_FIXED;
do
-- Initialise GTK
vegtk_init
-- Create a new window
!!window.make (Gtk_window_toplevel);
window.set_title("Fixed Container");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
-- Sets the border width of the window.
window.set_border_width (10);
-- Create a Fixed Container
!!fixed.make;
window.add(fixed);
fixed.show;
from
i := 1;
until
i >3
loop
-- Creates a new button with the label "Press me"
!!button.make_with_label ("Press me");
-- When the button receives the "clicked" signal, it will call the
-- function move_button() passing it the Fixed Containter as its
-- argument. */
signal_connect_with_data (button,"clicked",$move_button,fixed);
-- This packs the button into the fixed containers window.
fixed.put (button, i*50, i*50);
-- The final step is to display this newly created widget.
button.show;
i := i+1;
end -- loop
-- Display the window
window.show;
-- Enter the event loop
gtk_main;
end -- make
feature {NONE} -- Implementation
-- I'm going to be lazy and use some global variables to
-- store the position of the widget within the fixed
-- container
x,y : INTEGER;
feature {NONE} -- Callbacks
destroy is
do
gtk_main_quit;
end
move_button (data : ANY; cb_data : VEGTK_CALLBACK_DATA) is
-- This callback function moves the button to a new position
-- in the Fixed container.
local
fixed : GTK_FIXED;
widget : GTK_WIDGET;
do
widget ?= cb_data.get_widget;
fixed ?= data;
x := (x+30)\\300;
y := (y+50)\\300;
fixed.move (widget, x, y);
end
end -- class FIXED
-- example-end
The Layout container is similar to the Fixed container except that it implements an infinite (where infinity is less than 2^32) scrolling area. Xwindows has a limitation where windows can be at most 32767 pixels wide or tall. The Layout container gets around this limitation by doing some exotic stuff using window and bit gravities, so that you can have smooth scrolling even when you have many child widgets in your scrolling area.
The creation procedure of the class GTK_LAYOUT is:
make ( hadjustment : GTK_ADJUSTMENT; vadjustment : GTK_ADJUSTMENT )
You can specify the Adjustment objects that the Layout widget will use for it's scrolling, or else pass Void as hadjustment/vadjustment.
You can add and move widgets in the Layout container using the following two procedures:
put ( widget : GTK_WIDGET; x : INTEGER; y : INTEGER )
move ( widget : GTK_WIDGET; x : INTEGER; y : INTEGER )
The size of the Layout container can be set using the next procedure:
set_size ( width : INTEGER; height : INTEGER )
Layout containers are one of the very few widgets in the GTK widget
set that actively repaint themselves on screen as they are changed
using the above procedures (the vast majority of widgets queue
requests which are then processed when control returns to the
gtk_main()
function).
When you want to make a large number of changes to a Layout container, you can use the following two procedures to disable and re-enable this repainting functionality:
freeze
thaw
The final two functions and two procedures for use with Layout widgets are for manipulating the horizontal and vertical adjustment widgets:
get_hadjustment : GTK_ADJUSTMENT is
get_vadjustment : GTK_ADJUSTMENT is
set_hadjustment ( adjustment : GTK_ADJUSTMENT ) is
set_vadjustment ( adjustment : GTK_ADJUSTMENT ) is
Frames can be used to enclose one or a group of widgets with a box which can optionally be labelled. The position of the label and the style of the box can be altered to suit.
The creation procedure of the class GTK_FRAME is:
make ( label : STRING ) is
The label is by default placed in the upper left hand corner of the
frame. A value of Void for the label
argument will result in no
label being displayed. The text of the label can be changed using the
next procedure.
set_label ( label : STRING )
The position of the label can be changed using this function:
set_label_align ( xalign : REAL; yalign : REAL )
xalign
and yalign
take values between 0.0 and 1.0. xalign
indicates the position of the label along the top horizontal of the
frame. yalign
is not currently used. The default value of xalign
is 0.0 which places the label at the left hand end of the frame.
The next procedure alters the style of the box that is used to outline the frame.
set_shadow_type ( arg_type : GTK_SHADOW_TYPE ) is
The type
argument can take one of the following values:
The following code example illustrates the use of the Frame widget.
-- example-start frame frame.e
class FRAME
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
window : GTK_WINDOW;
frame : GTK_FRAME;
do
-- Initialise GTK
vegtk_init
-- Create a new window
!!window.make (Gtk_window_toplevel);
window.set_title("Frame Example");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
window.set_usize(300, 300);
-- Sets the border width of the window.
window.set_border_width (10);
-- Create a Frame
!!frame.make(Void);
window.add(frame);
-- Set the frames label
frame.set_label("GTK Frame Widget");
-- Align the label at the right of the frame
frame.set_label_align(1.0, 0.0);
-- Set the style of the frame
frame.set_shadow_type(Gtk_shadow_etched_out);
frame.show;
-- Display the window
window.show;
-- Enter the event loop
gtk_main;
end -- make
feature {NONE} -- Callbacks
destroy is
do
gtk_main_quit;
end
end -- class FRAME
-- example-end
The aspect frame widget is like a frame widget, except that it also enforces the aspect ratio (that is, the ratio of the width to the height) of the child widget to have a certain value, adding extra space if necessary. This is useful, for instance, if you want to preview a larger image. The size of the preview should vary when the user resizes the window, but the aspect ratio needs to always match the original image.
To create a new aspect frame use the following creation procedure from the class GTK_ASPECT_FRAME:
make ( label : STRING; xalign : REAL; yalign : REAL; ratio : REAL;
obey_child : BOOLEAN )
xalign
and yalign
specify alignment as with Alignment
widgets. If obey_child
is True, the aspect ratio of a child
widget will match the aspect ratio of the ideal size it requests.
Otherwise, it is given by ratio
.
To change the options of an existing aspect frame, you can use:
set ( xalign : REAL; yalign : REAL; ratio : REAL; obey_child : INTEGER )
As an example, the following program uses an AspectFrame to present a drawing area whose aspect ratio will always be 2:1, no matter how the user resizes the top-level window.
-- example-start aspectframe aspectframe.e
class ASPECTFRAME
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
window : GTK_WINDOW;
aspect_frame : GTK_ASPECT_FRAME;
drawing_area : GTK_DRAWING_AREA;
do
-- Initialise GTK
vegtk_init
-- Create a new window
!!window.make (Gtk_window_toplevel);
window.set_title("Aspect Frame");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
-- Sets the border width of the window.
window.set_border_width (10);
-- Create an aspect_frame and add it to our toplevel window
!!aspect_frame.make ("2x1", -- label
0.5, -- center x
0.5, -- center y
2, -- xsize/ysize = 2
False -- ignore child's aspect */
);
window.add (aspect_frame);
aspect_frame.show;
-- Now add a child widget to the aspect frame
!!drawing_area.make;
-- Ask for a 200x200 window, but the AspectFrame will give us a 200x100
-- window since we are forcing a 2x1 aspect ratio
drawing_area.set_usize (200, 200);
aspect_frame.add (drawing_area);
drawing_area.show;
window.show
gtk_main;
end -- make
feature {NONE} -- Callbacks
destroy is
do
gtk_main_quit;
end
end -- class ASPECTFRAME
-- example-end
The paned window widgets are useful when you want to divide an area into two parts, with the relative size of the two parts controlled by the user. A groove is drawn between the two portions with a handle that the user can drag to change the ratio. The division can either be horizontal (HPaned) or vertical (VPaned).
The creation procedures of the classes GTK_HPANED and GTK_VPANED are
make;
After creating the paned window widget, you need to add child widgets to its two halves. To do this, use the procedures:
add1 ( child : GTK_WIDGET )
add2 ( child : GTK_WIDGET )
add1()
adds the child widget to the left or top half of the paned
window. add2()
adds the child widget to the right or bottom half
of the paned window.
A paned widget can be changed visually using the following two procedures.
set_handle_size ( size : INTEGER )
set_gutter_size ( size : INTEGER )
The first of these sets the size of the handle and the second sets the size of the gutter that is between the two parts of the paned window.
As an example, we will create part of the user interface of an
imaginary email program. A window is divided into two portions
vertically, with the top portion being a list of email messages and
the bottom portion the text of the email message. Most of the program
is pretty straightforward. A couple of points to note: text can't be
added to a Text widget until it is realized. This could be done by
calling realize()
, but as a demonstration of an alternate
technique, we connect a handler to the "realize" signal to add the
text. Also, we need to add the GTK_SHRINK
option to some of the
items in the table containing the text window and its scrollbars, so
that when the bottom portion is made smaller, the correct portions
shrink instead of being pushed off the bottom of the window.
-- example-start paned paned.e
class PANED
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
window : GTK_WINDOW;
vpaned : GTK_VPANED;
text,list : GTK_WIDGET;
do
-- Initialise GTK
vegtk_init
-- Create a new window
!!window.make (Gtk_window_toplevel);
window.set_title("Paned Windows");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
-- Sets the border width of the window.
window.set_border_width (10);
window.set_usize (450, 400);
-- create a vpaned widget and add it to our toplevel window
!!vpaned.make;
window.add (vpaned);
vpaned.set_handle_size (10);
vpaned.set_gutter_size (15);
vpaned.show;
-- Now create the contents of the two halves of the window
list := create_list;
vpaned.add1 (list);
list.show;
text := create_text;
vpaned.add2 (text);
text.show;
window.show;
gtk_main;
end -- make
feature {NONE} -- Support
create_list : GTK_SCROLLED_WINDOW is
-- Create the list of "messages"
local
scrolled_window : GTK_SCROLLED_WINDOW;
list : GTK_LIST;
list_item : GTK_LIST_ITEM;
i : INTEGER;
buffer : STRING;
do
-- Create a new scrolled window, with scrollbars only if needed
!!scrolled_window.make (Void,Void);
scrolled_window.set_policy (Gtk_policy_automatic, Gtk_policy_automatic);
-- Create a new list and put it in the scrolled window
!!list.make;
scrolled_window.add_with_viewport (list);
list.show;
-- Add some messages to the window
from
i :=0
until
i >= 10
loop
!!buffer.make_from_string("Message # ");
buffer.append(i.out);
!!list_item.make_with_label (buffer);
list.add (list_item);
list_item.show;
i := i+1;
end
Result := scrolled_window;
end -- create_list
create_text : GTK_WIDGET is
-- Create a scrolled text area that displays a "message"
local
table : GTK_TABLE;
text : GTK_TEXT;
hscrollbar : GTK_HSCROLLBAR;
vscrollbar : GTK_VSCROLLBAR;
do
-- Create a table to hold the text widget and scrollbars */
!!table.make (2, 2, False);
-- Put a text widget in the upper left hand corner. Note the use of
-- GTK_SHRINK in the y direction */
!!text.make (Void, Void);
table.attach (text, 0, 1, 0, 1,
Gtk_fill and Gtk_expand,
Gtk_fill and Gtk_expand and Gtk_shrink, 0, 0);
text.show;
-- Put a HScrollbar in the lower left hand corner
!!hscrollbar.make(text.hadj);
table.attach (hscrollbar, 0, 1, 1, 2,
Gtk_expand and Gtk_fill, Gtk_fill, 0, 0);
hscrollbar.show;
-- And a VScrollbar in the upper right
!!vscrollbar.make (text.vadj);
table.attach (vscrollbar, 1, 2, 0, 1,
Gtk_fill, Gtk_expand and Gtk_fill and Gtk_shrink, 0, 0);
vscrollbar.show;
-- Add a handler to put a message in the text widget when it is realized
signal_connect (text, "realize",$realize_text);
Result := table;
end -- create_text
feature {NONE} -- Callbacks
destroy is
do
gtk_main_quit;
end
realize_text (data : ANY; cb_data : VEGTK_CALLBACK_DATA) is
-- Add some text to our text widget - this is a callback that is invoked
-- when our window is realized. We could also force our window to be
-- realized with gtk_widget_realize, but it would have to be part of
-- a hierarchy first
local
text : GTK_TEXT;
do
text ?= cb_data.get_widget;
text.freeze;
text.insert (Void,text.get_style.black,Void,
"From: pathfinder@nasa.gov%N%
%To: mom@nasa.gov%N%
%Subject: Made it!%N%
%%N%
%We just got in this morning. The weather has been%N%
%great - clear but cold, and there are lots of fun sights.%N%
%Sojourner says hi. See you soon.%N%
% -Path%N");
text.thaw;
end -- realize_text
end -- class PANED
-- example-end
It is unlikely that you will ever need to use the Viewport widget directly. You are much more likely to use the Scrolled Windows widget which itself uses the Viewport.
A viewport widget allows you to place a larger widget within it such that you can view a part of it at a time. It uses Adjustments to define the area that is currently in view.
class GTK_VIEWPORT
inherit
GTK_BIN
creation
make
feature -- creation
make ( hadjustment : GTK_ADJUSTMENT; vadjustment : GTK_ADJUSTMENT ) is
As you can see you can specify the horizontal and vertical Adjustments that the widget is to use when you create the widget. It will create it's own if you pass Void as the value of the arguments.
You can get and set the adjustments after the widget has been created using the following four procedures/functions:
get_hadjustment : GTK_ADJUSTMENT
get_vadjustment : GTK_ADJUSTMENT
set_hadjustment ( adjustment : GTK_ADJUSTMENT )
set_vadjustment ( adjustment : GTK_ADJUSTMENT )
The only other viewport procedure is used to alter its appearance:
set_shadow_type ( type : GTK_SHADOW_TYPE )
Possible values for the type
parameter are:
Scrolled windows are used to create a scrollable area inside a real window. You may insert any type of widget into a scrolled window, and it will be accessible regardless of the size by using the scrollbars.
The following function is used to create a new scrolled window.
class GTK_SCROLLED_WINDOW
inherit
GTK_CONTAINER
creation
make
feature -- creation
make ( hadjustment : GTK_ADJUSTMENT; vadjustment : GTK_ADJUSTMENT )
The first argument is the adjustment for the horizontal direction, and the second, the adjustment for the vertical direction. These are almost always set to Void.
set_policy ( hscrollbar_policy : GTK_POLICY_TYPE;
vscrollbar_policy : GTK_POLICY_TYPE )
This sets the policy to be used with respect to the scrollbars. The first argument sets the policy for the horizontal scrollbar, and the second the policy for the vertical scrollbar.
The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC will automatically decide whether you need scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars there.
You can then place your object into the scrolled window using the following function.
add_with_viewport ( child : GTK_WIDGET )
Here is a simple example that packs 100 toggle buttons into a scrolled window. I've only commented on the parts that may be new to you.
-- example-start scrolledwin scrolledwin.e
class SCROLLEDWIN
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
window : GTK_DIALOG;
scrolled_window : GTK_SCROLLED_WINDOW;
table : GTK_TABLE;
button : GTK_BUTTON;
buffer : STRING;
i,j : INTEGER;
do
-- Initialise GTK
vegtk_init
-- Create a new window
-- Create a new dialog window for the scrolled window to be
-- packed into. A dialog is just like a normal window except it has a
-- vbox and a horizontal separator packed into it. It's just a shortcut
-- for creating dialogs */
!!window.make;
window.set_title("GtkScrolledWindow example");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
-- Sets the border width of the window.
window.set_border_width (0);
window.set_usize(300, 300);
-- create a new scrolled window.
!!scrolled_window.make(Void, Void);
scrolled_window.set_border_width (10);
-- the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
-- GTK_POLICY_AUTOMATIC will automatically decide whether you need
-- scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
-- there. The first one is the horizontal scrollbar, the second,
-- the vertical.
scrolled_window.set_policy (Gtk_policy_automatic, Gtk_policy_always);
-- The dialog window is created with a vbox packed into it.
window.vbox.pack_start(scrolled_window, True, True, 0);
scrolled_window.show;
-- create a table of 10 by 10 squares.
!!table.make (10, 10, False);
-- set the spacing to 10 on x and 10 on y
table.set_row_spacings (10);
table.set_col_spacings (10);
-- pack the table into the scrolled window
scrolled_window.add_with_viewport (table);
table.show;
-- this simply creates a grid of toggle buttons on the table
-- to demonstrate the scrolled window.
from
i := 0
until
i >= 10
loop
from
j := 0
until
j >= 10
loop
!!buffer.make_from_string("button (");
buffer.append(i.out);
buffer.append(",");
buffer.append(j.out);
buffer.append(")%N");
!!button.make_with_label (buffer);
table.attach_defaults (button,i, i+1, j, j+1);
button.show;
j := j+1;
end -- loop
i := i+1;
end -- loop
-- Add a "close" button to the bottom of the dialog
!!button.make_with_label ("close");
signal_connect_with_data (button, "clicked",$close_application,window);
-- this makes it so the button is the default.
button.set_flags (Gtk_can_default);
window.action_area.pack_start (button, True, True, 0);
-- This grabs this button to be the default button. Simply hitting
-- the "Enter" key will cause this button to activate.
button.grab_default;
button.show;
window.show;
gtk_main;
end -- make
feature {NONE} -- Callbacks
close_application (data : ANY) is
local
window : GTK_OBJECT;
do
window ?= data;
window.destroy;
end
destroy is
do
gtk_main_quit;
end
end -- class SCROLLEDWIN
-- example-end
Try playing with resizing the window. You'll notice how the scrollbars react. You may also wish to use the set_usize() call to set the default size of the window or other widgets.
Button Boxes are a convenient way to quickly layout a group of buttons. They come in both horizontal and vertical flavours.
class GTK_HBUTTON_BOX
inherit
GTK_BUTTON_BOX
creation
make
feature -- creation
make
class GTK_VBUTTON_BOX
inherit
GTK_BUTTON_BOX
creation
make
feature -- creation
make
The only attributes pertaining to button boxes effect how the buttons are layed out. You can change the spacing between the buttons with:
set_spacing_default ( spacing : INTEGER ) is
Similarly, the current spacing values can be queried using:
get_spacing_default : INTEGER
The second attribute that we can access effects the layour of the buttons within the box. It is set using one of:
set_layout_default ( layout : GTK_BUTTON_BOX_STYLE )
The layout
argument can take one of the following values:
The current layout setting can be retrieved using:
get_layout_default : GTK_BUTTON_BOX_STYLE is
Buttons are added to a Button Box using the usual container procedure add:
Here's an example that illustrates all the different layout settings for Button Boxes.
-- example-start buttonbox buttonbox.e
class BUTTONBOX
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature -- Creation
make is
local
window : GTK_WINDOW;
vbox, main_vbox : GTK_VBOX;
hbox : GTK_HBOX;
frame_horz, frame_vert: GTK_FRAME;
do
-- Initialise GTK
vegtk_init
-- Create a new window
!!window.make(Gtk_window_toplevel);
window.set_title("Button Boxes");
-- Here we connect the "destroy" event to a signal handler
signal_connect (window, "destroy",$destroy);
-- Sets the border width of the window.
window.set_border_width (10);
!!main_vbox.make (False, 0);
window.add (main_vbox);
!!frame_horz.make ("Horizontal Button Boxes");
main_vbox.pack_start (frame_horz, True, True, 10);
!!vbox.make (False, 0);
vbox.set_border_width (10);
frame_horz.add (vbox);
vbox.pack_start (create_bbox (True, "Spread (spacing 40)",40, 85, 20,
Gtk_buttonbox_spread),
True, True,0);
vbox.pack_start (create_bbox (True, "Edge (spacing 30)", 30, 85, 20,
Gtk_buttonbox_edge),
True, True, 5);
vbox.pack_start (create_bbox (True, "Start (spacing 20)", 20, 85, 20,
Gtk_buttonbox_start),
True, True, 5);
vbox.pack_start (create_bbox (True, "End (spacing 10)", 10, 85, 20,
Gtk_buttonbox_end),
True, True, 5);
!!frame_vert.make ("Vertical Button Boxes");
main_vbox.pack_start (frame_vert, True, True, 10);
!!hbox.make (False, 0);
hbox.set_border_width (10);
frame_vert.add (hbox);
hbox.pack_start (create_bbox (False, "Spread (spacing 5)", 5, 85, 20,
Gtk_buttonbox_spread),
True, True, 0);
hbox.pack_start (create_bbox (False, "Edge (spacing 30)", 30, 85, 20,
Gtk_buttonbox_edge),
True, True, 5);
hbox.pack_start (create_bbox (False, "Start (spacing 20)", 20, 85, 20,
Gtk_buttonbox_start),
True, True, 5);
hbox.pack_start (create_bbox (False, "End (spacing 20)", 20, 85, 20,
Gtk_buttonbox_end),
True, True, 5);
window.show_all;
-- Enter the event loop
gtk_main;
end -- make
feature {NONE} -- Support
create_bbox (horizontal : BOOLEAN;
title : STRING;
spacing, child_w, child_h : INTEGER;
layout : GTK_BUTTON_BOX_STYLE) : GTK_WIDGET is
-- Create a Button Box with the specified parameters
local
frame : GTK_FRAME;
bbox : GTK_BUTTON_BOX;
button : GTK_BUTTON;
do
!!frame.make(title);
if horizontal then
!GTK_HBUTTON_BOX!bbox.make;
else
!GTK_VBUTTON_BOX!bbox.make;
end
bbox.set_border_width (5);
frame.add (bbox);
-- Set the appearance of the Button Box
bbox.set_layout (layout);
bbox.set_spacing (spacing);
bbox.set_child_size (child_w, child_h);
!!button.make_with_label ("OK");
bbox.add (button);
!!button.make_with_label ("Cancel");
bbox.add (button);
!!button.make_with_label ("Help");
bbox.add (button);
Result := frame;
end
feature {NONE} -- Callbacks
destroy is
do
gtk_main_quit;
end
end -- class BUTTONBOX
-- example-end
Toolbars are usually used to group some number of widgets in order to simplify customization of their look and layout. Typically a toolbar consists of buttons with icons, labels and tooltips, but any other widget can also be put inside a toolbar. Finally, items can be arranged horizontally or vertically and buttons can be displayed with icons, labels or both.
class GTK_TOOLBAR
inherit
GTK_CONTAINER
creation
make
feature -- creation
make ( orientation : GTK_ORIENTATION; style : GTK_TOOLBAR_STYLE ) is
Orientation may be one of:
GTK_ORIENTATION_HORIZONTAL
GTK_ORIENTATION_VERTICAL
and style one of:
GTK_TOOLBAR_TEXT
GTK_TOOLBAR_ICONS
GTK_TOOLBAR_BOTH
The style applies to all the buttons created with the `item' functions (not to buttons inserted into toolbar as separate widgets).
After creating a toolbar one can append, prepend and insert items (that means simple buttons) into the toolbar. To describe an item we need a label text, a tooltip text, a private tooltip text, an icon for the button and a callback function for it. For example, to append or prepend an item you may use the following functions:
append_item(text, tooltip_text, tooltip_private_text : STRING;
icon : GTK_WIDGET;
callback_object : VEGTK_CALLBACK_HANDLER;
callback : POINTER ;
callback_data : ANY) :GTK_BUTTON
prepend_item(text, tooltip_text, tooltip_private_text : STRING;
icon : GTK_WIDGET;
callback_object : VEGTK_CALLBACK_HANDLER;
callback : POINTER ;
callback_data : ANY) :GTK_BUTTON
If you want to use gtk_toolbar_insert_item, the only additional parameter which must be specified is the position in which the item should be inserted, thus:
insert_item(text, tooltip_text, tooltip_private_text : STRING;
icon : GTK_WIDGET;
callback_object : VEGTK_CALLBACK_HANDLER;
callback : POINTER ;
callback_data : ANY;
position : INTEGER) :GTK_BUTTON is
To simplify adding spaces between toolbar items, you may use the following procedures:
append_space
prepend_space
insert_space ( position : INTEGER )
While the size of the added space can be set globally for a whole toolbar with the procedure:
set_space_size ( space_size : INTEGER )
If it's required, the orientation of a toolbar and its style can be changed `on the fly' using the following procedures:
set_orientation ( orientation : GTK_ORIENTATION )
set_style ( arg_style : GTK_TOOLBAR_STYLE )
set_tooltips ( enable : BOOLEAN )
Where orientation
is one of GTK_ORIENTATION_HORIZONTAL or
GTK_ORIENTATION_VERTICAL. The style
is used to set appearance of
the toolbar items by using one of GTK_TOOLBAR_ICONS, GTK_TOOLBAR_TEXT
or GTK_TOOLBAR_BOTH.
To show some other things that can be done with a toolbar, let's take the following program (we'll interrupt the listing with some additional explanations):
-- example-start toolbar toolbar.e
class TOOLBAR
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature {NONE} -- Callbacks
delete_event is
-- This callback procedure is connected to the Close button or
-- closing the window from the WM
do
gtk_main_quit;
end
radio_event (data : ANY) is
-- that's easy... when one of the buttons is toggled, we just
-- check which one is active and set the style of the toolbar
-- accordingly
-- ATTENTION: our toolbar is passed as data to callback !
local
toolbar : GTK_TOOLBAR;
do
toolbar ?= data;
if text_button.get_active then
toolbar.set_style(Gtk_toolbar_text);
elseif icon_button.get_active then
toolbar.set_style(Gtk_toolbar_icons);
elseif (both_button.get_active) then
toolbar.set_style(Gtk_toolbar_both);
end
end
toggle_event (data : ANY; cb_data : VEGTK_CALLBACK_DATA) is
-- even easier, just check given toggle button and enable/disable
-- tooltips
local
toolbar : GTK_TOOLBAR;
button : GTK_TOGGLE_BUTTON;
do
button ?= cb_data.get_widget;
toolbar ?= data;
toolbar.set_tooltips (button.get_active );
end
feature {NONE} -- Implementation
close_button : GTK_BUTTON; -- This button will emit signal to close
-- application
tooltips_button : GTK_TOGGLE_BUTTON; -- to enable/disable tooltips
-- radio buttons for toolbar style
text_button,icon_button,both_button : GTK_RADIO_BUTTON;
entry : GTK_ENTRY; -- a text entry to show packing any widget into
-- toolbar */
feature {ANY} -- Creation
make is
local
-- Here is our main window (a dialog) and a handlebox
dialog : GTK_DIALOG;
handlebox : GTK_HANDLE_BOX;
-- Ok, we need a toolbar, an icon with a mask (one for all of
-- the buttons) and an icon widget to put this icon in (but
-- we'll create a separate widget for each button)
toolbar : GTK_TOOLBAR;
icon : GDK_PIXMAP;
iconw : GTK_PIXMAP;
do
-- this is called in all GTK application.
vegtk_init
-- create a new window with a given title, and nice size
!!dialog.make;
dialog.set_title ("GTKToolbar Tutorial");
dialog.set_usize (600, 300);
dialog.set_policy (True,True,False);
-- typically we quit if someone tries to close us
signal_connect (dialog, "delete_event",$delete_event);
-- we need to realize the window because we use pixmaps for
-- items on the toolbar in the context of it
dialog.realize;
-- to make it nice we'll put the toolbar into the handle box,
-- so that it can be detached from the main window */
!!handlebox.make;
dialog.vbox.pack_start (handlebox, False, False, 5 );
-- toolbar will be horizontal, with both icons and text, and
-- with 5pxl spaces between items and finally,
-- we'll also put it into our handlebox */
!!toolbar.make (Gtk_orientation_horizontal, Gtk_toolbar_both );
toolbar.set_border_width (5);
toolbar.set_space_size (5);
handlebox.add (toolbar);
-- now we create icon mask: we'll reuse it to create
-- icon widgets for toolbar items */
!!icon.make_from_xpm_d (dialog.window,dialog.get_style.white,gtk_xpm);
!!iconw.make(icon, icon.mask);
-- our first item is <close> button
toolbar.append_item ( "Close", -- button label
"Closes this app", -- this button's tooltip
"Private", -- tooltip private info
iconw, -- icon widget
Current,
$delete_event, -- callback procedure
Void);
close_button ?= toolbar.last_added_element
toolbar.append_space; -- space after item
-- now, let's make our radio buttons group...
!!iconw.make( icon, icon.mask );
toolbar.append_element(
Gtk_toolbar_child_radiobutton, -- a type of element */
Void, -- pointer to widget */
"Icon", -- label
"Only icons in toolbar", -- tooltip
"Private", -- tooltip private string */
iconw, -- icon
Current,
$radio_event, -- callback procedure
toolbar); -- data for signal
icon_button ?= toolbar.last_added_element
toolbar.append_space;
-- following radio buttons refer to previous ones
!!iconw.make( icon, icon.mask );
toolbar.append_element(Gtk_toolbar_child_radiobutton,
icon_button,
"Text",
"Only texts in toolbar",
"Private",
iconw,
Current,
$radio_event,
toolbar);
text_button ?= toolbar.last_added_element
toolbar.append_space;
!!iconw.make ( icon, icon.mask );
toolbar.append_element(Gtk_toolbar_child_radiobutton,
text_button,
"Both",
"Icons and text in toolbar",
"Private",
iconw,
Current,
$radio_event,
toolbar);
both_button ?= toolbar.last_added_element
toolbar.append_space;
both_button.set_active(True);
-- here we have just a simple toggle button
!!iconw.make ( icon, icon.mask );
toolbar.append_element(Gtk_toolbar_child_togglebutton,
Void,
"Tooltips",
"Toolbar with or without tips",
"Private",
iconw,
Current,
$toggle_event,
toolbar);
tooltips_button ?= toolbar.last_added_element
toolbar.append_space;
tooltips_button.set_active(True);
-- to pack a widget into toolbar, we only have to
-- create it and append it with an appropriate tooltip */
!!entry.make;
toolbar.append_widget (entry,
"This is just an entry",
"Private" );
-- well, it isn't created within thetoolbar, so we must still show it
entry.show;
-- that's it ! let's show everything.
toolbar.show;
handlebox.show;
dialog.show;
-- rest in gtk_main and wait for the fun to begin!
gtk_main;
end -- make
feature {NONE} -- Implementation
-- XPM
gtk_xpm : ARRAY[STRING] is
once
Result := <<
"32 39 5 1",
". c none",
"+ c black",
"@ c #3070E0",
"# c #F05050",
"$ c #35E035",
"................+...............",
"..............+++++.............",
"............+++++@@++...........",
"..........+++++@@@@@@++.........",
"........++++@@@@@@@@@@++........",
"......++++@@++++++++@@@++.......",
".....+++@@@+++++++++++@@@++.....",
"...+++@@@@+++@@@@@@++++@@@@+....",
"..+++@@@@+++@@@@@@@@+++@@@@@++..",
".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
".+##++@@@@+++@@@+++++@@@@@@@@$@.",
".+###++@@@@+++@@@+++@@@@@++$$$@.",
".+####+++@@@+++++++@@@@@+@$$$$@.",
".+#####+++@@@@+++@@@@++@$$$$$$+.",
".+######++++@@@@@@@++@$$$$$$$$+.",
".+#######+##+@@@@+++$$$$$$@@$$+.",
".+###+++##+##+@@++@$$$$$$++$$$+.",
".+###++++##+##+@@$$$$$$$@+@$$@+.",
".+###++++++#+++@$$@+@$$@++$$$@+.",
".+####+++++++#++$$@+@$$++$$$$+..",
".++####++++++#++$$@+@$++@$$$$+..",
".+#####+++++##++$$++@+++$$$$$+..",
".++####+++##+#++$$+++++@$$$$$+..",
".++####+++####++$$++++++@$$$@+..",
".+#####++#####++$$+++@++++@$@+..",
".+#####++#####++$$++@$$@+++$@@..",
".++####++#####++$$++$$$$$+@$@++.",
".++####++#####++$$++$$$$$$$$+++.",
".+++####+#####++$$++$$$$$$$@+++.",
"..+++#########+@$$+@$$$$$$+++...",
"...+++########+@$$$$$$$$@+++....",
".....+++######+@$$$$$$$+++......",
"......+++#####+@$$$$$@++........",
".......+++####+@$$$$+++.........",
".........++###+$$$@++...........",
"..........++##+$@+++............",
"...........+++++++..............",
".............++++...............">>;
end -- gtk_xpm
end -- class TOOLBAR
-- example-end
The NoteBook Widget is a collection of 'pages' that overlap each other, each page contains different information. This widget has become more common lately in GUI programming, and it is a good way to show blocks of similar information that warrant separation in their display.
class GTK_NOTEBOOK
inherit
GTK_CONTAINER
creation
make
feature -- creation
make
Once the notebook has been created, there are a number of procedures that operate on the notebook widget. Let's look at them individually.
The first one we will look at is how to position the page indicators. These page indicators or 'tabs' as they are referred to, can be positioned in four ways: top, bottom, left, or right.
set_tab_pos ( pos : GTK_POSITION_TYPE )
GTK_POSITION_TYPE will be one of the following, which are pretty self explanatory:
Gtk_pos_top is the default.
Next we will look at how to add pages to the notebook. There are three ways to add pages to the NoteBook. Let's look at the first two together as they are quite similar.
append_page ( child : GTK_WIDGET; tab_label : GTK_WIDGET )
prepend_page ( child : GTK_WIDGET; tab_label : GTK_WIDGET )
These procedures add pages to the notebook by inserting them from the
back of the notebook (append), or the front of the notebook (prepend).
child
is the widget that is placed within the notebook page, and
tab_label
is the label for the page being added. The child
widget must be created separately, and is typically a set of options
setout witin one of the other container widgets, such as a table.
The final procedure for adding a page to the notebook contains all of the properties of the previous two, but it allows you to specify what position you want the page to be in the notebook.
insert_page ( child : GTK_WIDGET; tab_label : GTK_WIDGET;
position : INTEGER )
The parameters are the same as _append_ and _prepend_ except it
contains an extra parameter, position
. This parameter is used to
specify what place this page will be inserted into.
Now that we know how to add a page, lets see how we can remove a page from the notebook.
remove_page ( page_num : INTEGER )
This function takes the page specified by page_num
and removes it
from the widget pointed to by notebook
.
To find out what the current page is in a notebook use the function:
get_current_page : INTEGER
These next two procedures are simple calls to move the notebook page forward or backward. Simply provide the respective procedure call on the notebook widget you wish to operate on. Note: when the NoteBook is currently on the last page, and gtk_notebook_next_page is called, the notebook will wrap back to the first page. Likewise, if the NoteBook is on the first page, and gtk_notebook_prev_page is called, the notebook will wrap to the last page.
next_page
prev_page
This next procedure sets the 'active' page. If you wish the notebook to be opened to page 5 for example, you would use this procedure. Without using this function, the notebook defaults to the first page.
set_page ( arg_page_num : INTEGER )
The next two procedures add or remove the notebook page tabs and the notebook border respectively.
set_show_tabs ( show_tabs : BOOLEAN )
set_show_border ( show_border : BOOLEAN )
The next procedure is useful when the you have a large number of pages, and the tabs don't fit on the page. It allows the tabs to be scrolled through using two arrow buttons.
set_scrollable ( scrollable : BOOLEAN ) is
Now lets look at an example, it is expanded from the testgtk code that comes with the VEGTK distribution. This small program creates a window with a notebook and six buttons. The notebook contains 11 pages, added in three different ways, appended, inserted, and prepended. The buttons allow you rotate the tab positions, add/remove the tabs and border, remove a page, change pages in both a forward and backward manner, and exit the program.
-- example-start notebook notebook.e
class NOTEBOOK
inherit
GTK_CONSTANTS
VEGTK_MAIN
VEGTK_CALLBACK_HANDLER
creation
make
feature {ANY} -- Creation
make is
local
window : GTK_WINDOW;
button : GTK_BUTTON;
table : GTK_TABLE;
frame : GTK_FRAME;
label : GTK_LABEL;
checkbutton : GTK_CHECK_BUTTON;
i : INTEGER;
bufferf, bufferl : STRING;
do
vegtk_init
!!window.make (Gtk_window_toplevel);
signal_connect (window, "delete_event",$delete_event);
window.set_border_width (10);
!!table.make (3,6,False);
window.add (table);
-- Create a new notebook, place the position of the tabs
!!notebook.make;
notebook.set_tab_pos (Gtk_pos_top);
table.attach_defaults (notebook, 0,6,0,1);
notebook.show;
-- Lets append a bunch of pages to the notebook
from
i := 0;
until
i >=5
loop
!!bufferf.make_from_string("Append Frame ")
bufferf.append ((i+1).out);
!!bufferl.make_from_string("Page ");
bufferl.append ((i+1).out);
!!frame.make(bufferf);
frame.set_border_width (10);
frame.set_usize (100, 75);
frame.show;
!!label.make (bufferf);
frame.add (label);
label.show;
!!label.make (bufferl);
notebook.append_page (frame, label);
i := i+1;
end -- loop
-- Now lets add a page to a specific spot
!!checkbutton.make_with_label ("Check me please!");
checkbutton.set_usize(100, 75);
checkbutton.show;
!!label.make ("Add page");
notebook.insert_page ( checkbutton, label, 2);
-- Now finally lets prepend pages to the notebook
from
i := 0;
until
i >=5
loop
!!bufferf.make_from_string("Prepend Frame ")
bufferf.append ((i+1).out);
!!bufferl.make_from_string("PPage ");
bufferl.append ((i+1).out);
!!frame.make(bufferf);
frame.set_border_width (10);
frame.set_usize (100, 75);
frame.show;
!!label.make (bufferf);
frame.add (label);
label.show;
!!label.make (bufferl);
notebook.prepend_page (frame, label);
i := i+1;
end -- loop
-- Set what page to start at (page 4)
notebook.set_page (3);
-- Create a bunch of buttons
!!button.make_with_label ("close");
signal_connect (button,"clicked",$delete_event);
table.attach_defaults (button, 0,1,1,2);
button.show;
!!button.make_with_label ("next page");
signal_connect (button,"clicked",$notebook_next_page);
table.attach_defaults(button, 1,2,1,2);
button.show;
!!button.make_with_label ("prev page");
signal_connect (button,"clicked",$notebook_prev_page);
table.attach_defaults (button, 2,3,1,2);
button.show;
!!button.make_with_label ("tab position");
signal_connect (button, "clicked",$rotate_book);
table.attach_defaults(button, 3,4,1,2);
button.show;
!!button.make_with_label ("tabs/border on/off");
signal_connect (button, "clicked",$tabsborder_book);
table.attach_defaults(button, 4,5,1,2);
button.show;
!!button.make_with_label ("remove page");
signal_connect (button, "clicked",$remove_book);
table.attach_defaults(button, 5,6,1,2);
button.show;
table.show;
window.show;
gtk_main;
end -- make
feature {NONE} -- Callbacks
notebook_next_page is
do
notebook.next_page;
end
notebook_prev_page is
do
notebook.prev_page;
end
rotate_book is
-- This procedure rotates the position of the tabs
local
positions : ARRAY[GTK_POSITION_TYPE];
rotated : BOOLEAN;
i : INTEGER;
do
positions := << Gtk_pos_top,
Gtk_pos_right,
Gtk_pos_bottom,
Gtk_pos_left >>
from
i := positions.lower
until
rotated or i > positions.upper
loop
if notebook.tab_pos = positions.item(i).get_value then
notebook.set_tab_pos(positions.item((i \\ 4) +1))
rotated := True
end -- if
i := i+1
end -- loop
end
tabsborder_book is
-- Add/Remove the page tabs and the borders
local
tval,bval : BOOLEAN;
do
if not notebook.show_tabs then
tval := True;
end
if not notebook.show_border then
bval := True;
end
notebook.set_show_tabs (tval);
notebook.set_show_border (bval);
end
remove_book is
-- Remove a page from the notebook
do
notebook.remove_page (notebook.get_current_page);
-- Need to refresh the widget
-- This forces the widget to redraw itself.
notebook.draw(Void);
end
delete_event is
do
gtk_main_quit;
end
feature {NONE} -- Implementation
notebook : GTK_NOTEBOOK;
end -- class NOTEBOOK
-- example-end
Hopefully this helps you on your way with creating notebooks for your GTK applications.