我无法从标签和操作列表中生成按钮。 我很确定这与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
答案 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)
由于buttonActivated
和data ButtonInfo = ButtonInfo {
buttonLabel :: ButtonLabel
, buttonAction :: ButtonAction
, buttonIo :: Button -- no IO here!
}
属于不同类型,这会立即导致很多类型错误。这很好,因为修复这些类型的错误会迫使你只创建一次按钮,这样就可以让它们响应并在屏幕上显示。