[Previous] [Contents] [Next]
10. Container Widgets
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).
To create a new EventBox widget, use:
FUNCTION gtk_event_box_new() :
pGtkWidget;
A child widget can then be added to this EventBox:
PROCEDURE gtk_container_add( GTK_CONTAINER(event_box),
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.
If you want to see what the fancy mouse-over hand looks like you'll have to compile and run the program yourself.
PROGRAM eventbox;
USES gtk, gdk;
VAR
window, event_box, the_label : pGtkWidget;
{ -----------------------------------Main Program------------------------------ }
BEGIN
gtk_init(@argc, @argv);
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), 'Event Box');
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_exit),
NIL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
{ Create an EventBox and add it to our toplevel window }
event_box := gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(window), event_box);
gtk_widget_show(event_box);
{ Create a long label }
the_label := gtk_label_new('Click here to quit, quit, quit');
gtk_container_add(GTK_CONTAINER(event_box), the_label);
gtk_widget_show(the_label);
gtk_widget_set_usize(the_label, 110, 20);
{ Clip it short }
gtk_widget_set_events(event_box, GDK_BUTTON_PRESS_MASK);
{ And bind an action to it }
gtk_signal_connect(GTK_OBJECT(event_box), 'button_press_event',
GTK_SIGNAL_FUNC(@gtk_exit),
NIL);
{ Yet one more thing you need an X window for ...}
gtk_widget_realize(event_box);
gdk_window_set_cursor(event_box^.window,
gdk_cursor_new(GDK_HAND1));
gtk_widget_show(window);
gtk_main();
END.
{ ----------------------------Main Program------------------------------}
[Previous] [Contents] [Next]
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.
There is just one function and one procedure associated with the Alignment widget:
FUNCTION gtk_alignment_new( xalign :
gfloat ; yalign : gfloat ;
xscale : gfloat ;
yscale : gfloat ) : pGtkWidget;
PROCEDURE gtk_alignment_set( alignment :
pGtkAlignment ; xalign : gfloat ;
yalign : gfloat ;
xscale : gfloat ; yscale : gfloat );
The function creates a new Alignment widget with the specified parameters. The procedure allows the alignment
parameters of an exisiting Alignment widget to be altered.
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.
A child widget can be added to this Alignment widget using:
PROCEDURE gtk_container_add(GTK_CONTAINER(alignment),
child_widget );
For an example of using an Alignment widget, refer to the example for the Progress Bar
widget.
[Previous] [Contents] [Next]
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.
There are only two procedures and one function associated with the fixed widget:
FUNCTION gtk_fixed_new() :
pGtkWidget;
PROCEDURE gtk_fixed_put( fixed :
pGtkFixed ; widget : pGtkWidget ;
x : gint16 ;
y : gint16 );
PROCEDURE gtk_fixed_move( fixed :
pGtkFixed ; widget : pGtkWidget ;
x : gint16 ;
y : gint16 );
The function gtk_fixed_new() allows you to create a new Fixed container.
gtk_fixed_put() places widget in the container fixed at the position specified
by x and y.
gtk_fixed_move() allows the specified widget to be moved to a new position.
The following example illustrates how to use the Fixed Container. Clicking on any of the buttons marked
Press me will move the button according to the move_button() procedure defined in the program.
PROGRAM fixedexample;
USES gtk, glib;
{ ------------------------Global Variables-------------------------- }
VAR
x, y : gint;
{ x and y store the position of the widget within the fixed container }
index : Integer;
{ used by the button creating for loop }
window, fixed, button : pGtkWidget;
{ ---------------------------move_button----------------------------- }
PROCEDURE move_button( widget : pGtkWidget ;
fixed : pGtkWidget ); cdecl;
{ This callback moves the button to a new position in the Fixed container. }
BEGIN
x := (x+30) MOD 300;
y := (y+50) MOD 300;
gtk_fixed_move(GTK_FIXED(fixed), widget, x, y);
END;
{ ---------------------------move_button----------------------------- }
{ -----------------------------------Main Program------------------------------ }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
x := 50;
y := 50;
{ Create a new window }
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), 'Fixed Container');
{ Here we connect the destroy event to a signal handler }
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_main_quit), NIL);
{ Sets the border width of the window. }
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
{ Create a Fixed Container }
fixed := gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
gtk_widget_show(fixed);
FOR index := 1 TO 3 DO
BEGIN
{ Creates a new button with the label "Press me"}
button := gtk_button_new_with_label('Press me');
{ When the button receives the "clicked" signal, it will call the
function move_button() passing it the Fixed Container as its argument. }
gtk_signal_connect(GTK_OBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@move_button), @fixed);
{ This packs the button into the fixed containers window. }
gtk_fixed_put(GTK_FIXED(fixed), button, index*50, index*50);
{ The final step is to display this newly created widget. }
gtk_widget_show(button);
END;
gtk_widget_show(window); { Display the window }
gtk_main(); { Enter the event loop }
END.
{ --------------------------------Main Program-------------------------- }
[Previous] [Contents] [Next]
The Layout container is similar to the Fixed container except that it implements an infinite (where infinity is less than
2^32) scrolling area. The X window system 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.
A Layout container is created using:
FUNCTION gtk_layout_new( hadjustment :
pGtkAdjustment ;
vadjustment : pGtkAdjustment) :
pGtkWidget;
As you can see, you can optionally specify the Adjustment objects that the Layout widget will use for its scrolling.
You can add and move widgets in the Layout container using the following two procedures:
PROCEDURE gtk_layout_put( layout :
pGtkLayout ; widget : pGtkWidget ;
x : gint ;
y : gint );
PROCEDURE gtk_layout_move( layout :
pGtkLayout ; widget : pGtkWidget ;
x : gint ;
y : gint );
The size of the Layout container can be set using the next procedure:
PROCEDURE gtk_layout_set_size( layout :
pGtkLayout ; width : guint;
height : guint );
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 functions (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:
PROCEDURE gtk_layout_freeze( layout :
pGtkLayout );
PROCEDURE gtk_layout_thaw( layout :
pGtkLayout );
The final two functions and two procedures for use with Layout widgets are for manipulating the horizontal and
vertical adjustment widgets:
FUNCTION gtk_layout_get_hadjustment( layout :
pGtkLayout ) : pGtkAdjustment;
FUNCTION gtk_layout_get_vadjustment( layout :
pGtkLayout ) : pGtkAdjustment;
PROCEDURE gtk_layout_set_hadjustment( layout :
pGtkLayout ;
adjustment : pGtkAdjustment );
PROCEDURE gtk_layout_set_vadjustment( layout :
pGtkLayout ;
adjustment : pGtkAdjustment );
[Previous] [Contents] [Next]
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.
A Frame can be created with the following function:
FUNCTION gtk_frame_new( a_label :
pgchar ) : pGtkWidget;
The label is by default placed in the upper left hand corner of the frame. A value of NIL for
the label argument will result in no label being displayed. The text of the label can be changed using the next procedure.
PROCEDURE gtk_frame_set_label( frame :
pGtkFrame ; a_label : pgchar );
The position of the label can be changed using this procedure:
PROCEDURE gtk_frame_set_label_align( frame :
pGtkFrame ; xalign : gfloat ;
yalign : gfloat );
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.
PROCEDURE gtk_frame_set_shadow_type( frame :
pGtkFrame ; type : LONGINT );
The type argument can take one of the following values:
| GTK_SHADOW_NONE | GTK_SHADOW_IN | GTK_SHADOW_OUT |
| GTK_SHADOW_ETCHED_IN* | GTK_SHADOW_ETCHED_OUT | |
*the default
The following code example illustrates the use of the Frame widget.
PROGRAM frames;
USES gtk;
{ ------------------------Global Variables-------------------------- }
VAR
window, frame : pGtkWidget;
{ -----------------------------------Main Program------------------------------ }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
{ Create a new window }
gtk_window_set_title(GTK_WINDOW(window), 'Frame Example');
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_main_quit),
NIL);
{ Here we connect the --destroy-- event to a signal handler }
gtk_widget_set_usize(window, 300, 300);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
{ Sets the border width of the window. }
frame := gtk_frame_new( NIL);
{ Create a Frame }
gtk_container_add(GTK_CONTAINER(window), frame);
gtk_frame_set_label(GTK_FRAME(frame),
'GTK Frame Widget' );
{ Set the frame's label }
gtk_frame_set_label_align(GTK_FRAME(frame), 1.0, 0.0);
{ Align the label at the right of the frame }
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
{ Set the style of the frame }
gtk_widget_show(frame);
gtk_widget_show(window); { Display the window }
gtk_main(); { Enter the event loop }
END.
{ -----------------------------Main Program--------------------------- }
[Previous] [Contents] [Next]
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:
FUNCTION gtk_aspect_frame_new( a_label :
pgchar ; xalign : gfloat ;
yalign : gfloat ;
ratio : gfloat ; obey_child : gint ) :
pGtkWidget;
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:
PROCEDURE gtk_aspect_frame_set( aspect_frame :
pGtkAspectFrame ; xalign : gfloat ;
yalign : gfloat ;
ratio : gfloat ; obey_child : gint );
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.
PROGRAM aspectframes;
USES gtk;
{ ------------------------Global Variables-------------------------- }
VAR
window, aspect_frame, drawing_area : pGtkWidget;
{ -----------------------------------Main Program------------------------------ }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
{ Create a new window }
gtk_window_set_title(GTK_WINDOW(window), 'Aspect Frame');
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_main_quit), NIL);
{ Here we connect the --destroy-- event to a signal handler }
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
{ Sets the window border width }
{ Create an aspect_frame and add it to our toplevel window: }
aspect_frame := gtk_aspect_frame_new( '2x1',
{ label } 0.5, { center x }
0.5, { center y }
2, { xsize/ysize = 2 }
0 { i.e. false - ignore child's aspect } );
gtk_container_add(GTK_CONTAINER(window), aspect_frame);
gtk_widget_show(aspect_frame);
{ Now add a child widget to the aspect frame: }
drawing_area := gtk_drawing_area_new();
{ Ask for a 200x200 window, but the AspectFrame will give us a 200x100
window since we are forcing a 2x1 aspect ratio: }
gtk_widget_set_usize(drawing_area, 200, 200);
gtk_container_add(GTK_CONTAINER(aspect_frame), drawing_area);
gtk_widget_show(drawing_area);
gtk_widget_show(window); { Display the window }
gtk_main(); { Enter the event loop }
END.
{ -----------------------------Main Program--------------------------- }
[Previous] [Contents] [Next]
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).
To create a new paned window, call one of:
FUNCTION gtk_hpaned_new() :
pGtkWidget
FUNCTION gtk_vpaned_new() :
pGtkWidget
After creating the paned window widget, you need to add child widgets to its two halves. To do this, use the procedures:
PROCEDURE gtk_paned_add1( paned :
pGtkPaned ; child : pGtkWidget );
PROCEDURE gtk_paned_add2( paned :
pGtkPaned ; child : pGtkWidget );
gtk_paned_add1() adds the child widget to the left or top half of the paned window.
gtk_paned_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:
PROCEDURE gtk_paned_set_handle_size( paned :
pGtkPaned ; size : guint16 );
PROCEDURE gtk_paned_set_gutter_size( paned :
pGtkPaned ; size : guint16 );
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 e-mail program. A window is divided into two
portions vertically, with the top portion being a list of e-mail messages and the bottom portion the text of the e-mail
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
gtk_widget_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.
PROGRAM panedexample;
USES gtk, glib, sysutils;
{ ----------------------------------create_list--------------------------- }
FUNCTION create_list() : pGtkWidget;
{ Create the list of "messages" }
VAR
scrolled_window, list, list_item : pGtkWidget;
i : Integer;
label_str : String;
l_str_as_char_ptr : pChar;
BEGIN
{ Create a new scrolled window, with srollbars only if needed }
scrolled_window := gtk_scrolled_window_new( NIL,
NIL );
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
{ Create a new list and put it in the scrolled window}
list := gtk_list_new();
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), list);
gtk_widget_show(list);
{ Add some messages to the window }
FOR i := 1 TO 10 DO
BEGIN
label_str := 'Message #' + IntToStr(i);
l_str_as_char_ptr := StrAlloc(Length(label_str) + 1);
StrPCopy(l_str_as_char_ptr, label_str);
list_item := gtk_list_item_new_with_label(l_str_as_char_ptr);
gtk_container_add(GTK_CONTAINER(list), list_item);
gtk_widget_show(list_item);
END; { FOR i:=1 TO 10 DO }
create_list := scrolled_window;
END;
{ ----------------------------------create_list--------------------------- }
{ ----------------------------------realize_text--------------------------- }
PROCEDURE realize_text( text : pGtkWidget ;
data : gpointer ); cdecl;
{ 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 }
VAR
style : pGtkStyle;
BEGIN
gtk_text_freeze(GTK_TEXT(text));
style := gtk_widget_get_style(text);
gtk_text_insert(GTK_TEXT(text), NIL,
@style^.black, NIL,
'From: beagle2@esa.int'+#10+'To:
mum@esa.int'+#10+
'Subject: Made it to Mars!'+#10+#10+
'Just got in this morning. The weather has been dusty'+#10+
'(as expected). Have started looking for Martians.'+#10+
'Think I know why the Viking face is red. Tell you later!'+#10+
' -Beagle'#10' ', -1);
gtk_text_thaw(GTK_TEXT(text));
END;
{ -------------------------------------realize_text----------------------------------- }
{ ----------------------------------create_text--------------------------- }
FUNCTION create_text() : pGtkWidget;
{ Create a scrolled text area that displays a "message" }
VAR
table, text, hscrollbar, vscrollbar : pGtkWidget
BEGIN
{ Create a table to hold the text widget and scrollbars }
table := gtk_table_new(2, 2, FALSE);
{ Put a text widget in the upper left hand corner. Note the use of GTK_SHRINK in the
y direction: }
text := gtk_text_new(NIL, NIL);
gtk_table_attach(GTK_TABLE(table), text, 0, 1, 0, 1,
GTK_FILL OR GTK_EXPAND,
GTK_FILL OR GTK_EXPAND
OR GTK_SHRINK, 0, 0);
gtk_widget_show(text);
{ Put an HScrollbar in the lower left hand corner: }
hscrollbar := gtk_hscrollbar_new(GTK_TEXT(text)^.hadj);
gtk_table_attach(GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
GTK_EXPAND OR GTK_FILL,
GTK_FILL, 0, 0);
gtk_widget_show(hscrollbar);
{ And a VScrollbar in the upper right: }
vscrollbar := gtk_vscrollbar_new(GTK_TEXT(text)^.vadj);
gtk_table_attach(GTK_TABLE(table), vscrollbar, 1, 2, 0, 1, GTK_FILL,
GTK_EXPAND OR GTK_FILL
OR GTK_SHRINK, 0, 0);
gtk_widget_show(vscrollbar);
{ Add a handler to put a message in the text widget when it is realized: }
gtk_signal_connect(GTK_OBJECT(text), 'realize',
GTK_SIGNAL_FUNC(@realize_text), NIL);
create_text := table;
END;
{ ----------------------------------------create_text------------------------------------ }
{ ------------------------Global Variables-------------------------- }
VAR
window, vpaned, list, text : pGtkWidget;
{ -----------------------------------Main Program------------------------------ }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
{ Create a new window }
gtk_window_set_title(GTK_WINDOW(window), 'Paned Windows');
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_main_quit), NIL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_widget_set_usize(GTK_WIDGET(window), 370, 250);
{ create a vpaned widget and add it to our toplevel window: }
vpaned := gtk_vpaned_new();
gtk_container_add(GTK_CONTAINER(window), vpaned);
gtk_paned_set_handle_size(GTK_PANED(vpaned), 10);
gtk_paned_set_gutter_size(GTK_PANED(vpaned), 15);
gtk_widget_show(vpaned);
{ Now create the contents of the two halves of the window: }
list := create_list();
gtk_paned_add1(GTK_PANED(vpaned), list);
gtk_widget_show(list);
text := create_text();
gtk_paned_add2(GTK_PANED(vpaned), text);
gtk_widget_show(text);
gtk_widget_show(window);
gtk_main();
END.
{ -----------------------------------Main Program----------------------------- }
[Previous] [Contents] [Next]
It is unlikely that you will ever need to use the Viewport widget directly. You are much more likely to use the Scrolled
Window 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.
A Viewport is created with the function
FUNCTION gtk_viewport_new( hadjustment :
pGtkAdjustment ;
vadjustment : pGtkAdjustment ) :
pGtkWidget;
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 its own if you pass NIL as the value of the arguments.
You can get and set the adjustments after the widget has been created using these functions and procedures:
FUNCTION gtk_viewport_get_hadjustment( viewport :
pGtkViewport ) : pGtkAdjustment;
FUNCTION gtk_viewport_get_vadjustment( viewport :
pGtkViewport ) : pGtkAdjustment;
PROCEDURE gtk_viewport_set_hadjustment( viewport :
pGtkViewport ;
adjustment : pGtkAdjustment );
PROCEDURE gtk_viewport_set_vadjustment( viewport :
pGtkViewport ;
adjustment : pGtkAdjustment );
The only other viewport procedure is used to alter its appearance:
PROCEDURE gtk_viewport_set_shadow_type( viewport :
pGtkViewport ; type : LONGINT );
Possible values for the type parameter are:
| GTK_SHADOW_NONE | GTK_SHADOW_IN | GTK_SHADOW_OUT |
| GTK_SHADOW_ETCHED_IN | GTK_SHADOW_ETCHED_OUT | |
[Previous] [Contents] [Next]
Scrolled windows are used to create a scrollable area with another widget inside it. 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.
FUNCTION gtk_scrolled_window_new( hadjustment :
pGtkAdjustment ;
vadjustment : pGtkAdjustment ) :
pGtkWidget;
Where 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 NIL.
PROCEDURE gtk_scrolled_window_set_policy( scrolled_window :
pGtkScrolledWindow ;
hscrollbar_policy : LONGINT ;
vscrollbar_policy : LONGINT );
This sets the policy to be used with respect to the scrollbars. The first argument is the scrolled window you wish to
change. The second sets the policy for the horizontal scrollbar, and the third 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 procedure:
PROCEDURE gtk_scrolled_window_add_with_viewport(
scrolled_window :
pGtkScrolledWindow ;
child : pGtkWidget );
Here is a simple example that packs a table eith 100 toggle buttons into a scrolled window. I've only commented on the
parts that may be new to you.
PROGRAM scrolledwin;
USES gtk, glib, sysutils;
{ ---------------------------------destroy------------------------------------- }
PROCEDURE destroy( widget : pGtkWidget ; data :
gpointer ); cdecl;
BEGIN
gtk_main_quit();
END;
{ ----------------------------------destroy----------------------------------- }
{ ----------------------------------Global Variables------------------------- }
VAR
window, scrolled_window, table, button : pGtkWidget;
i, j : Integer;
label_str : String;
l_str_as_char_ptr : pchar;
{ --------------------------------Main Program-------------------------- }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
{ Create a new dialog window for the scrolled window to be packed into: }
window := gtk_dialog_new();
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@destroy), NIL);
gtk_window_set_title(GTK_WINDOW(window),
'GtkScrolledWindow example');
gtk_container_set_border_width(GTK_CONTAINER(window), 0);
gtk_widget_set_usize(window, 300, 300);
scrolled_window := gtk_scrolled_window_new(NIL,
NIL);
{ create a new scrolled window. }
gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 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.}
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
{ The dialog window is created with a vbox packed into it. }
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)^.vbox), scrolled_window,
TRUE, TRUE, 0);
gtk_widget_show(scrolled_window);
table := gtk_table_new(10, 10, FALSE);
{ create a table of 10 by 10 squares. }
{ set the spacing to 10 on x and 10 on y: }
gtk_table_set_row_spacings(GTK_TABLE(table), 10);
gtk_table_set_col_spacings(GTK_TABLE(table), 10);
{ pack the table into the scrolled window: }
gtk_scrolled_window_add_with_viewport(
GTK_SCROLLED_WINDOW(scrolled_window), table);
gtk_widget_show(table);
{ this simply creates a grid of toggle buttons on the table to demonstrate the scrolled
window.}
FOR i := 1 TO 10 DO
BEGIN
FOR j := 1 TO 10
DO
BEGIN
label_str := 'Button (' + IntToStr(i) + ',' +
IntToStr(j) + ')' + #10 + ' ';
l_str_as_char_ptr :=
StrAlloc(Length(label_str) + 1);
StrPCopy(l_str_as_char_ptr, label_str);
button := gtk_toggle_button_new_with_label(l_str_as_char_ptr);
gtk_table_attach_defaults(GTK_TABLE(table), button, i, i+1, j, j+1);
gtk_widget_show(button);
END;
END;
{ Add a --close-- button to the bottom of the dialog: }
button := gtk_button_new_with_label('close');
gtk_signal_connect_object(GTK_OBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@gtk_main_quit),
NIL);
GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
{ this makes the button the default. }
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)^.action_area), button,
TRUE, TRUE, 0);
{ This grabs this button to be the default button. Simply hitting the --Enter--
key will cause this button to activate: }
gtk_widget_grab_default(button);
gtk_widget_show(button);
gtk_widget_show(window);
gtk_main();
END.
{ ------------------------Main Program-------------------------- }
Try playing with resizing the window. You'll notice how the scrollbars react. You may also wish to use the
gtk_widget_set_usize() call to set the default size of the window or other widgets.
[Previous] [Contents] [Next]
Button Boxes are a convenient way to quickly layout a group of buttons. They come in both horizontal and vertical flavours.
You create a new Button Box with one of the following calls, which create a horizontal or vertical box, respectively:
FUNCTION gtk_hbutton_box_new() :
pGtkWidget;
FUNCTION gtk_vbutton_box_new() :
pGtkWidget;
The only attributes pertaining to button boxes effect how the buttons are laid out. You can change the spacing between
the buttons with:
PROCEDURE gtk_hbutton_box_set_spacing_default( spacing :
gint );
PROCEDURE gtk_vbutton_box_set_spacing_default( spacing :
gint );
Similarly, the current spacing values can be queried using:
FUNCTION gtk_hbutton_box_get_spacing_default() :
gint;
FUNCTION gtk_vbutton_box_get_spacing_default() :
gint;
The second attribute that we can access effects the layout of the buttons within the box. It is set using one of:
PROCEDURE gtk_hbutton_box_set_layout_default( layout :
LONGINT );
PROCEDURE gtk_vbutton_box_set_layout_default( layout :
LONGINT );
The layout argument can take one of the following values:
| GTK_BUTTONBOX_DEFAULT_STYLE | GTK_BUTTONBOX_SPREAD |
GTK_BUTTONBOX_EDGE |
| GTK_BUTTONBOX_START | GTK_BUTTONBOX_END | |
The current layout setting can be retrieved using:
FUNCTION gtk_hbutton_box_get_layout_default() :
LONGINT;
FUNCTION gtk_vbutton_box_get_layout_default() :
LONGINT;
Buttons are added to a Button Box using the usual procedure:
PROCEDURE gtk_container_add(GTK_CONTAINER(button_box),
child_widget);
Here's an example that illustrates all the different layout settings for Button Boxes.
PROGRAM buttonbox;
USES gtk, glib;
{ ---------------------------------create_bbox------------------------------------- }
FUNCTION create_bbox( horizontal : boolean ;
title : pchar ; spacing : gint ;
child_w : gint ;
child_h : gint ; layout : gint ) :
pGtkWidget;
{ Create a Button Box with the specified parameters }
VAR
frame, bbox, button : pGtkWidget;
BEGIN
frame := gtk_frame_new(pchar(title));
IF (horizontal = true)
THEN
bbox := gtk_hbutton_box_new()
ELSE
bbox := gtk_vbutton_box_new();
gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
gtk_container_add(GTK_CONTAINER(frame), bbox);
{ Set the appearance of the Button Box }
gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), layout);
gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), spacing);
gtk_button_box_set_child_size(GTK_BUTTON_BOX(bbox), child_w, child_h);
button := gtk_button_new_with_label('OK');
gtk_container_add(GTK_CONTAINER(bbox), button);
button := gtk_button_new_with_label('Cancel');
gtk_container_add(GTK_CONTAINER(bbox), button);
button := gtk_button_new_with_label('Help');
gtk_container_add(GTK_CONTAINER(bbox), button);
create_bbox := frame;
END;
{ ----------------------------------create_bbox----------------------------------- }
{ ----------------------------------Global Variables------------------------- }
VAR
window, main_vbox, vbox, hbox, frame_horz, frame_vert : pGtkWidget;
{ --------------------------------Main Program-------------------------- }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), 'Button Boxes');
gtk_signal_connect(GTK_OBJECT(window), 'destroy',
GTK_SIGNAL_FUNC(@gtk_main_quit),
NIL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
main_vbox := gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), main_vbox);
frame_horz := gtk_frame_new('Horizontal Button Boxes');
gtk_box_pack_start(GTK_BOX(main_vbox), frame_horz, TRUE,
TRUE, 10);
vbox := gtk_vbox_new(FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
gtk_container_add(GTK_CONTAINER(frame_horz), vbox);
gtk_box_pack_start(GTK_BOX(vbox),
create_bbox(TRUE,
pchar('Spread (spacing 40)'), 40, 85, 20,
GTK_BUTTONBOX_SPREAD), TRUE,
TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox),
create_bbox(TRUE,
pchar('Edge (spacing 30)'), 30, 85, 20,
GTK_BUTTONBOX_EDGE), TRUE,
TRUE, 5);
gtk_box_pack_start(GTK_BOX(vbox),
create_bbox( TRUE,
pchar('Start (spacing 20)'), 20, 85, 20,
GTK_BUTTONBOX_START), TRUE,
TRUE, 5);
gtk_box_pack_start(GTK_BOX(vbox),
create_bbox(TRUE,
pchar('End (spacing 10)'), 10, 85, 20,
GTK_BUTTONBOX_END), TRUE,
TRUE, 5);
frame_vert := gtk_frame_new('Vertical Button Boxes');
gtk_box_pack_start(GTK_BOX(main_vbox), frame_vert, TRUE,
TRUE, 10);
hbox := gtk_hbox_new(FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
gtk_container_add(GTK_CONTAINER(frame_vert), hbox);
gtk_box_pack_start(GTK_BOX(hbox),
create_bbox(FALSE,
pchar('Spread (spacing 5)'), 5, 85, 20,
GTK_BUTTONBOX_SPREAD), TRUE,
TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox),
create_bbox(FALSE,
pchar('Edge (spacing 30)'), 30, 85, 20,
GTK_BUTTONBOX_EDGE), TRUE,
TRUE, 5);
gtk_box_pack_start(GTK_BOX(hbox),
create_bbox(FALSE,
pchar('Start (spacing 20)'), 20, 85, 20,
GTK_BUTTONBOX_START), TRUE,
TRUE, 5);
gtk_box_pack_start(GTK_BOX(hbox),
create_bbox(FALSE,
pchar('End (spacing 20)'), 20, 85, 20,
GTK_BUTTONBOX_END), TRUE,
TRUE, 5);
gtk_widget_show_all(window);
gtk_main(); { Enter the event loop }
END.
{ ----------------------------------Main Program----------------------------- }
[Previous] [Contents] [Next]
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.
Creating a toolbar is (as one may already suspect) done with the following function:
FUNCTION gtk_toolbar_new( orientation :
LONGINT ; style : LONGINT ) :
pGtkWidget;
where 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 text strings) or elements (that means
any widget types) 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:
FUNCTION gtk_toolbar_append_item( toolbar :
pGtkToolbar ; text : pchar ;
tooltip_text : pchar ;
tooltip_private_text : pchar ; icon : pGtkWidget ;
callback : GtkSignalFunc ;
user_data : gpointer ) : pGtkWidget;
FUNCTION gtk_toolbar_prepend_item( toolbar :
pGtkToolbar ; text : pchar ;
tooltip_text : pchar ;
tooltip_private_text : pchar ; icon : pGtkWidget ;
callback : GtkSignalFunc ;
user_data : gpointer ) : pGtkWidget;
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:
FUNCTION gtk_toolbar_insert_item( toolbar :
pGtkToolbar ; text : pchar ;
tooltip_text : pchar ;
tooltip_private_text : pchar ; icon : pGtkWidget ;
callback : GtkSignalFunc ;
user_data : gpointer ; position : gint )
: pGtkWidget;
To simplify adding spaces between toolbar items, you may use the following procedures:
PROCEDURE gtk_toolbar_append_space( toolbar :
pGtkToolbar );
PROCEDURE gtk_toolbar_prepend_space( toolbar :
pGtkToolbar );
PROCEDURE gtk_toolbar_insert_space( toolbar :
pGtkToolbar ; position : gint );
While the size of the added space can be set globally for a whole toolbar with the procedure:
PROCEDURE gtk_toolbar_set_space_size( toolbar :
pGtkToolbar ; space_size : gint );
If it's required, the orientation of a toolbar and its style can be changed on the fly using the following procedures:
PROCEDURE gtk_toolbar_set_orientation( toolbar :
pGtkToolbar ; orientation : LONGINT );
PROCEDURE gtk_toolbar_set_style( toolbar :
pGtkToolbar ; style: LONGINT );
PROCEDURE gtk_toolbar_set_tooltips( toolbar :
pGtkToolbar ; enable: gint );
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). To start off though, it might be useful to see what we're aiming at. In order to see the
different tooltips you'll need to compile and run the program yourself, but this is what the rest of it looks like:
PROGRAM toolbars;
USES glib, gdk, gtk;
{ XPM data of icon to be used for all buttons }
CONST
gtk_xpm : ARRAY[0..45] OF
pchar =
('32 39 5 1',
'. c none',
'+ c black',
'@ c #3070E0',
'# c #F05050',
'$ c #35E035',
'................+...............',
'..............+++++.............',
'............+++++@@++...........',
'..........+++++@@@@@@++.........',
'........++++@@@@@@@@@@++........',
'......++++@@++++++++@@@++.......',
'.....+++@@@+++++++++++@@@++.....',
'...+++@@@@+++@@@@@@++++@@@@+....',
'..+++@@@@+++@@@@@@@@+++@@@@@++..',
'.++@@@@@@+++@@@@@@@@@@@@@@@@@@++',
'.+#+@@@@@@++@@@@+++@@@@@@@@@@@@+',
'.+##++@@@@+++@@@+++++@@@@@@@@$@.',
'.+###++@@@@+++@@@+++@@@@@++$$$@.',
'.+####+++@@@+++++++@@@@@+@$$$$@.',
'.+#####+++@@@@+++@@@@++@$$$$$$+.',
'.+######++++@@@@@@@++@$$$$$$$$+.',
'.+#######+##+@@@@+++$$$$$$@@$$+.',
'.+###+++##+##+@@++@$$$$$$++$$$+.',
'.+###++++##+##+@@$$$$$$$@+@$$@+.',
'.+###++++++#+++@$$@+@$$@++$$$@+.',
'.+####+++++++#++$$@+@$$++$$$$+..',
'.++####++++++#++$$@+@$++@$$$$+..',
'.+#####+++++##++$$++@+++$$$$$+..',
'.++####+++##+#++$$+++++@$$$$$+..',
'.++####+++####++$$++++++@$$$@+..',
'.+#####++#####++$$+++@++++@$@+..',
'.+#####++#####++$$++@$$@+++$@@..',
'.++####++#####++$$++$$$$$+@$@++.',
'.++####++#####++$$++$$$$$$$$+++.',
'.+++####+#####++$$++$$$$$$$@+++.',
'..+++#########+@$$+@$$$$$$+++...',
'...+++########+@$$$$$$$$@+++....',
'.....+++######+@$$$$$$$+++......',
'......+++#####+@$$$$$@++........',
'.......+++####+@$$$$+++.........',
'.........++###+$$$@++...........',
'..........++##+$@+++............',
'...........+++++++..............',
'.............++++...............');
{ --------------------------------delete_event---------------------------- }
PROCEDURE delete_event( widget : pGtkWidget ; data :
gpointer ); cdecl;
{ This procedure is connected to the Close button or closing the window from the WM }
BEGIN
gtk_main_quit();
END;
The above beginning seems for sure familiar to you if it's not your first GTK program. There is one additional thing
though, we include a nice XPM picture to serve as an icon for all of the buttons.
{ ----------------------------------Global Variables------------------------- }
VAR
close_button, tooltips_button, text_button, icon_button,
both_button, entry : pGtkWidget;
{ text_, icon_ and both_ buttons will be radio buttons for selecting the toolbar style }
{ For our main window (a dialog) and a handle for the handlebox: }
dialog, handlebox : pGtkWidget;
{ 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, iconw : pGtkWidget;
icon : pGdkPixmap;
mask : pGdkBitmap;
style : pGtkStyle;
In fact not all of the above widgets are needed here, but to make things clearer I put them all together.
{ ---------------------------radio_event----------------------------- }
PROCEDURE radio_event( widget : pGtkWidget ; data :
gpointer ); cdecl;
{ when one of the buttons is toggled, we check which one is active and set the style of the
toolbar accordingly. ATTENTION: our toolbar is passed as data to callback! }
BEGIN
IF ( active(GTK_TOGGLE_BUTTON(text_button)^) ) THEN
gtk_toolbar_set_style(GTK_TOOLBAR(data), GTK_TOOLBAR_TEXT)
ELSE IF ( active(GTK_TOGGLE_BUTTON(icon_button)^) ) THEN
gtk_toolbar_set_style(GTK_TOOLBAR(data), GTK_TOOLBAR_ICONS)
ELSE IF ( active(GTK_TOGGLE_BUTTON(both_button)^) ) THEN
gtk_toolbar_set_style(GTK_TOOLBAR(data), GTK_TOOLBAR_BOTH);
END;
{ -----------------------------------radio_event------------------------------- }
{ --------------------------------toggle_event------------------------------- }
PROCEDURE toggle_event( widget : pGtkWidget ; data :
gpointer );
{ check given toggle button and enable/disable tooltips}
BEGIN
gtk_toolbar_set_tooltips(GTK_TOOLBAR(data), active(GTK_TOGGLE_BUTTON(widget)^));
END;
{ ----------------------------------toggle_event----------------------------- }
The above are just two callbacks that will be called when one of the buttons on a toolbar is pressed. You should
already be familiar with things like this if you've already used toggle buttons (and radio buttons).
{ --------------------------------Main Program-------------------------- }
BEGIN
gtk_init(@argc, @argv); { Initialise GTK }
dialog := gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog) ,
'GTKToolbar Tutorial' );
gtk_widget_set_usize(GTK_WIDGET(dialog) , 600 , 300 );
GTK_WINDOW(dialog)^.allow_shrink := TRUE;
{ as usual we quit if someone tries to close us }
gtk_signal_connect(GTK_OBJECT(dialog), 'delete_event',
GTK_SIGNAL_FUNC(@delete_event), NIL);
{ we need to realize the window because we use pixmaps for items on the toolbar in
the context of it}
gtk_widget_realize(dialog);
{ to make it nice we'll put the toolbar into the handle box, so that it can be detached
from the main window }
handlebox := gtk_handle_box_new();
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)^.vbox), handlebox,
FALSE, FALSE, 5);
The above should be similar to any other GTK application. Just initialization of GTK, creating the window, etc. There is
only one thing that probably needs some explanation: a handle box. A handle box is just another box that can be used to pack
widgets in to. The difference between it and typical boxes is that it can be detached from a parent window (or, in fact, the
handle box remains in the parent, but it is reduced to a very small rectangle, while all of its contents are re-parented to
a new freely floating window). It is usually nice to have a detachable toolbar, so these two widgets occur together quite
often.
{ 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 := gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH );
gtk_container_set_border_width(GTK_CONTAINER(toolbar), 5);
gtk_toolbar_set_space_size(GTK_TOOLBAR(toolbar), 5);
gtk_container_add(GTK_CONTAINER(handlebox), toolbar);
{ now we create icon with mask: we'll reuse it to create icon widgets for
toolbar items}
style := gtk_widget_get_style(dialog);
icon := gdk_pixmap_create_from_xpm_d(dialog^.window, @mask, @style^.white, gtk_xpm );
Well, what we do above is just a straightforward initialization of the toolbar widget and creation of a GDK pixmap with
its mask. If you want to know something more about using pixmaps, refer to GDK documentation or to the Pixmaps section
earlier in this tutorial.
{ our first item is close button }
iconw := gtk_pixmap_new(icon, mask); { icon widget }
close_button := gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),
{our toolbar}
'Close', {button label}
'Closes this app', {this button's tooltip}
'Private', {tooltip private info}
iconw, {icon widget}
GTK_SIGNAL_FUNC(@delete_event), {a signal}
NIL );
gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
{space after item}
In the above code you see the simplest case: adding a button to toolbar. Just before appending a new item, we have to
construct a pixmap widget to serve as an icon for this item; this step will have to be repeated for each new item. Just
after the item we also add a space, so the following items will not touch each other. As you see
gtk_toolbar_append_item() returns a pointer to our newly created button widget, so that we can
work with it in the normal way.
{ now, let's make our radio buttons group... }
iconw := gtk_pixmap_new(icon, mask);
icon_button := gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON, {a type of element}
NIL, {pointer to widget}
'Icon', {label}
'Only icons in toolbar', {tooltip}
'Private', {tooltip private string}
iconw, {icon}
GTK_SIGNAL_FUNC(@radio_event), {signal} toolbar);
{ data for signal }
gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
Here we begin creating a radio buttons group. To do this we use gtk_toolbar_append_element().
In fact, using this function one can also add simple items or even spaces (type = GTK_TOOLBAR_CHILD_SPACE or
GTK_TOOLBAR_CHILD_BUTTON). In the above case we start creating a radio group. In creating other radio buttons for
this group a pointer to the previous button in the group is required, so that a list of buttons can be easily constructed
(see the section on Radio Buttons earlier in this tutorial).
{ following radio buttons refer to previous ones }
iconw := gtk_pixmap_new(icon, mask);
text_button := gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON, icon_button, 'Text',
'Only texts in toolbar',
'Private', iconw,
GTK_SIGNAL_FUNC(@radio_event), toolbar);
gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
iconw := gtk_pixmap_new(icon, mask);
both_button := gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_RADIOBUTTON, text_button, 'Both',
'Icons and text in toolbar',
'Private', iconw,
GTK_SIGNAL_FUNC(@radio_event), toolbar);
gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
{ Set both_button depressed when program starts }
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),
TRUE);
In the end we have to set the state of one of the buttons manually (otherwise they all stay in active state, preventing us
from switching between them).
{ here we have just a simple toggle button }
iconw := gtk_pixmap_new(icon, mask);
tooltips_button := gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
GTK_TOOLBAR_CHILD_TOGGLEBUTTON, NIL,
'Tooltips',
'Toolbar with or without tips',
'Private', iconw,
GTK_SIGNAL_FUNC(@toggle_event), toolbar);
gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),
TRUE);
A toggle button can be created in the obvious way (if one knows how to create radio buttons already).
{ to pack a widget into toolbar, we only have to create it and append it with an
appropriate tooltip }
entry := gtk_entry_new();
gtk_toolbar_append_widget(GTK_TOOLBAR(toolbar), entry,
'This is just an entry',
'Private' );
{ well, it isn't created within the toolbar, so we must still show it }
gtk_widget_show(entry);
As you see, adding any kind of widget to a toolbar is simple. The one thing you have to remember is that this widget
must be shown manually (contrary to other items which will be shown together with the toolbar).
{ that's it ! let's show everything. }
gtk_widget_show(toolbar);
gtk_widget_show(handlebox);
gtk_widget_show(dialog);
{ rest in gtk_main and wait for the fun to begin! }
gtk_main();
END.
{ --------------------------------Main Program------------------------------ }
[Previous] [Contents] [Next]
The NoteBook Widget is a collection of pages that overlap each other, each page contains different information with
only one page visible at a time. 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.
The first function call you will need to know, as you can probably guess by now, is used to create a new notebook widget.
FUNCTION gtk_notebook_new() :
pGtkWidget;
Once the notebook has been created, there are a number of functions 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.
PROCEDURE gtk_notebook_set_tab_pos( notebook :
pGtkNotebook ; position : LONGINT );
position will be one of the following, which are pretty self explanatory:
| GTK_POS_LEFT | GTK_POS_RIGHT | GTK_POS_TOP |
GTK_POS_BOTTOM |
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.
PROCEDURE gtk_notebook_append_page( notebook :
pGtkNotebook ; child : pGtkWidget ;
tab_label : pGtkWidget );
PROCEDURE gtk_notebook_prepend_page( notebook :
pGtkNotebook ; child : pGtkWidget ;
tab_label : pGtkWidget );
These functions 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 setup witin
one of the other container widgets, such as a table.
The final function 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.
PROCEDURE gtk_notebook_insert_page( notebook :
pGtkNotebook ; child : pGtkWidget ;
tab_label : pGtkWidget ;
position : gint );
The parameters are the same as _append_ and _prepend_ except for
the extra parameter, position. This parameter is used to specify what place this page will be inserted into the
first page having position zero.
Now that we know how to add a page, lets see how we can remove a page from the notebook.
PROCEDURE gtk_notebook_remove_page( notebook :
pGtkNotebook ; page_num : gint );
This procedure 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:
FUNCTION gtk_notebook_get_current_page( notebook :
pGtkNotebook ) : gint;
These next two procedures are simple calls to move the notebook page forward or backward. Simply provide the respective
procedure call with 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.
PROCEDURE gtk_notebook_next_page( notebook :
pGtkNoteBook );
PROCEDURE gtk_notebook_prev_page( notebook :
pGtkNoteBook );
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 procedure, the notebook defaults to the first page.
PROCEDURE gtk_notebook_set_page( notebook :
pGtkNoteBook ; page_num : gint );
The next two procedures add or remove the notebook page tabs and the notebook border respectively.
PROCEDURE gtk_notebook_show_tabs( notebook :
pGtkNoteBook ;
show_tabs : gboolean );
PROCEDURE gtk_notebook_show_border( notebook :
pGtkNoteBook ;
show_border : gboolean );
The next function 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.
PROCEDURE gtk_notebook_set_scrollable( notebook :
pGtkNoteBook ;
scrollable : gboolean );
show_tabs, show_border and scrollable can be either TRUE or
FALSE.
Now let's look at an example, it is expanded from the testgtk.c code that comes with the GTK 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.
{ Converted from C to Pascal by Frank Loemker <floemker@techfak.uni-bielefeld.de> }
PROGRAM notebook;
USES glib,gdk,gtk;
{ ------------------------------itos------------------------------- }
FUNCTION itos( I : LONGINT ) :
String;
{ converts longint type to a String }
VAR
S : String[15];
BEGIN
Str(I, S);
itos := S;
END;
{ --------------------------itos-------------------------------- }
{ -----------------------------rotate_book------------------------- }
PROCEDURE rotate_book(notebook : pGtkNotebook );
cdecl;
{ This function rotates the position of the tabs }
BEGIN
gtk_notebook_set_tab_pos(notebook,
tGtkPositionType((tab_pos(notebook^) +1) mod 4));
END;
{ --------------------------rotate_book------------------------- }
{ ------------------------------tabsborder_book-------------------- }
PROCEDURE tabsborder_book( notebook : pGtkNotebook );
cdecl;
{ Add/Remove the page tabs and the borders }
VAR
tval, bval : gboolean;
BEGIN
tval := false;
bval := false;
IF show_tabs(notebook^) = 0 THEN
tval := true;
IF show_border(notebook^) = 0 THEN
bval := true;
gtk_notebook_set_show_tabs(notebook, tval);
gtk_notebook_set_show_border(notebook, bval);
END;
{ --------------------------tabsborder_book--------------------- }
{ -------------------------------remove_book------------------------ }
PROCEDURE remove_book( notebook : pGtkNotebook );
cdecl;
{ Remove a page from the notebook }
VAR
page : gint;
BEGIN
page := gtk_notebook_get_current_page(notebook);
gtk_notebook_remove_page(notebook, page);
{ Need to refresh the widget -- This forces the widget to redraw itself: }
gtk_widget_draw(pGTKWIDGET(notebook), NIL);
END;
{ ---------------------------remove_book------------------------- }
{ ------------------------------delete------------------------------- }
PROCEDURE delete( widget : pGtkWidget ;
event : pGdkEvent ;
data : pgpointer );
cdecl;
BEGIN
gtk_main_quit();
END;
{ ---------------------------delete----------------------------- }
{ ----------------------------Global Variables------------------------ }
VAR
window, button, table, thenotebook, frame, thelabel, checkbutton : pGtkWidget;
i : Integer;
bufferf, bufferl : String[33];
{ ----------------------------Main Program---------------------------- }
BEGIN
gtk_init(@argc, @argv);
window := gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(pGTKOBJECT(window), 'delete_event',
GTK_SIGNAL_FUNC(@delete), NIL);
gtk_container_set_border_width(pGTKCONTAINER(window), 10);
table := gtk_table_new(2, 6, FALSE);
gtk_container_add(pGTKCONTAINER(window), table);
{ Create a new notebook, place the position of the tabs }
thenotebook := gtk_notebook_new();
gtk_notebook_set_tab_pos(pGTKNOTEBOOK(thenotebook), GTK_POS_TOP);
gtk_table_attach_defaults(pGTKTABLE(table), thenotebook, 0, 6, 0, 1);
{ lets append a bunch of pages to the notebook }
FOR i := 0 TO 4 DO
BEGIN
bufferf := 'Append Frame ' + itos(i+1) + #0;
bufferl := 'Page ' + itos(i+1) + #0;
frame := gtk_frame_new( pchar(@bufferf[1]) );
gtk_container_set_border_width(pGTKCONTAINER(frame), 10);
gtk_widget_set_usize(frame, 100, 75);
thelabel := gtk_label_new( pchar(@bufferf[1]) );
gtk_container_add(pGTKCONTAINER(frame), thelabel);
thelabel := gtk_label_new( pchar(@bufferl[1]) );
gtk_notebook_append_page(pGTKNOTEBOOK(thenotebook), frame, thelabel);
END; { 0 TO 4 DO }
{ now lets add a page to a specific spot }
checkbutton := gtk_check_button_new_with_label('Check me please!');
gtk_widget_set_usize(checkbutton, 100, 75);
thelabel := gtk_label_new('Add page');
gtk_notebook_insert_page(pGTKNOTEBOOK(thenotebook), checkbutton, thelabel, 2);
{ Now finally lets prepend pages to the notebook }
FOR i := 0 TO 4 DO
BEGIN
bufferf := 'Prepend Frame ' + itos(i+1) + #0;
bufferl := 'PPage ' + itos(i+1) + #0;
frame := gtk_frame_new( pchar(@bufferf[1]) );
gtk_container_set_border_width(pGTKCONTAINER(frame), 10);
gtk_widget_set_usize(frame, 100, 75);
thelabel := gtk_label_new( pchar(@bufferf[1]) );
gtk_container_add(pGTKCONTAINER(frame), thelabel);
thelabel := gtk_label_new( pchar(@bufferl[1]) );
gtk_notebook_prepend_page(pGTKNOTEBOOK(thenotebook), frame, thelabel);
gtk_widget_show(frame);
END; { 0 TO 4 DO }
{ Set the page to start at (page 4) }
gtk_notebook_set_page(pGTKNOTEBOOK(thenotebook), 3);
{ create a bunch of buttons }
button := gtk_button_new_with_label('close');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@delete), NIL);
gtk_table_attach(pGTKTABLE(table), button, 0, 1, 1, 2,
GTK_FILL OR GTK_EXPAND, GTK_FILL, 0, 0);
button := gtk_button_new_with_label('next page');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@gtk_notebook_next_page), pGTKOBJECT(thenotebook));
gtk_table_attach(pGTKTABLE(table), button, 1, 2, 1, 2,
GTK_FILL OR GTK_EXPAND, GTK_FILL, 0, 0);
button := gtk_button_new_with_label('prev page');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@gtk_notebook_prev_page), pGTKOBJECT(thenotebook));
gtk_table_attach(pGTKTABLE(table), button, 2, 3, 1, 2,
GTK_FILL OR GTK_EXPAND, GTK_FILL, 0, 0);
button := gtk_button_new_with_label('tab position');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@rotate_book), pGTKOBJECT(thenotebook));
gtk_table_attach(pGTKTABLE(table), button, 3, 4, 1, 2,
GTK_FILL OR GTK_EXPAND, GTK_FILL, 0, 0);
button := gtk_button_new_with_label('tabs/border on/off');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@tabsborder_book), pGTKOBJECT(thenotebook));
gtk_table_attach(pGTKTABLE(table), button, 4, 5, 1, 2,
GTK_FILL OR GTK_EXPAND, GTK_FILL, 0, 0);
button := gtk_button_new_with_label('remove page');
gtk_signal_connect_object(pGTKOBJECT(button), 'clicked',
GTK_SIGNAL_FUNC(@remove_book), pGTKOBJECT(thenotebook));
gtk_table_attach(pGTKTABLE(table), button, 5, 6, 1, 2,
GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show_all(window);
gtk_main();
END.
{ ------------------------------Main Program------------------------------ }
I hope this helps you on your way with creating notebooks for your GTK applications.
[Previous] [Contents] [Next]