A dialog is an example of a composite widget. It consists of a window, an upper part which is a vertical box, and an action area which is a horizontal box. By default, both parts are separated by a horizontal separator.
Dialog widget can be used for pop-up messages to the user, and
other similar tasks. The basic functions needed are:
dialogNew :: IO Dialog dialogRun :: DialogClass self => self -> IO ResponseID
You add buttons into the action area with:
dialogAddButton :: DialogClass self => self -> String -> ResponseId -> IO Button
Any widget can be added in a similar way with
dialogAddButton can be the text of the
button, but since dialogs are mostly used for standard situations a
StockItem will usually be more appropriate.
StockItems are resources which are known throughout Gtk2Hs, such
IconSets. You can define your own, but many useful
ones are listed in the
They have an identifier
StockId, which is a type synonym for
String. From this identifier a widget (usually a button) with the
appropriate standard text and icon is automatically selected.
If you use a
StockId when adding a button to a dialog, you can
also use a pre-defined
ResponseId constructor with the buttons.
ResponseId is not a
String.) Customized responses
may be constructed with
Whenever a dialog button is pressed, its response is passed to the calling
dialogRun. According to the Gtk2Hs API
dialogRun blocks in a recursive main loop until the
dialog either emits the response signal, or is destroyed. The default mode is
modal, which means the user cannot access any other window while
dialogRun is waiting for a response.
Progress bars are used to show the status of an ongoing operation.
progressBarNew :: IO ProgressBar
Though there is only one type, there are two distinct ways to use a progress bar. If it is known how much of the task has been completed, the fraction (between 0.0 and 1.0 inclusive) can be set with:
progressBarSetFraction :: ProgressBarClass self => self -> Double -> IO ()
This causes the progress bar to be filled in with the specified amount (between 0.0 and 1.0). To trace the progress this function should be called at regular times during the operation.
When it is not known how much of the operation has been completed, the bar can be moved back and forth with:
progressBarPulse :: ProgressBarClass self => self -> IO ()
This function must also be called repeatedly, to show that the activity is going on. There are several other functions to control the display of a progress bar, like orientation, additional text etc.; they are fairly trivial.
Application, however, is not trivial because progress bars are usually applied with timeouts or other such functions to give the illusion of multitasking. With concurrent Haskell you can also use threads and communication between threads.
In the following example we'll simulate an activity using
timeoutAdd, which runs a function repeatedly at the interval
specified, in milliseconds. The function is passed to
and must return a type of
IO Bool. When true the timeout is run
again, when false it stops. The priority of
priorityDefault of type
timeoutAdd :: IO Bool -> Int -> IO HandlerId
In the example we define the function
showPulse, which causes the
progress bar to pulse and always returns
IO True. The pulse step,
the amount which the indicator moves through the bar, is set to 1.0 with
The example is somewhat atypical of the use of a dialog, since we keep it to
show the progress after the user has pressed the apply button. To close the
application the dialog must be destroyed by destroying the window. The close
and cancel buttons don't work after apply has been selected. If selected,
instead of Apply, the first time, the application will close. This is
done by testing the response from
If the dialog widget is destroyed,
mainQuit is called. As
mentioned above, a
Dialog consists of a window and two boxes. The
boxes must be accessed through special functions, and the progress bar is
packed into the upper part using
dialogGetUpper. The buttons in a
dialog are visible by default, but the widgets in the upper part are not. A
Dialog is an instance of the
WindowClass, and so we
can set the title and/or default length and height if we want.
A trivial feature to watch out for: A widget can only be made visible if its
parent is visible. So, to show the progress bar, we use
widgetShowAll on the vertical box and not
on the progress bar.
import Graphics.UI.Gtk main :: IO () main = do initGUI dia <- dialogNew set dia [windowTitle := "Time Flies"] dialogAddButton dia stockApply ResponseApply dialogAddButton dia stockCancel ResponseCancel dialogAddButton dia stockClose ResponseClose pr <- progressBarNew progressBarSetPulseStep pr 1.0 upbox <- dialogGetUpper dia boxPackStart upbox pr PackGrow 10 widgetShowAll upbox answer <- dialogRun dia if answer == ResponseApply then do tmhandle <- timeoutAdd (showPulse pr) 500 return () else widgetDestroy dia onDestroy dia mainQuit mainGUI showPulse :: ProgressBar -> IO Bool showPulse b = do progressBarPulse b return True