<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
  <title></title>
</head>
<body bgcolor="#ffffff" text="#000000">
Michael Mossey wrote:<br>
<blockquote cite="mid:4AA96C0F.6070302@alumni.caltech.edu" type="cite">Duncan
Coutts wrote:
  <br>
  <blockquote type="cite">On Wed, 2009-09-09 at 18:29 -0700, Michael P
Mossey wrote:
    <br>
    <blockquote type="cite">I'm trying to learn qtHaskell. I realize
few people on this list know anything about qtHaskell, but I have a
question that probably relates to all GUIs as implemented in Haskell. I
just need a hint that could help me figure out the next step, which I
might be able to infer from the qtHaskell API.
      <br>
    </blockquote>
    <br>
Ultimately it's done by some kind of mutable state, either an IORef,
    <br>
MVar or a thread.
    <br>
  </blockquote>
</blockquote>
In wxHaskell, the 'simplest' way to code this looks something like the
following (literate Haskell)<br>
<br>
<span style="font-size: 11pt; font-family: &quot;Calibri&quot;,&quot;sans-serif&quot;;"><span
 style="color: rgb(31, 73, 125);"></span></span><tt>Structure
containing 'state' of all of the GUI objects<br>
<br>
&gt; data UIState = UIState { uiConnect&nbsp;&nbsp;&nbsp; :: Button ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiPort&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiUser&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiPasswd&nbsp;&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiSandbox&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiClients&nbsp;&nbsp;&nbsp; :: ComboBox ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiChanges&nbsp;&nbsp;&nbsp; :: SingleListBox ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiChangeInfo :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiOrigin&nbsp;&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiUpdate&nbsp;&nbsp;&nbsp;&nbsp; :: TextCtrl ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , uiFrame&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :: Frame ()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
&gt; uiState = unsafePerformIO $ newMVar (Nothing :: Maybe UIState)<br>
<br>
Ensure that we initialize exactly once...<br>
<br>
&gt; uiInitState bt pt us pw sb cl ci ch or up f =<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; takeMVar uiState &gt;&gt;= \st -&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; case st of<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nothing -&gt; let st' = UIState bt pt us pw sb cl ci ch or
up f in<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; putMVar uiState (Just st')<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Just _&nbsp; -&gt; return ()<br>
<br>
Get the mutable state.<br>
Note that in the error case we deliberately do not put the MVar back,
as a means<br>
to block all threads waiting on the MVar (as this would indicate a
general<br>
programming/threading issue to be identified).<br>
<br>
&gt; getMVarState mv txt =<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; takeMVar mv &gt;&gt;= \may_st -&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; case may_st of<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Nothing -&gt; error (txt ++ " is not available")<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Just st -&gt; putMVar mv may_st &gt;&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return st<br>
<br>
Fetch the UI state - this will fail fatally if we fetch before state is
initialized<br>
<br>
&gt; uiGetState = getMVarState uiState "UI state"</tt><br>
<br>
I don't have anything as neat to show you as Duncan's suggetion (I'd
also be interested to see a cleaner way to do it - this sort of code
always grates a little with me, although all of the major Haskell GUI
bindings seem to need a similar programming style.<br>
<br>
However, at the most basic 'trying it out' level, I suspect that
something very like this will work just as well for qtHaskell as it
does for wxHaskell.<br>
<blockquote cite="mid:4AA96C0F.6070302@alumni.caltech.edu" type="cite">
  <blockquote type="cite">On top of these you can layer nicer stuff
like a state monad (with a
    <br>
'runState' function that saves and restores from an IORef).
    <br>
    <br>
A personal favourite of mine is having the GUI event handler post data
    <br>
over a channel to a thread. That thread reads from the channel and
deals
    <br>
with the events. The state of the GUI app is then held as local
    <br>
parameters in that thread.
    <br>
    <br>
Doing this of course requires that the GUI lib you're using can cope
    <br>
with normal Haskell (forkIO) threads. This is possible with gtk2hs, I
    <br>
don't know about the others.
    <br>
  </blockquote>
</blockquote>
Regards<br>
Jeremy<br>
</body>
</html>