Haskell/GUI

Haskell has at least four toolkits for programming a graphical interface:
 * wxHaskell - provides a Haskell interface to the cross-platform wxWidgets toolkit which supports Windows, OS X, and Gtk+ on GNU/Linux, among others.
 * Gtk2Hs - provides a Haskell interface to the GTK+ library
 * hoc (documentation at sourceforge) - provides a Haskell to Objective-C binding which allows users to access to the Cocoa library on MacOS X
 * qtHaskell - provides a set of Haskell bindings for the Qt Widget Library

In this tutorial, we will focus on the wxHaskell toolkit.

Getting and running wxHaskell
To install wxHaskell, look for your version of instructions at: GNU/Linux Mac Windows

or the wxHaskell download page and follow the installation instructions provided on the wxHaskell download page. Don't forget to register wxHaskell with GHC, or else it won't run (automatically registered with Cabal). To compile source.hs (which happens to use wxHaskell code), open a command line and type:

ghc -package wx source.hs -o bin

Code for GHCi is similar:

ghci -package wx

You can then load the files from within the GHCi interface. To test if everything works, go to $wxHaskellDir/samples/wx ($wxHaskellDir is the directory where you installed it) and load (or compile) HelloWorld.hs. It should show a window with title "Hello World!", a menu bar with File and About, and a status bar at the bottom, that says "Welcome to wxHaskell".

If it doesn't work, you might try to copy the contents of the $wxHaskellDir/lib directory to the ghc install directory.

Shortcut for Debian and Ubuntu
If your operating system is Debian or Ubuntu, you can simply run these commands from the terminal:

sudo apt-get install g++ sudo apt-get install libglu-dev sudo apt-get install libwxgtk2.8-dev

Hello World
Here's the basic Haskell "Hello World" program:

It will compile just fine, but how do we actually do GUI work with this? First, you must import the wxHaskell library. has some more stuff, but we won't need that now.

To start a GUI, use. In this case,  is the name of a function which we'll use to build the interface. It must have an IO type. Let's see what we have:

To make a frame, we use  which has the type. It takes a list of "frame properties" and returns the corresponding frame. We'll look deeper into properties later, but a property is typically a combination of an attribute and a value. What we're interested in now is the title. This is in the  attribute and has type. The most important thing here, is that it's a  attribute. Here's how we code it:

The operator  takes an attribute and a value and combines both into a property. Note that  returns an. The  function has the type. You can change the type of  to , but it might be better just to add. Now we have our own GUI consisting of a frame with title "Hello World!". Its source:

The result should look like the screenshot. (It might look slightly different on Linux or MacOS X, on which wxhaskell also runs)

A text label
A simple frame doesn't do much. In this section, we're going to add some more elements. Let's start simple with a label. wxHaskell has a, but that's a layout thing. We won't be doing layout until next section. What we're looking for is a. It's in. The  function takes a   as argument along with a list of properties. Do we have a window? Yup! Look at. There, we see that a  is merely a type-synonym of a special sort of window. We'll change the code in  so it looks like this:



Again,  is an attribute of a   object, so this works. Try it!

A button
Now for a little more interaction. A button. We're not going to add functionality to it until the section about events, but already something visible will happen when you click on it.

A  is a control, just like. Look it up in.

Again, we need a window and a list of properties. We'll use the frame again. is also an attribute of a button:



Load it into GHCi (or compile it with GHC) and... hey!? What's that? The button's been covered up by the label! We're going to fix that next.

Layout
The reason that the label and the button overlap, is that we haven't set a layout for our frame yet. Layouts are created using the functions found in the documentation of. Note that you don't have to import  to use layouts.

The documentation says we can turn a member of the widget class into a layout by using the  function. Also, windows are a member of the widget class. But, wait a minute... we only have one window, and that's the frame! Nope... we have more, look at  and click on any occurrence of the word Control. You'll be taken to, and it is there we see that a Control is also a type synonym of a special type of window. We'll need to change the code a bit, but here it is.

Now we can use  and   to create a layout of the staticText and the button. is an attribute of the frame, so we'll set it here:



The  function will be covered in the section below about attributes. Try the code, what's wrong? This only displays the staticText, not the button. We need a way to combine the two. We will use layout combinators for that. and  look nice. They take an integer and a list of layouts. We can easily make a list of layouts of the button and the staticText. The integer is the spacing between the elements of the list. Let's try something:



Play around with the integer and see what happens. Also, change  into. Try to change the order of the elements in the list to get a feeling of how it works. For fun, try to add  several more times in the list. What happens?

Here are a few exercises to spark your imagination. Remember to use the documentation!

After having completed the exercises, the end result should look like this: You could have used different spacing for  and   or have the options of the radiobox displayed horizontally.

Attributes
After all this, you might be wondering: "Where did that  function suddenly come from?" and "How would I know if  is an attribute of something?". Both answers lie in the attribute system of wxHaskell.

Setting and modifying attributes
In a wxHaskell program, you can set the properties of the widgets in two ways:
 * 1) during creation:
 * 2) using the   function:

The  function takes two arguments: something of type   along with properties of. In wxHaskell, these will be the widgets and the properties of these widgets. Some properties can only be set during creation, such as the  of a , but you can set most others in any IO-function in your program — as long as you have a reference to it (the   in  ).

Apart from setting properties, you can also get them. This is done with the  function. Here's a silly example:

Look at the type signature of. It's. is a  attribute, so we have an   which we can bind to. The last line edits the text of the frame. Yep, destructive updates are possible in wxHaskell. We can overwrite the properties using  anytime with. This inspires us to write a modify function:

First it gets the value, then it sets it again after applying the function. Surely we're not the first one to think of that...

Look at this operator:. You can use it in  because it takes an attribute and a function. The result is a property in which the original value is modified by the function. That means we can write:

This is a great place to use anonymous functions with the lambda-notation.

There are two more operators we can use to set or modify properties:  and. They do almost the same as  and   except a function of type   is expected, where   is the widget type, and   is the original "value" type (  in case of   and   in case of  ). We won't be using them now, as we've only encountered attributes of non-IO types, and the widget needed in the function is generally only useful in IO-blocks.

How to find attributes
Now the second question. Where do we go to determine that  is an attribute of all those things? Go to the documentation…

Let's see what attributes a button has: Go to. Click the link that says "Button". You'll see that a  is a type synonym of a special kind of , and a list of functions that can be used to create a button. After each function, there's a list of "Instances". For the normal  function, we see Commanding -- Textual, Literate, Dimensions, Colored, Visible, Child, Able, Tipped, Identity, Styled, Reactive, Paint. That's the list of classes of which a button is an instance. Read through the ../Classes and types/ chapter. It means that there are some class-specific functions available for the button. , for example, adds the  and   functions. If a widget is an instance of the  class, it means that it has a   attribute!

Note that while  hasn't got a list of instances, it's still a , and that's a synonym for some kind of. When looking at the  class, it says that   is an instance of it. That's an error on the side of the documentation!

Let's take a look at the attributes of a frame. They can be found in. Another error in the documentation here: It says  instantiates. This was true in an older version of wxHaskell. It should say. Apart from that, we have,  ,  ,  ,   and a few more. We're already seen  and. Anything that is an instance of  has a   attribute.

adds (among others) the  attribute. It's an attribute of the  type, which can be made with. Please note that the  attribute can also change the size. If you want to use  you should set it after the.

adds the  and   attributes.

adds the Boolean  attribute. This can be used to enable or disable certain form elements, which is often displayed as a greyed-out option.

There are lots of other attributes, read through the documentation for each class.

Events
There are a few classes that deserve special attention. They are the  class and the   class. As you can see in the documentation of these classes, they don't add attributes (of the form ), but events. The  class adds the   event. We'll use a button to demonstrate event handling.

Here's a simple GUI with a button and a staticText:



We want to change the staticText when you press the button. We'll need the  function:

The type of :. is of type, so we need an IO-function. This function is called the Event handler. Here's what we get:

Insert text about event filters here