(Haskell) gi-gtk 在按钮回调中设置图像
(Haskell) gi-gtk setting image in button callback
我遵循了有关创建基本 Gi-Gtk 应用程序的教程。
现在我想通过将图像的源设置为我从常量字符串列表中随机选择的字符串来对按钮按下做出反应:
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.GI.Base
import System.Random
import qualified GI.Gtk as Gtk
import Control.Monad.Random
akkorde = ["C11.png","C13.png","C69.png","C6.png","C7#11.png","C7#9.png","C7b13.png","C7b9.png","C7.png","C9.png","Cadd9.png","Cj7.png"]
selectAcc:: (MonadRandom m) => m [Char]
selectAcc = do
let n = length akkorde
i <- getRandomR (0, n-1)
return (akkorde !! i)
main :: IO ()
main = do
name <- selectAcc
Gtk.init Nothing
win <- Gtk.windowNew Gtk.WindowTypeToplevel
Gtk.windowSetTitle win "accordtrainer"
Gtk.onWidgetDestroy win Gtk.mainQuit
#resize win 640 480
img <- Gtk.imageNewFromFile ("../" ++ name)
box <- new Gtk.Box [#orientation := Gtk.OrientationVertical ]
#add box img
#add win box
msg <- new Gtk.Label[#label := ( "")]
#packStart box msg True False 10
btn <- new Gtk.Button [#label := "Click me!"]
#packStart box btn False False 10
on btn #clicked ( Gtk.imageSetFromFile img (do { name <- selectAcc; return ("../" ++ name) }))
Gtk.widgetShowAll win
Gtk.main
问题出现在行
on btn #clicked ( Gtk.imageSetFromFile img (do { name <- selectAcc; return ("../" ++ name) }))
我认为 Gtk.imageSetFromFile 需要一个 Maybe[Char] 但目前它只能得到 [Char]
ghc 说:
app/Main.hs:38:62: error:
• No instance for (MonadRandom Maybe)
arising from a use of ‘selectAcc’
Just 构造函数应该给我一个 maybe 类型
on btn #clicked ( Gtk.imageSetFromFile img (Just(do { name <- selectAcc; return ("../" ++ name) })))
但后来我发现类型不匹配
• Couldn't match type ‘[Char]’ with ‘Char’
Expected type: Maybe [Char]
Actual type: Maybe [[Char]]
错误/“修复”链仍在继续
我认为我做的事情从根本上是错误的,但我不知道如何以“正确”的方式做到这一点如果你知道我应该如何写这一行或更好的方法来获得随机选择的字符串,请回复
您已经在使用 mtl
风格的 monad 约束,它比普通的 monad 更高级,所以不用担心不理解所有内容。
imageSetFromFile
的简化类型为:
imageSetFromFile :: Image -> Maybe [Char] -> IO ()
因此它希望您提供 Maybe [Char]
作为输入,其中 Nothing
可能会删除图像,而 Just someFile
会将图像设置到该文件位置。
您正在使用的函数具有以下类型:
selectAcc:: MonadRandom m => m [Char]
这意味着m
这里需要一些可以生成随机数的monad。您可以通过在 GHCi 中键入以下内容来查找 MonadRandom
的实例:
ghci> import Control.Monad.Random
ghci> :i MonadRandom
type MonadRandom :: (* -> *) -> Constraint
class Monad m => MonadRandom m where
getRandomR :: Random a => (a, a) -> m a
getRandom :: Random a => m a
getRandomRs :: Random a => (a, a) -> m [a]
getRandoms :: Random a => m [a]
{-# MINIMAL getRandomR, getRandom, getRandomRs, getRandoms #-}
-- Defined in ‘Control.Monad.Random.Class’
instance (RandomGen g, Monad m) => MonadRandom (RandT g m)
-- Defined in ‘Control.Monad.Trans.Random.Lazy’
instance [safe] MonadRandom IO
-- Defined in ‘Control.Monad.Random.Class’
在底部你会看到两个实例:一个是 RandT
(一个 monad 转换器),另一个是 IO
。但是,imageSetFromFile
需要一个 Maybe [Char]
作为参数,因此两者都不会立即起作用。但是在这种情况下,您可以在 IO
monad 中调用 imageSetFromFile
之前生成随机名称:
on btn #clicked $ do
name <- selectAcc
Gtk.imageSetFromFile img (Just ("../" ++ name))
我遵循了有关创建基本 Gi-Gtk 应用程序的教程。 现在我想通过将图像的源设置为我从常量字符串列表中随机选择的字符串来对按钮按下做出反应:
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Data.GI.Base
import System.Random
import qualified GI.Gtk as Gtk
import Control.Monad.Random
akkorde = ["C11.png","C13.png","C69.png","C6.png","C7#11.png","C7#9.png","C7b13.png","C7b9.png","C7.png","C9.png","Cadd9.png","Cj7.png"]
selectAcc:: (MonadRandom m) => m [Char]
selectAcc = do
let n = length akkorde
i <- getRandomR (0, n-1)
return (akkorde !! i)
main :: IO ()
main = do
name <- selectAcc
Gtk.init Nothing
win <- Gtk.windowNew Gtk.WindowTypeToplevel
Gtk.windowSetTitle win "accordtrainer"
Gtk.onWidgetDestroy win Gtk.mainQuit
#resize win 640 480
img <- Gtk.imageNewFromFile ("../" ++ name)
box <- new Gtk.Box [#orientation := Gtk.OrientationVertical ]
#add box img
#add win box
msg <- new Gtk.Label[#label := ( "")]
#packStart box msg True False 10
btn <- new Gtk.Button [#label := "Click me!"]
#packStart box btn False False 10
on btn #clicked ( Gtk.imageSetFromFile img (do { name <- selectAcc; return ("../" ++ name) }))
Gtk.widgetShowAll win
Gtk.main
问题出现在行
on btn #clicked ( Gtk.imageSetFromFile img (do { name <- selectAcc; return ("../" ++ name) }))
我认为 Gtk.imageSetFromFile 需要一个 Maybe[Char] 但目前它只能得到 [Char] ghc 说:
app/Main.hs:38:62: error:
• No instance for (MonadRandom Maybe)
arising from a use of ‘selectAcc’
Just 构造函数应该给我一个 maybe 类型
on btn #clicked ( Gtk.imageSetFromFile img (Just(do { name <- selectAcc; return ("../" ++ name) })))
但后来我发现类型不匹配
• Couldn't match type ‘[Char]’ with ‘Char’
Expected type: Maybe [Char]
Actual type: Maybe [[Char]]
错误/“修复”链仍在继续
我认为我做的事情从根本上是错误的,但我不知道如何以“正确”的方式做到这一点如果你知道我应该如何写这一行或更好的方法来获得随机选择的字符串,请回复
您已经在使用 mtl
风格的 monad 约束,它比普通的 monad 更高级,所以不用担心不理解所有内容。
imageSetFromFile
的简化类型为:
imageSetFromFile :: Image -> Maybe [Char] -> IO ()
因此它希望您提供 Maybe [Char]
作为输入,其中 Nothing
可能会删除图像,而 Just someFile
会将图像设置到该文件位置。
您正在使用的函数具有以下类型:
selectAcc:: MonadRandom m => m [Char]
这意味着m
这里需要一些可以生成随机数的monad。您可以通过在 GHCi 中键入以下内容来查找 MonadRandom
的实例:
ghci> import Control.Monad.Random
ghci> :i MonadRandom
type MonadRandom :: (* -> *) -> Constraint
class Monad m => MonadRandom m where
getRandomR :: Random a => (a, a) -> m a
getRandom :: Random a => m a
getRandomRs :: Random a => (a, a) -> m [a]
getRandoms :: Random a => m [a]
{-# MINIMAL getRandomR, getRandom, getRandomRs, getRandoms #-}
-- Defined in ‘Control.Monad.Random.Class’
instance (RandomGen g, Monad m) => MonadRandom (RandT g m)
-- Defined in ‘Control.Monad.Trans.Random.Lazy’
instance [safe] MonadRandom IO
-- Defined in ‘Control.Monad.Random.Class’
在底部你会看到两个实例:一个是 RandT
(一个 monad 转换器),另一个是 IO
。但是,imageSetFromFile
需要一个 Maybe [Char]
作为参数,因此两者都不会立即起作用。但是在这种情况下,您可以在 IO
monad 中调用 imageSetFromFile
之前生成随机名称:
on btn #clicked $ do
name <- selectAcc
Gtk.imageSetFromFile img (Just ("../" ++ name))