Gtk2Hs Tutorial

<<< Previous


Next >>>

Dialogs, Stock Items and Progress Bars

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.

The 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 dialogAddActionWidget.

The String in 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 as standard IconSets. You can define your own, but many useful ones are listed in the Graphics.UI.Gtk.General.StockItems module. 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 ResponseUser Int .

Whenever a dialog button is pressed, its response is passed to the calling application through dialogRun. According to the Gtk2Hs API documentation 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 timeoutAdd and must return a type of IO Bool. When true the timeout is run again, when false it stops. The priority of timeoutAdd is priorityDefault of type Priority.

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 progressBarSetPulseStep.


GtkChap10

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 dialogRun.

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 widgetShow 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

<<< Previous

Home

Next >>>

Arrows and Tooltips


Text Entries and Satusbars