Definitions in Tk.hs

The Tk environment
Widgets and containers
Images and bitmaps
Window widgets
Record types subtyped by window widgets
Canvas widgets
Packing and layout

The Tk environment

Access to all the features of Tk is given to the programmer through the TkEnv structure. A procedure
main :: TkEnv -> Cmd ()
can be executed by typing main to the prompt in the interactive system ohugs or by running rohugs with the file name as command line argument.
struct Tk =
    window    :: [WindowOpt]   -> Request Window
    bitmap    :: [BitmapOpt]   -> Request ConfBitmap
    photo     :: [PhotoOpt]    -> Request Photo
    delay     :: Int -> (String -> Cmd ()) -> Request String
    periodic  :: Int -> Cmd () -> Request Runnable
    bell      :: Action 

struct TkEnv < Tk, StdEnv

struct Runnable = 
   start :: Action
   stop  :: Action
The TkEnv structure has six methods:

Widgets and containers

GUIs are built up from Widgets, which are objects having a visual appearance on screen.

Many of the structures in Tk have methods with a signature of the form

  aWidget :: [AWidgetOpt] -> Request AWidget
A call of this method creates an instance of AWidget; as argument to the call the instance can be configured with a list of widget-specific options. The widget creating methods appear in a hierarchy:
struct Widget = 
    ident   :: String
    destroy :: Action
    exists  :: Request Bool 
    focus, raise, lower :: Action
    bind    :: [Event] -> Action

struct Configurable a = 
    set     :: [a] -> Action

struct ConfWidget a < Widget, Configurable a

struct Container = 
    pack      :: Packable -> Action
    unpackAll :: Action
struct WWidget a < ConfWidget a, Packable
A Widget has a unique identity, can be destroyed (and consequently one can check whether it still exists), can take keyboard focus, can be raised and lowered in the stacking order on screen. Finally and most importantly, one can bind callback procedures to a widget as response to user actions, represented as Events.

ConfWidgets are also Configurable, ie one can set their options not only at creation time but at any time. All Widgets in Tk are actually ConfWidgets; the reason for the design is that there are also other Configurable objects, such as ConfBitmap and Photos.

Some Widgets, notably Windows and Frames, are also Containers, ie they can be packed with a Packable object. All widgets created by methods of a Window are Packable; to capture this we introduce the type WWidget. In addition there are layout functions to combine packables horizontally and vertically, allowing several widgets to be flexibly packed in a container.


A Window is a toplevel window. As such it is a subtype of both a BasicWindow, which provides widget-creating methods, and ManagedWindow, which provides methods to interact with the window manager. Furthermore, a BasicWindow is also a Widget and a Container.
struct Window < BasicWindow WindowOpt, ManagedWindow 

data WindowOpt > Background, BorderWidth, Cursor, Relief, Title

struct BasicWindow a < ConfWidget a, Container =
    button      :: [ButtonOpt]      -> Request Button
    canvas      :: [CanvasOpt]      -> Request Canvas
    checkButton :: [CheckButtonOpt] -> Request CheckButton
    entry       :: [EntryOpt]       -> Request Entry
    frame       :: [FrameOpt]       -> Request Frame
    label       :: [LabelOpt]       -> Request Label
    listBox     :: [ListBoxOpt]     -> Request ListBox
    menuButton  :: [MenuButtonOpt]  -> Request MenuButton
    radioButton :: [RadioButtonOpt] -> Request RadioButton
    scrollBar   :: [ScrollBarOpt]   -> Request ScrollBar
    slider      :: [SliderOpt]      -> Request Slider
    textEditor  :: [TextEditorOpt]  -> Request TextEditor
struct ManagedWindow = 
    getGeometry :: Request (Pos,Pos)   -- size,position
    setSize     :: Pos -> Action
    setPosition :: Pos -> Action
    iconify     :: Action
    deiconify   :: Action

type Pos = (Int,Int)
The ManagedWindow methods are hopefully self-explanatory. All the BasicWindow methods produce WWidgets.

Images and bitmaps

struct Image =
  imageName :: String

struct Bitmap < Image

struct ConfBitmap < Bitmap, Configurable BitmapOpt

struct PredefBitmap < Bitmap

struct Photo < Image, Configurable PhotoOpt =
  blank    :: Action
  putPixel :: Pos -> Color -> Action
  getPixel :: Pos -> Request Color
  copyFrom :: Photo -> Action  -- to be refined
  saveAs   :: FilePath -> Action 

data PhotoOpt  > Width, Height, File
data BitmapOpt > Background, Foreground, File, BitmapData

stop, hourglass, info, questhead, question, warning  :: PredefBitmap
An Image is either a Bitmap or a Photo. There are a small number of predefined PreDefBitmaps, enumerated above; these are typically used in dialogs. General bitmaps can be created from either a file containing a bitmap in standard X bitmap format (using the File option) or a string, also in X bitmap format (using the BitmapData option). The general bitmaps can also be configured with a foreground and background color.

Photos represent full-color images, which are created from GIF or PPM files, using the File option. There are also methods to get and set the color of individual pixels. It is, however, infeasible to create or process images significantly using these methods. Presently, image processing using this module is thus not possible; the use of images is limited to pure presentation of externally generated images.

Window widgets

struct Button < WWidget ButtonOpt, Invokable =
    flash   :: Action

struct Canvas < ScrollWidget CanvasOpt, Scannable Pos = 
   oval      :: Pos -> Pos -> [OvalOpt]      -> Request Oval
   arc       :: Pos -> Pos -> [ArcOpt]       -> Request Arc
   rectangle :: Pos -> Pos -> [RectangleOpt] -> Request Rectangle
   line      :: [Pos]      -> [LineOpt]      -> Request Line
   polygon   :: [Pos]      -> [PolygonOpt]   -> Request Polygon
   text      :: Pos        -> [CTextOpt]     -> Request CText
   image     :: Pos        -> [CImageOpt]    -> Request CImage
   cwindow   :: Pos        -> [CWindowOpt]   -> Request CWindow
   clear     :: Action
   save      :: FilePath -> Action

struct CheckButton < Button = 
   toggle   :: Action
   checked  :: Request Bool

struct Entry < ScrollWidget EntryOpt, Cell String, Scannable Int =
   cursorPos :: Request Int

struct Frame <  WWidget FrameOpt, Container

struct Label < WWidget LabelOpt

struct ListBox < ScrollWidget ListBoxOpt, LineEditable, Cell [Int],  
                 Scannable Pos =
  view :: Int -> Action

struct MenuButton < WWidget MenuButtonOpt =
   menu :: [MenuOpt] -> Request Menu

struct RadioButton < Button = 
   select   :: Action
   deselect :: Action
struct ScrollBar < WWidget ScrollBarOpt = 
   attach :: ScrollWidget Background -> Dir -> Action

struct Slider < WWidget SliderOpt, Cell Int

struct TextEditor < ScrollWidget TextEditorOpt, LineEditable, Scannable Pos

data BasicOpt       > Background, BorderWidth, Cursor, Relief
data BasicWOpt      > BasicOpt, Width
data DimOpt         > Height, Width
data StdOpt         > BasicWOpt, DimOpt
data FontOpt        > Font, Foreground, Anchor, Justify
data PadOpt         > Padx, Pady

data ButtonOpt      > MenuButtonOpt, Command
data CanvasOpt      > StdOpt, ScrollRegion 
data CheckButtonOpt > ButtonOpt, Indicatoron, SelectColor
data EntryOpt       > BasicWOpt, Justify, Font, Foreground, Enabled
type FrameOpt       = StdOpt
data LabelOpt       > StdOpt, FontOpt, PadOpt, Img, Btmp, Underline, Text
data ListBoxOpt     > StdOpt, Font, Foreground, SelectMode
data MenuButtonOpt  > LabelOpt, Enabled
type RadioButtonOpt = CheckButtonOpt
type ScrollBarOpt   = StdOpt
data SliderOpt      > BasicWOpt, From, To, Orientation, Length, 
                      Font, Foreground, CmdInt, Enabled
data TextEditorOpt  > StdOpt, Font, Foreground, PadOpt, Wrap, Enabled
The widgets that can be created from a BasicWindow and packed in a Container are

Record types subtyped by window widgets

The following record types are subtyped by some of the window widgets to give added behavior.
struct Cell a =
  setValue :: a -> Action
  getValue :: Request a

struct LineEditable =
  lines       :: Request Int
  getLine     :: Int -> Request String
  deleteLine  :: Int -> Action
  insertLines :: Int -> [String] -> Action

struct Invokable = 
    invoke  :: Action

struct Scannable a =
    mark :: a -> Action
    drag :: a -> Action

struct ScrollWidget a < WWidget a 
A Cell a is an objects that maintains an value of type a. This can typically be manipulated by the user in a widget-specific way; the Cell type gives a unified way of program interaction with this value.

A LineEditable widget supports a few operations for setting and accessing content on a line basis.

An Invokable has a widget-specific way to be invoked by the user; the method invoke provides a uniform way for program invokation.

Finally, a Scannable widget provides hook methods to implement rapid scanning over the widget. All the scannable widgets implement this by default using the middle button; moving the mouse with this button pressed over the widget scans over the widget.

Canvas widgets

A canvas provides methods to create canvas widgets, which are configurable widgets that are positioned in absolute coordinates (thus a canvas is not packed) ant that have additional methods for setting and getting the present position in canvas coordinates (setCoords, getCoords) and for relative movement (move). Note that the length of the coordinate lists are different for different widgets.

Canvas coordinates have their origin in the upper left corner and pixels as unit.

struct CWidget a < ConfWidget a = 
   getCoords :: Request [Pos]
   setCoords :: [Pos] -> Action
   move      :: Pos -> Action

struct Arc       < CWidget ArcOpt
struct CImage    < CWidget CImageOpt
struct CText     < CWidget CTextOpt
struct CWindow   < CWidget WindowOpt, BasicWindow WindowOpt
struct Line      < CWidget LineOpt
struct Oval      < CWidget OvalOpt
struct Polygon   < CWidget PolygonOpt
struct Rectangle < CWidget RectangleOpt

data CBasicOpt      > Fill, Width, Stipple

data ArcOpt         > OvalOpt, ArcStyle, Angles
data CImageOpt      > Anchor, Img, Btmp
data CTextOpt       > Font, Justify, Text, Anchor, Fill
data CWindowOpt     > DimOpt, Anchor
data LineOpt        > CBasicOpt, Arrow, Smooth, CapStyle, JoinStyle
data OvalOpt        > CBasicOpt, Outline
data PolygonOpt     > OvalOpt, Smooth
data RectangleOpt   > OvalOpt
The canvas widgets are


Menus are accessed through a MenuButton, which is a window widget with the menu name.
struct Menu < ConfWidget MenuOpt =
    mButton :: [MButtonOpt] -> Request MButton
    cascade :: [MButtonOpt] -> Request Menu

struct MButton < Configurable MButtonOpt, Invokable

data MenuOpt        > WindowOpt, Enabled
data MButtonOpt     > StdOpt, FontOpt, PadOpt, Img, Btmp, Underline, 
                      CLabel, Enabled, Command
With a menu one can create MButton (button-like entries with text or image and an associated Command) option) and cascaded submenus. Simple use of menus in a menubar (without cascades) is captured in the function menubar in TkUtil.

For popup menus and option menus, see Tix.


User actions are captured by the hierarhy of Event data types. Each such type also contains a callback procedure, which is a command with event-specific parameters. Values of Eventtypes are used as arguments to widgets' bind method.
data ButtonPress = ButtonPress Int (Pos -> Cmd ())
                 | AnyButtonPress  (Int -> Pos -> Cmd ())

data MouseEvent > ButtonPress = 
           ButtonRelease Int (Pos -> Cmd ()) 
         | AnyButtonRelease (Int -> Pos -> Cmd ())
         | Motion Int (Pos -> Cmd ())
         | AnyMotion  (Pos -> Cmd ())
         | Double ButtonPress
         | Triple ButtonPress

data WindowEvent = Enter (Cmd ())
                 | Leave (Cmd ())
                 | Configure (Pos -> Cmd ()) 

data SimpleKeyEvent = KeyPress String (Cmd ())
                    | KeyRelease String (Cmd ())
                    | AnyKeyPress (String -> Cmd ())

data KeyEvent > SimpleKeyEvent = Mod [Modifier] SimpleKeyEvent

data Modifier = Alt | Control  | Lock | Meta | Shift deriving Show

data DestroyEvent = Destroy (Cmd ())

data Event > MouseEvent, KeyEvent, WindowEvent, DestroyEvent
The supported event types are the following: Note that many widgets have several default bindings to various user actions.


Widget option types are formed by using subtyping (or, rather, supertyping), i.e. the available options for a widget is the supertype formed by including the relevant individual options.

Auxiliary types

The following types are auxiliary to some of the option types below.
data None       = None
data AnchorType = NW | N | NE | W | C | E | SW | S | SE 
data ReliefType = Raised | Sunken | Flat | Ridge | Solid | Groove
data VertSide   = Top | Bottom 
data WrapType   = NoWrap | CharWrap | WordWrap
data SelectType = Single | Multiple
data Align      = LeftAlign | CenterAlign | RightAlign
data Round      = Round
data ArcStyleType = Pie | Chord | Perimeter
data CapStyleType  > Round = Butt | Proj 
data JoinStyleType > Round = Bevel | Miter 
data ArrowType     > None = First | Last | Both

Individual options

data Anchor = Anchor AnchorType Specifies positioning detail for text in some text-based widgets and for the widget as a whole in some canvas widgets.

data Angles = Angles Pos Specifies extent of an Arc.

data ArcStyle = ArcStyle ArcStyleType Specifies form of an Arc.

data Arrow = Arrow ArrowType Specifies in which end(s) a Line should have arrowheads.

data Background = Background Color Specifies a background color for the widget.

data BitmapData = BitmapData String Describes a bitmap as a string in X bitmap format.

data BorderWidth = BorderWidth Int Specifies border width in pixels (normally used together with the Relief option to describe the border).

data Btmp = Btmp PredefBitmap Used to describe (only) the predefined bitmaps to display in a label or button (other bitmaps are prescribed using the Img option).

data CapStyle = CapStyle CapStyleType Specifies cap style for Line widgets.

data CLabel = CLabel String Describes the text on an MButton. (This is unfortunate; for technical reasons the Text option cannot be used for MButtons).

data CmdInt = CmdInt (Int -> Cmd ()) Specifies a callback procedure for sliders (and other widgets in Tix).

data Command = Command (Cmd ()) Specifies a callback procedure for buttons.

data Cursor = Cursor String Specifies the cursor to be used in the widget; the string should be a valid name for an X cursor (e.g. "crosshair","arrow"); a listing of valid cursor names is in the X11 header file cursorfont.h.

data Enabled = Enabled Bool Specifies whether user actions should be enabled (for e.g. buttons, mbuttons, entries, texteditors).

data File = File FilePath Specifies a file name from where to read a bitmap or image.

data Fill = Fill Color Specifies a color for fillable canvas widgets.

data Font = Font String Specifies a font. Valid strings are family size styles, where family includes at least courier, helvetica and times, size is a positive integer and the optional styles includesnormal (default), bold, italic, underline and overstrike. Also full X font names such as "-adobe-courier-medium-o-normal--12-120-75-75-m-70-iso8859-1" are accepted.

data Foreground = Foreground Color Specifies a foreground color for the widget.

data From = From Int Specifies the minimum value for sliders.

data Height = Height Int Specifies the widget height; in lines for font-based widgets and in pixels for others.

data Img = Img Image Specifies an image to be displayed in a label, button or CImage.

data Indicatoron = Indicatoron Bool Specifies whether the indicator should be displayed for checkbuttons and radiobuttons.

data JoinStyle = JoinStyle JoinStyleType Specifies join style for LInes.

data Justify = Justify Align Specifies multi-line text justification.

data Length = Length Int Specifies the length (in pixels) of a slider.

data Orientation = Orientation Dir Specifies orientation of a slider.

data Outline = Outline Color Specifies outline color for fillable canvas widgets.

data Padx = Padx Int Specifies requested external padding (i.e. intra-widget space) in the X direction for a widget (in pixels).

data Pady = Pady Int Specifies requested external padding (i.e. intra-widget space) in the Y direction for a widget (in pixels).

data Relief = Relief ReliefType Specifies border type.

data ScrollRegion = ScrollRegion (Int,Int) (Int,Int) Specifies the coordinates of two opposite corners in a Canvas when attaching scrollbars.

data SelectMode = SelectMode SelectType Specifies for a listbox whether multiple selections are accepted.

data SelectColor = SelectColor (Maybe Color) Specifies the color marking selection in the indicator of a check- or radiobutton.

data Smooth = Smooth Bool Indicates spline approximation for lines and polygons.

data Stipple = Stipple String Specifies a file containing a bitmap pattern to be used for stippling when filling a canvas widget.

data Text = Text String Specifies text on a label or button.

data Title = Title String Specifies a window title to be used by the window manager as title.

data To = To Int Specifies maximum value for a slider.

data Underline = Underline Int Specifies the index of a character in the widget text to underlined.

data Width = Width Int Specifies the width of a widget; in characters for font-based widgets and in pixels for others.

data Wrap = Wrap WrapType Specifies wrap mode for TextEditors.

Packing and layout

[This documentation is inaccurate!] Normally, programmers don't need to bother about how packing and layout is carried out; it is sufficient to create widgets in windows and frames, and then specify their layout with the pack command.

In the event that a widget that was created in a window needs to be packed inside a subframe, one has to be more explicit. Widgets are laid out in a Container by using the container's pack method. In simple use, widgets created in a window win are packed bu call of win.pack. However, one can also pack these widget in a frame created by calls to win.frame, thus producing Packables or WWidgets.

Packing a window also causes the window to be displayed on screen.

The argument to pack is a Packable object. All WWidgets are Packable; in addition one can combine Packables using the functions

row :: [Packable] -> Packable
col :: [Packable] -> Packable

infix 6 ^^^ 
infix 7 <<< 

(^^^), (<<<) :: Packable -> Packable -> Packable
p1 <<< p2 = row [p1,p2]
p1 ^^^ p2 = col [p1,p2]
For simple layout effects these combinators are sufficient. However, for fine-tunig the layout further concepts are needed.

Every window widget has a preferred size (width and height), which is determined either by the size of its content (text, image, etc) or by explicit setting of Width and Height options. It is then easy to determine a preferred size for a row (column) of widgets; just add their widths (heights) and take the maximum of their heights (widths). Packing a container c using the call c.pack p for some packable p causes the container's size to be set to the preferred size of p (thus containersdo not support the Width and Height options); then sizes are assigned top-down to individual packables. This may lead to a packable being assigned a size that is larger than it prefers (since all elements in a row do not have the same preferred height, etc). Layout finetuning is concerned with how this extra size is utilized. By default, all packables adapt to make use of the extra space. This means that e.g. in a window with a button below a canvas, the button will accept to take on the full width of the canvas, even though it likely prefers a much smaller width. This behaviour can be changed by using the functions

data Stretch > None = XFill | YFill | XYFill

type Expandable = Bool

fill :: Stretch -> Expandable -> Packable -> Packable

rigid, fillX, fillY :: Packable -> Packable
rigid = fill None False 
fillX = fill XFill False 
fillY = fill YFill False 
Each packable has a stretch property, deciding how it will accept to stretch to fill out extra space in no direction (None), only in the x direction (XFill), only in the y direction (YFill), or in both directions (XYFill). The default is XYFill.

A packable may or may not be expandable; an expandable packable accepts to be assigned extra width as a member of a row and extra height as a member of a column. If a row has been assigned extra width (this can happen!), this is shared equally among its expandable elements; if no element is expandable, unused space is left in the right end of the row; similarly for cols. The default is to be expandable.

A rigid packable is determined to stick to its preferred size; a rigid (row of) button(s) below a canvas will not expand, regardless of how the window is resized. A fillX packable will expand in the x direction, but not in the y direction; this is likely to be the preferred behaviour for a menubar or horizontal scrollbar.


The data type of colors used in Tk is
data Color = RGB Int Int Int 
           deriving (Eq)

black  = RGB 0 0 0
white  = RGB 255 255 255
red    = RGB 255 0 0
green  = RGB 0 255 0
blue   = RGB 0 0 255
yellow = RGB 255 255 0

rgb :: Int -> Int -> Int -> Color
rgb r g b = RGB r g b