Haskell& gtk2hs,按钮激活信号无法绑定

时间:2014-05-17 20:12:16

标签: haskell gtk2hs

我无法从标签和操作列表中生成按钮。 我很确定这与IO没有得到评估有关(按钮上的按钮激活动作&#39;),但我不确定如何解决它。< / p>

我有一个(Label,Command)元组列表,我用它来生成一个Button,以及它与IO()的关联动作。

调用的功能:&#39;按钮按钮激活动作&#39;被调用,但按钮仍然没有记录点击。

module GtkTest where

import qualified Data.Map as M
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Buttons.Button
import Graphics.UI.Gtk.Windows.Window
import Graphics.UI.Gtk.Layout.VBox
import Control.DeepSeq

type Command = String
type ButtonLabel = String
type ButtonAction = IO ()
type ButtonDesc = (ButtonLabel, Command)
data ButtonInfo = ButtonInfo {
    buttonLabel :: ButtonLabel
  , buttonAction :: ButtonAction
  , buttonIo :: IO Button
  }

genAction :: Command -> ButtonAction
genAction command = putStrLn ("Running: " ++ command)

genButton :: ButtonDesc -> ButtonInfo
genButton info = let (label, command) = info
                 in ButtonInfo label (genAction command) (buttonNewWithLabel label)

getButtonDescs :: IO [ButtonDesc]
getButtonDescs = return [("Ok", "ok"),
                         ("Foo", "foo"),
                         ("Bar", "bar")]

applyAction (ButtonInfo _ action io) = do
--This gets called
  putStrLn "applying click handler"
  button <- io
--But apparently not this
  on button buttonActivated action

addIoToContainer container io = do
  widget <- io
  containerAdd container widget

main = do
  initGUI
  window <- windowNew
--These buttons do not work
  buttonDescs <- getButtonDescs
  buttons <- return $ map genButton buttonDescs
  vbox <- vBoxNew True 0
  _ <- sequence $ map ((addIoToContainer vbox) . buttonIo) buttons
  _ <- sequence $ map applyAction buttons
  _ <- containerAdd window vbox
-- This button works
  button <- buttonNewWithLabel "Manually made"
  on button buttonActivated $ genAction "Manual action"
  containerAdd vbox button
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI

非常感谢任何帮助。谢谢。

编辑:

根据chi的回答,我将ButtonInfo数据类型更新为不执行IO,最后使用IO [ButtonInfo],这允许我绑定操作。

修订来源(工作):

module GtkTest where

import qualified Data.Map as M
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Buttons.Button
import Graphics.UI.Gtk.Windows.Window
import Graphics.UI.Gtk.Layout.VBox
import Control.DeepSeq

type Command = String
type ButtonLabel = String
type ButtonAction = IO ()
type ButtonDesc = (ButtonLabel, Command)
data ButtonInfo = ButtonInfo {
    buttonLabel :: ButtonLabel
  , buttonAction :: ButtonAction
  , buttonWidget :: Button
  }

genAction :: Command -> ButtonAction
genAction command = putStrLn ("Running: " ++ command)

genButton :: ButtonDesc -> IO ButtonInfo
genButton info = let (label, command) = info
                 in do
                   button <- (buttonNewWithLabel label)
                   return $ ButtonInfo label (genAction command) button

getButtonDescs :: IO [ButtonDesc]
getButtonDescs = return [("Ok", "ok"),
                         ("Foo", "foo"),
                         ("Bar", "bar")]

applyAction (ButtonInfo _ action widget) = do
  putStrLn "applying click handler"
  on widget buttonActivated action

addIoToContainer container io = do
  widget <- io
  containerAdd container widget

main = do
  initGUI
  window <- windowNew
  buttonDescs <- getButtonDescs
  buttons <- sequence $ map genButton buttonDescs
  vbox <- vBoxNew True 0
  _ <- sequence $ map ((containerAdd vbox) . buttonWidget) buttons
  _ <- sequence $ map applyAction buttons
  _ <- containerAdd window vbox
  button <- buttonNewWithLabel "Manually made"
  on button buttonActivated $ genAction "Manual action"
  containerAdd vbox button
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI

1 个答案:

答案 0 :(得分:1)

我可以看到,buttonIo的{​​{1}}字段存储了一个动作,每次运行时都会创建一个新按钮。因此,代码

ButtonInfo

看起来不对,因为applyAction (ButtonInfo _ action io) = do putStrLn "applying click handler" button <- io -- (1) on button buttonActivated action addIoToContainer container io = do widget <- io -- (2) containerAdd container widget 创建了一个新按钮(行addIoToContainer)并将其添加到容器中,而(2)创建了另一个按钮(行applyAction)并带有{ {1}}附加行动。因此,屏幕上会显示一个无响应的按钮,屏幕上会显示一个响应按钮。

我的建议是使用

(1)

由于buttonActivateddata ButtonInfo = ButtonInfo { buttonLabel :: ButtonLabel , buttonAction :: ButtonAction , buttonIo :: Button -- no IO here! } 属于不同类型,这会立即导致很多类型错误。这很好,因为修复这些类型的错误会迫使你只创建一次按钮,这样就可以让它们响应并在屏幕上显示。