When creating an application, you'll want to put more than one widget inside a
window. Our first "hello world" example only used one widget so we could simply
use set
to specify a containerChild
widget for
window
, or use containerAdd
to "pack" the widget into
the window. But when you want to put more than one widget into a window, how do
you control where that widget is positioned? This is where packing comes in.
Most packing is done by creating boxes. These are invisible widget containers that we can pack our widgets into which come in two forms: a horizontal box and a vertical box. When packing widgets into a horizontal box, the objects are inserted horizontally from left to right or right to left depending on the call used. In a vertical box, widgets are packed from top to bottom or vice versa. You may use any combination of boxes inside or beside other boxes to create the desired effect.
To create a new horizontal box, we use hBoxNew
, and for vertical
boxes, vBoxNew
. Both take a Bool
and an
Int
parameter. The first parameter will give all children equal
space allotments if set to True and the second sets the number of
pixels to place by default between the children.
The boxPackStart
and boxPackEnd
functions are used to
place objects inside of these containers. The boxPackStart
function will start at the top and work its way down in a VBox
,
and pack left to right in an HBox
. boxPackEnd
will do
the opposite, packing from bottom to top in a VBox
, and right to
left in an HBox
. Using these functions allows us to right justify
or left justify our widgets and they may be mixed in any way to achieve the
desired effect. We will use boxPackStart
in most of our examples.
An object may be another container or a widget. In fact, many widgets are
actually containers themselves—including button
, but we
usually only use a label
inside a button
.
import Graphics.UI.Gtk main :: IO () main = do initGUI window <- windowNew hbox <- hBoxNew True 10 button1 <- buttonNewWithLabel "Button 1" button2 <- buttonNewWithLabel "Button 2" set window [windowDefaultWidth := 200, windowDefaultHeight := 200, containerBorderWidth := 10, containerChild := hbox] boxPackStart hbox button1 PackGrow 0 boxPackStart hbox button2 PackGrow 0 onDestroy window mainQuit widgetShowAll window mainGUI
By using boxPackStart
or boxPackEnd
, GTK knows where
you want to place your widgets so it can do automatic resizing and other nifty
things.
boxPackStart :: (WidgetClass child, BoxClass self) => self -> child -> Packing -> Int -> IO ()
boxPackEnd :: (WidgetClass child, BoxClass self) => self -> child -> Packing -> Int -> IO ()
The Packing
parameter specifies the way the widgets in the
container behave when the window is resized. PackNatural
means the
widgets will retain their size and stay where they are, PackGrow
means they will be resized, and using PackRepel
the widgets will
be padded equally on both sides. The last parameter is an Int
,
which specifies any extra padding to be put between this child and its
neighbours.
Note that the packing only applies to the dimension of the box. If, for
example, you specify PackNatural
instead of PackGrow
in the above, resizing horizontally will keep the buttons at their original
size, but resizing vertically will also resize the buttons. This is because the
buttons are placed homogeneously in the horizontal box (the first parameter is
True) and the box itself will resize with the window. The next
example will make the effects more clear.