Virheen sattuessa näytetään varoitusraita, jonka on tarkoitus olla visuaalisesti riittävän häiritsevä kirjoittamisen pysäyttämiseksi. Alkuperäisessä ohjelmassa käytin Gimpillä maalattua mustakeltaista PNG-kuvaa
Image-komponentissa. Tällä kertaa annamme ohjelman piirtää raidat
DrawingArea-komponentille. Olen tähän valinnut punaiset ja siniset raidat, mutta värejä on helppo muuttaa koodista.
Lopputulos tulee näyttämään jotakuinkin tältä:
Luonnollinen paikka piirtorutiinin käynnistämiseen on funktiossa
whenBufferChanged. Tieto virheestä sisältyy
gsRef-viitteeseen, joten selviämme komennolla
widgetQueueDraw canvas, missä
canvas on viittaus
DrawingArea-komponenttiin. Se luodaan funktiossa
createGUI:
canvas <- drawingAreaNew
widgetSetSizeRequest canvas 300 40
onExpose canvas (
drawCanvas gsRef canvas)
boxPackStart outerVBox canvas PackGrow 0
Nyt siis komento
widgetQueueDraw aiheuttaa funktion
onExpose kutsun, joka on jaettu kahteen osaan, riippuen siitä piirretäänkö tyhjä vai näkyvä komponentti. Tyhjän komponentin piirtäminen on triviaali toimenpide, joka perustuu järjestelmän taipumukseen päivittää komponentit alkuperäisasetuksiin.
drawCanvas gsRef canvas _evt = do
gs <- readIORef gsRef
if (oldStatus gs) /= Error
then drawCanvas0 canvas _evt
else drawCanvas1 canvas _evt
drawCanvas0 canvas _evt = do
return True
drawCanvas1 canvas _evt = do
(w,h) <- widgetGetSize canvas
dw <- widgetGetDrawWindow canvas
gc1 <- gcNew dw
gc2 <- gcNew dw
gcSetValues gc1 newGCValues { foreground = red }
gcSetValues gc2 newGCValues { foreground = blue }
let c = h
r = 15
limit0 = -1 - c `div` r
limit1 = (w+c) `div` r + 1
mapM
( \(points,gc) -> drawPolygon dw gc True points)
[([(x*r+c,0),(x*r,h),((x+1)*r,h),((x+1)*r+c,0)],
if x `mod` 2 == 0 then gc1 else gc2) | x <- [limit0..limit1]]
return True
Piirtorutiinit, kuten tavallisesti, menevät minulla lukukelvottomaksi sekasotkuksi, mutta ajatus on siinä, että vuorotellaan grafiikkakonteksteja
gc1 ja
gc2, jotka tässä ovat punainen ja sininen kynä. Kukin raita on monikulmio (
drawPolygon), jonka alakoordinaattien x-arvot poikkeavat vakion
c verran yläkoordinaateista, aiheuttaen monikulmion kallistumisen. Vakio
r määrää yhden raidan leveyden pikseleinä.
Punainen ja sininen väri ovat
red ja
blue, jotka olen määritellyt seuraavasti:
color r g b = Color (r*256) (g*256) (b*256)
green = color 115 210 22
red = color 255 51 102
blue = color 51 102 255
yellow = color 252 233 79
Kun erilaisia värejä on nyt koko joukko määriteltynä, voimme tehdä niiden avulla vaikkapa pienen väriefektin Tietoja-valikon tulostietodialogiin. Se värittää tekstirivin vihreäksi kun CSV-muotoinen tulosluettelo tallennetaan.
Label-komponentti ei sisällä tietoa taustaväristä, joten upotamme sen
EventBox-komponenttiin, ja muutamme sen taustavärin vihreäksi:
onSaveClicked fname text label = do
writeFile fname text
labelSetText label ("Kirjoitettiin " ++ fname)
parent <- widgetGetParent label
case parent of
Nothing -> print "No parent"
Just parent -> widgetModifyBg parent StateNormal (green)
return ()
Yksi tärkeä muutos ohjelmaan on varautua virheisiin tekstitiedostoa luettaessa, esimerkiksi tiedoston puuttumiseen aloitettaessa. Tämän vuoksi sisällytämme
readFile-käskyn
try-rakenteeseen, samaan tapaan kuin aikaisemmin tuloksia ja asetuksia luettaessa. Tiedoston luvun epäonnistuessa näytämme yksinkertaisen virhedialogin ja palautamme epämääräisen joukon valmiiksi määriteltyjä latinankielisiä sananlaskuja (ei kuvassa).
tryReadFile fname = do
opResult <- try ( do
text <- readFile fname
return text)
case opResult of
Left excp -> return (
(unlines proverbs),
Just ("Tiedostoa " ++ fname ++ " ei voitu lukea."))
Right text -> return (text, Nothing)
showErrorDialog txt gsRef = do
gs <- readIORef gsRef
let parent = Just (gWindow (g gs))
dialog <- messageDialogNew parent [] MessageWarning ButtonsOk "Avaa tiedosto"
messageDialogSetSecondaryText dialog txt
dialogRun dialog
widgetDestroy dialog
getLines gsRef = do
gs <- readIORef gsRef
(originalText, err) <- tryReadFile (textfile (s gs))
...
case err of
Nothing -> return ()
Just txt -> showErrorDialog txt gsRef
Ohjelmakoodi kokonaisuudessaan:
http://personal.inet.fi/koti/jhii/varoitusraidat.hsTässä vielä hieman ohjeita ohjelman kääntämiseksi GHC-kääntäjällä.
Tulkattavassa muodossa ohjelma käynnistettiin komennolla
runhaskell varoitusraidat.hs
Nimetään ensin lähdetiedosto hieman asiallisemmin:
mv varoitusraidat.hs hatupist.hs
Yksinkertainen käännösprosessi tuottaa valtaisan 18 megatavun tiedoston:
$ ghc hatupist.hs
[1 of 1] Compiling Main ( hatupist.hs, hatupist.o )
Linking hatupist ...
$ ll hatupist
-rwxrwxr-x. 17996645 29.7. 22:09 hatupist
Tässä kaikki GTK-kirjastot on linkitettynä ohjelmaan. Voimme jättää ne pois kääntämällä ohjelma komennolla
ghc -O2 -dynamic (Valitsin on O-kirjain, ei nolla), jolloin päädymme alle neljäsataakiloiseen ohjelmaan.
$ ghc -O2 -dynamic hatupist.hs
[1 of 1] Compiling Main ( hatupist.hs, hatupist.o )
Linking hatupist ...
$ ll hatupist
-rwxrwxr-x. 357132 29.7. 22:15 hatupist
Komennolla
strip ohjelmasta saa vieläkin ylimääräistä pois:
$ strip hatupist
$ ll hatupist
-rwxrwxr-x. 239176 29.7. 22:18 hatupist
$ rm hatupist.hi hatupist.o
$ ./hatupist