2013-05-10 25 views
8

के साथ प्रतिक्रियाशील तालिका मैंने एक छोटा सा एप्लीकेशन लिखा है जो टीवी श्रृंखला में मेरी प्रगति को ट्रैक करता है। आवेदन reactive banana के साथ कार्यात्मक प्रतिक्रियाशील प्रोग्रामिंग (एफआरपी) के साथ हास्केल में लिखा गया है।प्रतिक्रियाशील केला और gtk2hs

आवेदन कर सकते हैं:

  • जोड़ें/
  • परिवर्तन मौसम और एक श्रृंखला

App Screenshot

मैं समस्याओं लेखन है प्रकरण तालिका करने के लिए नए टीवी श्रृंखला को दूर कोड जो तालिका में एक नई टीवी श्रृंखला जोड़ता है और नई घटनाओं को तार देता है। here से सीआरयूडी उदाहरण ने मेरी मदद नहीं की क्योंकि मेरे पास अधिक आवश्यकताएं हैं और फिर सूची से तत्व का चयन करें।

मैं reactiveTable फ़ंक्शन कैसे reactiveListDisplay फ़ंक्शन को CRUD Example से FRF तरीके से लिखूं? हटाए गए बटन और सीजन और एपिसोड स्पिन बटन के लिए नेटवर्क को संकलित करने के बाद ईवेंट कैसे जोड़ा जा सकता है?

data Series = Series { name :: String 
        , season :: Int 
        , episode :: Int 
        } 


insertIntoTable :: TableClass t => t -> SeriesChangeHandler -> SeriesRemoveHandler -> Series -> IO() 
insertIntoTable table changeHandler removeHandler (Series name s e) = do 
    (rows, cols) <- tableGetSize table 
    tableResize table (rows+1) cols 

    nameLabel  <- labelNew $ Just name 
    adjustmentS <- adjustmentNew (fromIntegral s) 1 1000 1 0 0 
    adjustmentE <- adjustmentNew (fromIntegral e) 1 1000 1 0 0 
    seasonButton <- spinButtonNew adjustmentS 1.0 0 
    episodeButton <- spinButtonNew adjustmentE 1.0 0 
    removeButton <- buttonNewWithLabel "remove" 
    let getSeries = do 
      s <- spinButtonGetValue seasonButton 
      e <- spinButtonGetValue episodeButton 
      return $ Series name (round s) (round e) 
     handleSeries onEvent widget handler = do 
      onEvent widget $ do 
       series <- getSeries 
       handler series 

    handleSeries onValueSpinned seasonButton changeHandler 
    handleSeries onValueSpinned episodeButton changeHandler 
    onPressed removeButton $ do 
     series <- getSeries 
     containerRemove table nameLabel 
     containerRemove table seasonButton 
     containerRemove table episodeButton 
     containerRemove table removeButton 
     removeHandler series 

    let tadd widget x = tableAdd table widget x (rows - 1) 
    tadd nameLabel  0 
    tadd seasonButton 1 
    tadd episodeButton 2 
    tadd removeButton 3 
    widgetShowAll table 


main :: IO() 
main = do 

    initGUI 

    window  <- windowNew 
    scroll  <- scrolledWindowNew Nothing Nothing 
    table  <- tableNew 1 5 True 
    addButton <- buttonNewWithLabel "add series" 
    vbox  <- vBoxNew False 10 

    containerAdd window vbox 
    boxPackStart vbox addButton PackNatural 0 

    let networkDescription :: forall t. Frameworks t => Moment t() 
     networkDescription = do 

      addEvent <- eventButton addButton 

      (changeHandler,fireChange) <- liftIO $ newAddHandler 
      changeEvent <- fromAddHandler changeHandler 
      (removeHandler,fireRemove) <- liftIO $ newAddHandler 
      removeEvent <- fromAddHandler removeHandler 

      let insertIntoTable' = insertIntoTable table fireChange fireRemove 
       addSeries e = do 
        s <- addSeriesDialog 
        liftIO $ insertIntoTable' s 

      liftIO $ mapM_ insertIntoTable' initSeries 

      reactimate $ addSeries   <$> addEvent 
      reactimate $ updateSeries conn <$> changeEvent 
      reactimate $ removeSeries conn <$> removeEvent 

    network <- compile networkDescription 
    actuate network 

    onDestroy window $ do 
     D.disconnect conn 
     mainQuit 

    widgetShowAll window 
    mainGUI 

मैं घटनाओं और व्यवहार के बजाय साधारण कॉलबैक का उपयोग करके उपयोग करने के लिए insertIntoTable विधि refactor करना चाहते हैं।

संपादित करें:

मैं एक ListStore बैकएंड साथ जीटीके TreeView कोशिश की है। इस परिदृश्य में आपको गतिशील ईवेंट स्विचिंग की आवश्यकता नहीं है। मैंने घटनाओं को सम्मिलित करने, बदलने और हटाने के लिए सूची व्यवहार प्राप्त करने के लिए नीचे reactiveList फ़ंक्शन लिखा है। यह ^^

reactiveList :: (Frameworks t) 
    => ListStore a 
    -> Event t (Int,a) -- insert event 
    -> Event t (Int,a) -- change event 
    -> Event t (Int,a) -- remove event 
    -> Moment t (Behavior t [a]) 
reactiveList store insertE changeE removeE = do 

    (listHandler,fireList) <- liftIO $ newAddHandler 

    let onChange f (i,a) = do 
      f i a 
      list <- listStoreToList store 
      fireList list 

    reactimate $ onChange (listStoreInsert store)   <$> insertE 
    reactimate $ onChange (listStoreSetValue store)  <$> changeE 
    reactimate $ onChange (const . listStoreRemove store) <$> removeE 

    initList <- liftIO $ listStoreToList store 
    fromChanges initList listHandler 


main :: IO() 
main = do 

    initGUI 

    window  <- windowNew 
    addButton <- buttonNewWithLabel "add series" 
    vbox  <- vBoxNew False 10 
    seriesList <- listStoreNew (initSeries :: [Series]) 
    listView <- treeViewNewWithModel seriesList 

    treeViewSetHeadersVisible listView True 

    let newCol title newRenderer f = do 
      col <- treeViewColumnNew 
      treeViewColumnSetTitle col title 
      renderer <- newRenderer 
      cellLayoutPackStart col renderer False 
      cellLayoutSetAttributes col renderer seriesList f 
      treeViewAppendColumn listView col 
      return renderer 

    newCol "Image" cellRendererPixbufNew $ \s -> [cellPixbuf :=> newPixbuf s] 
    newCol "Name" cellRendererTextNew $ \s -> [cellText := name s] 
    seasonSpin <- newCol "Season" cellRendererSpinNew $ \s -> 
     [ cellRendererSpinAdjustment :=> adjustmentNew (fromIntegral (season s)) 1 1000 1 0 0 
     , cellText := (show $ season s) 
     , cellTextEditable := True 
     ] 
    episodeSpin <- newCol "Episode" cellRendererSpinNew $ \s -> 
     [ cellRendererSpinAdjustment :=> adjustmentNew (fromIntegral (episode s)) 1 1000 1 0 0 
     , cellText := (show $ episode s) 
     , cellTextEditable := True 
     ] 

    containerAdd window vbox 
    boxPackStart vbox listView PackGrow 0 
    boxPackStart vbox addButton PackNatural 0 

    let networkDescription :: forall t. Frameworks t => Moment t() 
     networkDescription = do 

      (addHandler,fireAdd) <- liftIO $ newAddHandler 
      maybeSeriesE <- fromAddHandler addHandler 
      (removeHandler,fireRemove) <- liftIO $ newAddHandler 
      removeE <- fromAddHandler removeHandler 

      -- when the add button was pressed, 
      -- open a dialog and return maybe a new series 
      askSeriesE <- eventButton addButton 
      reactimate $ (const $ fireAdd =<< askSeries) <$> askSeriesE 

      -- ommit all nothing series 
      let insertE = filterJust maybeSeriesE 
       insert0E = ((,) 0) <$> insertE 

      seasonSpinE <- eventSpin seasonSpin seriesList 
      episodeSpinE <- eventSpin episodeSpin seriesList 
      let changeSeason (i,d,s) = (i,s {season = round d}) 
       changeEpisode (i,d,s) = (i,s {episode = round d}) 
      let changeE = (changeSeason <$> seasonSpinE) `union` (changeEpisode <$> episodeSpinE) 

      listB <- reactiveList seriesList insert0E changeE removeE 
      listE <- (changes listB) 

      reactimate $ (putStrLn . unlines . map show) <$> listE 
      reactimate $ insertSeries conn  <$> insertE 
      reactimate $ updateSeries conn . snd <$> changeE 
      reactimate $ removeSeries conn . snd <$> removeE 

      return() 

    network <- compile networkDescription 
    actuate network 

    onDestroy window $ do 
     D.disconnect conn 
     mainQuit 

    widgetShowAll window 
    mainGUI 

मैं टिप्पणियों और सुझावों के लिए खुला हूं।

+0

अगर हमारे पास कुछ कोड भी काम करने में मदद मिलेगी तो इससे मदद मिलेगी। विशेष रूप से, आपकी अंतर्निहित डेटा संरचना क्या है? – isturdy

उत्तर

3

ऐसा लगता है कि आपकी समस्या CRUD एक से Bar Tab उदाहरण के करीब है।

नए व्यवहार जोड़ने के लिए मूल विचार - नए व्यवहार और घटनाओं के साथ - तथाकथित "गतिशील घटना स्विचिंग" का उपयोग करना है। अनिवार्य रूप से, यह नव निर्मित घटनाओं और व्यवहार को आपके नेटवर्क में वापस लाने का एक तरीका है।

नया विजेट बनाने की क्रिया में दो भाग हैं। पहला भाग liftIO का उपयोग करके विजेट बनाने के लिए है। दूसरा यह है कि इसके इनपुट प्राप्त करें और उपयुक्त के रूप में trimE या trimB का उपयोग करें। जीटीके-विशिष्ट विवरण के सबसे बाहर छोड़कर (मैं जीटीके उपयोग करने के लिए पता नहीं कैसे: पी), यह कुछ इस तरह दिखाई देंगे:

let newSeries name = do 
    label <- liftIO . labelNew $ Just name 
    liftIO $ tadd labelNew 0 
    {- ... the rest of your controls here ... -} 
    seasonNumber <- trimB $ getSpinButtonBehavior seasonButton 
    {- ... wrap the rest of the inputs using trimB and trimE ... -} 
    return (label, seasonNumber, ...) 

तो यह समारोह एक नया विजेट बनाता है, "ट्रिम" अपने इनपुट और मूल्य आपको वापस देता है। अब आप वास्तव में इन मूल्यों का उपयोग करना होगा:

newSeasons <- execute (FrameworkMoment newSeries <$> nameEvents) 
यहाँ nameEvents

एक Event String हर बार जब आप जोड़ना चाहते हैं नई श्रृंखला के नाम के साथ एक घटना से युक्त होना चाहिए।

अब आप नए सीजन के सभी की एक धारा है तो आप उसे यह सब stepper की तरह कुछ का उपयोग कर प्रविष्टियों की एक सूची की एक एकल व्यवहार में जोड़ सकते हैं।

अधिक जानकारी के लिए - अपने सभी विजेटों से कुल जानकारी प्राप्त करने जैसी चीजों सहित - वास्तविक उदाहरण कोड देखें।

+0

महान उत्तर के लिए धन्यवाद। जवाब देने से पहले, मैं कोशिश करता हूं और परिणामों को पोस्ट करता हूं। – SvenK

संबंधित मुद्दे