Understanding Gtk# Layout Managers
Gtk# provides a number of widgets which, while invisible at runtime, are used to organize (or in the nomenclature of Gtk#, pack
) a collection of related widgets into a container. Using types such as VBox (vertical box) and HBox (horizontal box) you can establish a consistent GUI layout that maintains the relative position of the widgets when end users resize your windows.
Both of these types have methods named PackStart()
that add a widget to the HBox or VBox type. Calling PackStart()
on an HBox type packs the widget into the box from left to right, while calling the same method on a VBox type adds the items in a top-down manner. In either case, PackStart()
takes four parameters that control how to position the incoming Widget-derived type within the box:
|Figure 6. HBox Packing: Packing the MenuBar within an HBox object results in a radically different menu layout.|
void PackStart( Widget widgetToAdd, bool expand,
bool fill, uint padding )
method shown earlier uses the VBox type to pack in the MenuBar object; therefore the menu system is attached to the upper left corner of the Window type. However, by way of illustration, if you were to update CreateMenu()
to make use of an HBox type, you would see a radically different widget arrangement (see Figure 6
). Here's the altered code:
// Now with an HBox!
HBox h = new HBox();
h.PackStart(mainMenu, false, false, 0);
Using HBox and VBox types in this manner is very common when building Gtk# user interfaces. You may be thinking that building a complicated UI in this manner would be quite tedious and labor intensive (and I would agree). Thankfully, many Mono IDEs provide visual designers for working with the visual layout of widgets. However, to further illustrate the role of the HBox and VBox types, it's worth exploring the process of building a dialog box using Gtk#.
Building Gtk# Dialog Boxes
|Figure 7. The Updated Menu System: Here's the menu showing an added Tools menu, with a sub item called "Enter Name."|
Assume that the standard (VBox-based) version of the CreateMenu()
method has been updated to define a new topmost menu item named Tools, which defines a sub item called "Enter Name" (see Figure 7
I won't bother to list the menu construction code here (as it is more or less identical to the code used to build the File | Exit menu), however you can find the full CreateMenu()
implementation in the WindowWithDialog.cs
file in the sample code
When the end user clicks on the Enter Name menu option, the application should display a custom dialog in which users can enter a first and last name. This activity will occur in the event hander for the Enter Name MenuItem's Activated
event. You'll see the full implementation shortly; for now, some simple stub code will suffice:
void ToolsEnterName_Activated(object sender, EventArgs args)
// ToDo! Show our custom dialog box and gather user input.
|Figure 8. A Custom Dialog Box: The figure shows the dialog that appears when users click the Enter Name menu item.|
The Gtk.Dialog class is the parent for dialogs in the Gtk# API. Like the Window type, you can either create a Dialog object directly or subclass Dialog to build a strongly-typed derived class. To facilitate code reuse, let's opt for the later alternative. When complete, the dialog (named UserNameDialog) will look like Figure 8
The dialog implementation breaks down into the following main tasks:
- UserNameDialog will extend the Gtk.Dialog base class.
- The dialog will define two member variables of type Entry (text fields) that allow users to enter their first and last names.
- The dialog will support stock OK and Cancel buttons.
- The dialog will define two read-only properties (FirstName and LastName) to allow the owning window to extract the value in each Entry object.
With that said, Listing 2
contains the complete definition of the UserNameDialog type, with analysis to follow.
The first point of interest takes place in the BuildDialogUI()
method. Notice that the Gtk.Dialog parent class defines a VBox
property, to which the method adds an HBox object:
// Add an HBox to the dialog's VBox.
HBox hbox = new HBox (false, 8);
hbox.BorderWidth = 8;
this.VBox.PackStart (hbox, false, false, 0);
If adding HBoxes to VBoxes sounds odd, recall that VBox widgets add items in a top-down manner. It just so happens that the item in the dialog's VBox is an HBox (which adds widgets in a left-to-right manner).
Next, the method adds an Image widget to the HBox, set to make use of the stock information image of the Gtk# libraries.
// Add an Image widget to the HBox using a stock 'info' icon.
Image stock = new Image (Stock.DialogInfo, IconSize.Dialog);
hbox.PackStart (stock, false, false, 0);
The second item added to the HBox is a Gtk.Table widget. Much like an HTML-based Table, the Table widget allows you to pack in items using a cell-like placement scheme.
Table table = new Table (2, 2, false);
table.RowSpacing = 4;
table.ColumnSpacing = 4;
hbox.PackStart (table, true, true, 0);
Label label = new Label ("_First Name");
table.Attach (label, 0, 1, 0, 1);
table.Attach (fNameEntry, 1, 2, 0, 1);
label.MnemonicWidget = fNameEntry;
label = new Label ("_Last Name");
table.Attach (label, 0, 1, 1, 2);
table.Attach (lNameEntry , 1, 2, 1, 2);
label.MnemonicWidget = lNameEntry ;
Notice that the code aligns the Label and Entry items using the Attach()
method. The final four arguments of that method represent the coordinates of the top left and bottom right positions to place the widget:
void Attach (Widget widget, uint left_attach,
uint right_attach, uint top_attach,
After informing the HBox to display each item, we then add two stock button types via the AddButton()
method inherited from the parent Gtk.Dialog class.
Take note that the second argument to this method is a value from the ResponseType enumeration. As you'll see shortly, assigning ResponseType values to a Button widget makes it very simple to determine which button the end user clicked.