在gtk2hs按下按钮时如何反复执行某些操作?

时间:2014-02-27 04:38:08

标签: haskell ghc gtk2hs

我需要在按下按钮时执行某些操作。我该怎么办?

我的版本是0.12.4。

P上。小号: 出于某种原因,

中的onButtonActivate
import Graphics.UI.Gtk
import Control.Concurrent
main = do
    initGUI
    window <- windowNew

    but <-buttonNewWithLabel "Write A"

    onButtonActivate  but $ do
        putStr "A"
        threadDelay 1000000
        return()

    containerAdd window but

    widgetShowAll window
    onDestroy window mainQuit
    mainGUI

什么都不做。


此外,如果在按下键盘上的某个键时反复进行操作,那么最好去。

2 个答案:

答案 0 :(得分:1)

根据docs onButtonActivate被折旧,所以你可能不应该使用它。我很难找到正确的方法,可能有一些你应该使用的泛型信号。您可以尝试使用onPressed和onRelease的解决方案(这些也被称为折旧)。您可以按照注释中的建议执行操作并分叉线程:

import Control.Concurrent (forkIO, killThread, threadDelay)
import Control.Monad (void, when)

whilePressed button action = do
    onPressed button $ do
        threadId <- forkIO go
        onReleased button (killThread threadId)
    where
        go = do
            action
            threadDelay 1000000
            go

然后重写你的主要做:

whilePressed but (putStr "A")

我不确定这是否安全,因为似乎可以在killThread注册之前触发buttonReleased事件。使用IORef可能更安全:

import Data.IORef


whilePressed button action = do
    isPressed <- newIORef False

    onPressed button $ do
        writeIORef isPressed True
        void $ forkIO $ go isPressed

    onReleased button (writeIORef isPressed False)

    where
        go isPressed = do
            c <- readIORef isPressed
            when c $ do
                action
                threadDelay 1000000
                void $ forkIO $ go isPressed

不幸的是我没有编译或测试代码正弦我无法在这台电脑上安装GTK,但如果您有任何问题请告诉我。

答案 1 :(得分:1)

这使用了一个ToggleButton,一个“超时”对象(参见文档中System.Glib.MainLoop模块中的timeoutAdd)和一个IORef。按下ToggleButton时启动计时器,但前提是当前没有其他计时器正在运行(这就是IORef的目的)。如果释放按钮,则计时器停止。计时器的回调函数返回IO False以停止并销毁计时器对象。

import Graphics.UI.Gtk
import Data.IORef
import Control.Monad(void, when)

action but idle = do
    butDown <- get but toggleButtonActive
    if butDown
        then do
            putStrLn "A"
            writeIORef idle False
            return True
        else do
            writeIORef idle True
            return False

main = do
    initGUI
    window <- windowNew

    but <-toggleButtonNewWithLabel "Write A"

    idle <- newIORef True

    on but toggled $ do
        butDown <- get but toggleButtonActive
        isIdle  <- readIORef idle
        when (butDown && isIdle) $ void $ timeoutAdd (action but idle) 1000

    containerAdd window but

    widgetShowAll window
    on window objectDestroy mainQuit
    mainGUI

注册信号回调的首选方法是使用“on”。还要注意“on window objectDestroy mainQuit”正确地破坏窗口并停止Gtk主循环(你的版本没有销毁GHCi中的定时器,它们在再次调用“main”后继续运行)。