1

ラベルとアクションのリストからボタンを生成するのに問題があります。IO が評価されていないこと (「on button buttonActivated アクション」) に関係していると確信していますが、それを修正する方法はわかりません。

Button を生成するために使用する (Label, Command) タプルのリストがあり、関連付けられている IO () アクションです。

「on button buttonActivated アクション」を呼び出す関数が呼び出されますが、ボタンはまだクリックを登録しません。

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
4

1 に答える 1

1

私が見る限り、のbuttonIoフィールドに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)) を作成するため、間違っているように見えます。buttonActivatedそのため、画面上に応答しないボタンが表示され、画面外に応答するボタンが表示されます。

私の提案は使用することです

data ButtonInfo = ButtonInfo {
    buttonLabel :: ButtonLabel
  , buttonAction :: ButtonAction
  , buttonIo :: Button   -- no IO here!
  }

これにより、IO ButtonButtonが異なる型であるため、すぐに多くの型エラーが発生します。これらのタイプ エラーを修正すると、ボタンを 1 回だけ作成する必要があり、応答性が高く、画面上に表示されるため、これは良いことです。

于 2014-05-17T21:34:35.247 に答える