gtk2hs

2011-03-14 7 views
9

में ईवेंट हैंडलर के बीच स्थिति कैसे पारित करें मैं हास्केल में ईवेंट संचालित प्रोग्राम लिखने के तरीके के बारे में अपना सिर प्राप्त करने के लिए खिलौना एप्लिकेशन बनाने की कोशिश कर रहा हूं। जो मैं करने की कोशिश कर रहा हूं वह एक कैनवास की रेखा खींचता है जो हर बार एक कुंजी दबाए जाने पर आगे बढ़ता है (इसलिए यह टेक्स्ट एडिटर में एक प्रायोगिक कर्सर है)।gtk2hs

मेरी समस्या यह है कि मैं काम नहीं कर सकता कि उपयोगकर्ता ने कुंजी दबाए जाने की संख्या को गिनने का सबसे अच्छा तरीका क्या है। जाहिर है, मैं एक वैश्विक चर का उपयोग नहीं कर सकता जैसे कि मैं एक अनिवार्य कार्यक्रम में हूं, इसलिए शायद मुझे कॉल स्टैक पर राज्य को पास करने की ज़रूरत है, लेकिन प्रत्येक ईवेंट हैंडलर रिटर्न के बाद जीटीके निष्पादन मुख्य लूप में उतरता है और जब से मैं नहीं करता मुख्य पाश को नियंत्रित करें मैं नहीं देखता कि मैं एक ईवेंट हैंडलर से बदलती वैश्विक स्थिति को कैसे पार कर सकता हूं। तो एक घटना हैंडलर कभी भी एक और घटना हैंडलर पर राज्य कैसे पारित कर सकता है?

मेरे यहां एक आंशिक समाधान है, जहां कीबोर्ड ईवेंट फिर से मेरा ड्रॉ करता है और इसे ईवेंट हैंडलर के रूप में सेट करता है। मुझे यकीन नहीं है कि क्या यह समाधान बढ़ाया जा सकता है, या यहां तक ​​कि यदि यह एक अच्छा विचार है।

इस समस्या का सबसे अच्छा कण समाधान क्या है?

import Graphics.UI.Gtk 
import Graphics.Rendering.Cairo 

main :: IO() 
main= do 
    initGUI 
    window <- windowNew 
    set window [windowTitle := "Hello World", 
       windowDefaultWidth := 300, windowDefaultHeight := 200] 

    canvas <- drawingAreaNew 
    containerAdd window canvas 

    widgetShowAll window 
    draWin <- widgetGetDrawWindow canvas 
    canvas `on` exposeEvent $ do liftIO $ renderWithDrawable draWin (myDraw 10) 
            return False 

    window `on` keyPressEvent $ onKeyboard canvas 
    window `on` destroyEvent $ do liftIO mainQuit 
            return False 

    mainGUI 

onKeyboard :: DrawingArea -> EventM EKey Bool 
onKeyboard canvas = do 
    liftIO $ do drawWin <- widgetGetDrawWindow canvas 
       canvas `on` exposeEvent $ do liftIO $renderWithDrawable drawWin (myDraw 20) 
              return False 
       widgetQueueDraw canvas 
    return False 



myDraw :: Double -> Render() 
myDraw pos = do 
    setSourceRGB 1 1 1 
    paint 
    setSourceRGB 0 0 0 

    moveTo pos 0 
    lineTo pos 20 
    stroke 

उत्तर

7

सबसे पहले, आप वैश्विक हो सकते हैं। उस समाधान को खराब रूप के रूप में अनदेखा करते हुए, यह MVar के लिए नौकरी की तरह दिखता है। main में आप बस एक नई MVAr जो आप onKeyboard में अद्यतन कर सकते हैं बनाने के लिए और myDraw में जाँच:

... 
import Control.Concurrent.MVar 

main = do 
    ... 
    mv <- newMVar 0 
    .... 
    canvas `on` exposeEvent $ do liftIO $ renderWithDrawable draWin (myDraw mv 10) 
    ... 
    window `on` keyPressEvent $ onKeyboard canvas mv 

onKeyboard canvas mv = do 
    modifyMVar_ mv (\x -> return (x + 1)) 
    .... 

myDraw mv pos = do 
    val <- readMVar mv 
    ... 

ध्यान दें कि परिवर्तनशील राज्य को बांटने भी अक्सर उपयोगी होता है जब पहला आंशिक अनुप्रयोग का उपयोग MVar प्रदान करने के लिए (द्वारा तर्क के रूप में कार्य गुजर या TVar, IORef, जो भी हो)।

ओह, और एक चेतावनी: एमवीआर सख्त नहीं हैं - यदि एप्लिकेशन में मूल्य को मजबूर किए बिना बहुत कुछ लिखने की क्षमता है (यानी Int निहित और तुलना करना), तो आपको इमारत से बचने के लिए लिखने से पहले मूल्य को मजबूर करना चाहिए एक बड़ा हिस्सा