Haskell で wxFormBuilder を使う。

  • wxFormBuilderの使い方を学ぶには

wxRubyのこと (RubyでGUI)はwxRubyのサイトです。wxFormBuilderを使用して、「Hello World」「ラーメンタイマー」「時計」「双六ゲーム」「Twitterクライアント」を作り、XRCファイルも公開していますので、wxFormBuilderの学習には最適。「wxFormBuilderの使い方http://hackage.haskell.org/packages/archive/wxcore/0.12.1.7/doc/html/Graphics-UI-WXCore-WxcClassesMZ.html#g:94から丁寧に記述されています。ここから読み始めると良いでしょう。
最初から wxFormBuilder は使いこなせないので、公開されている XRC をwxFormBuilderに読み込ませ、部品の右・中央・左、上・中央・下、EXPANDなどのボタンを押して、何が変わるのか確認してみました。

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwindows.org/wxxrc" version="2.3.0.1">
	<object class="wxFrame" name="RamenFrame" subclass="RF1">
		<style>wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL</style>
		<size>500,300</size>
		<title>Ramen Timer</title>
		<aui_managed>0</aui_managed>
		<object class="wxPanel" name="panel">
			<style>wxTAB_TRAVERSAL</style>
			<object class="wxBoxSizer">
				<orient>wxVERTICAL</orient>
				<object class="sizeritem">
					<option>1</option>
					<flag>wxEXPAND</flag>
					<border>5</border>
					<object class="wxFlexGridSizer">
						<rows>1</rows>
						<cols>1</cols>
						<vgap>0</vgap>
						<hgap>0</hgap>
                                                <!-- サイズを変更しても中央になる  -->
						<growablecols>0</growablecols>
                                                <growablerows>0</growablerows>
						<object class="sizeritem">
							<option>1</option>
							<flag>wxALIGN_CENTER|wxALL</flag>
							<border>5</border>
							<object class="wxStaticText" name="staticText">
								<font>
									<size>55</size>
									<family>default</family>
									<style>normal</style>
									<weight>normal</weight>
									<underlined>0</underlined>
								</font>
								<label>00:00</label>
								<wrap>0</wrap>
							</object>
						</object>
					</object>
				</object>
				<object class="sizeritem">
					<option>0</option>
					<flag>wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND</flag>
					<border>5</border>
					<object class="wxButton" name="button0">
						<label>START!</label>
						<default>0</default>
					</object>
				</object>
			</object>
		</object>
	</object>
</resource>
module Main where

import Graphics.UI.WX                   (start)
import Graphics.UI.WX.Classes           (Textual(text))
import Graphics.UI.WX.Types             (objectNull)
import Graphics.UI.WX.Events            (on, command)
import Graphics.UI.WX.Attributes        (Prop((:=)), set)
import Graphics.UI.WX.Timer             (timer)
import Graphics.UI.WXCore.WxcDefs       (wxXRC_USE_LOCALE)
import Graphics.UI.WXCore.WxcClassTypes (Timer)
import Graphics.UI.WXCore.WxcClassesMZ  (xmlResourceCreateFromFile, xmlResourceLoadFrame, xmlResourceGetPanel,
                                         xmlResourceGetStaticText,  xmlResourceGetButton, windowShow, timerStart)

import Data.IORef                       (IORef, newIORef, readIORef, writeIORef)
import Text.Printf                      (printf)
import Control.Monad                    (when)

data Ramen = Ramen{counter::Int, valid::Bool} deriving (Show)


main :: IO ()
main = start $ do
    newCnt <- newIORef (Ramen 0 False)
    res    <- xmlResourceCreateFromFile "ramen.xrc" wxXRC_USE_LOCALE
    form   <- xmlResourceLoadFrame res objectNull "RamenFrame"
    panel  <- xmlResourceGetPanel      form  "panel"
    txt    <- xmlResourceGetStaticText panel "staticText"
    button <- xmlResourceGetButton     panel "button0"
    tm     <- timer panel [on command := nextTimer txt newCnt]
    set button [on command := pushButton newCnt tm]
    windowShow form

nextTimer :: Textual w => w -> IORef Ramen -> IO ()
nextTimer txt ramenCNT = do
    (Ramen sec flag) <- readIORef ramenCNT
    when (flag && (sec >= 0 )) 
         (set txt [text := printf "%02d:%02d" (sec `div` 60) (sec `rem` 60)] >>
          writeIORef ramenCNT (Ramen (sec-1) flag))

pushButton :: IORef Ramen -> Timer a -> IO ()
pushButton ioCnt tm = do 
  b <- timerStart tm 1000 False
  writeIORef ioCnt (Ramen 180 True)
readFile "./name.xrc" >>= \f ->writeFile "./new.xrc" $ unlines $ 
  map (foldl  (\acc c -> acc++if c =='\t' then "    " else [c]) "") $ lines f
readFile "./file" >>= \f ->putStrLn $ Data.List.foldl' (\a c -> a++if c =='\t' then " " else [c]) "") f