如何处理Haskell + GTK中的大量小部件?

时间:2016-09-19 06:41:39

标签: haskell gtk

我有一个Glade文件描述我的界面。其目标是通过本地网络控制Nec监视器。因此,有许多小部件控制着监视器的工作方式:

enter image description here

我需要在监视器和小部件之间创建/设置的内容之间建立链接。这意味着获取/设置值并将功能附加到小部件。

来自GTK库的Builder需要使用IO()并转换每个小部件以便调用它们上的特定功能。这有点无聊并添加(不必要的)代码行。

module GUI where

import Graphics.UI.Gtk

data NecControlGUI = NecControlGUI
    { winNecControl :: Window
    , entIPAddress :: Entry
    , btnConnection :: Button
    , cbtVideoInput :: ComboBox
    , cbtPIPInput :: ComboBox
    , sclSharpness :: Scale
    , sclContrast :: Scale
    , sclBrightness :: Scale
    , sclBlackLevel :: Scale
    , sclColorTemperature :: Scale
    , cbtGamma :: ComboBox
    , sclBalance :: Scale
    , sclTreble :: Scale
    , sclBass :: Scale
    , sclVolume :: Scale
    , cbtLanguage :: ComboBox
    , sclMenuDisplayTime :: Scale
    }

loadGUI :: String -> IO NecControlGUI
loadGUI guiPath = do
    bdr <- builderNew

    builderAddFromFile bdr guiPath

    window <- builderGetObject bdr castToWindow "winNecControl"
    ipaddress <- builderGetObject bdr castToEntry "entIPAddress"
    connection <- builderGetObject bdr castToButton "btnConnection"
    videoinput <- builderGetObject bdr castToComboBox "cbtVideoInput"
    pipinput <- builderGetObject bdr castToComboBox "cbtPIPInput"
    sharpness <- builderGetObject bdr castToScale "sclSharpness"
    contrast <- builderGetObject bdr castToScale "sclContrast"
    brightness <- builderGetObject bdr castToScale "sclBrightness"
    blacklevel <- builderGetObject bdr castToScale "sclBlackLevel"
    colortemperature <- builderGetObject bdr castToScale "sclColorTemparature"
    gamma <- builderGetObject bdr castToComboBox "cbtGamma"
    balance <- builderGetObject bdr castToScale "sclBalance"
    treble <- builderGetObject bdr castToScale "sclTreble"
    bass <- builderGetObject bdr castToScale "sclBass"
    volume <- builderGetObject bdr castToScale "sclVolume"
    language <- builderGetObject bdr castToComboBox "cbtLanguage"
    menudisplaytime <- builderGetObject bdr castToScale "sclMenuDisplayTime"

    return NecControlGUI
        { winNecControl = window
        , entIPAddress = ipaddress
        , btnConnection = connection
        , cbtVideoInput = videoinput
        , cbtPIPInput = pipinput
        , sclSharpness = sharpness
        , sclContrast = contrast
        , sclBrightness = brightness
        , sclBlackLevel = blacklevel
        , sclColorTemperature = colortemperature
        , cbtGamma = gamma
        , sclBalance = balance
        , sclTreble = treble
        , sclBass = bass
        , sclVolume = volume
        , cbtLanguage = language
        , sclMenuDisplayTime = menudisplaytime
        }

有没有办法自动化这部分?

我听说过LGtk,但这是唯一的方法吗?

编辑2016-09-20 1

我试图采用适用的方式,但似乎Haskell似乎没有结合应用IO? (但可能是我)

module NecControlGUI where

import Graphics.UI.Gtk

data NecControlGUI = NecControlGUI
    { adjBalance :: Adjustment
    , winNecControl :: Window
    }

loadNecControlGUI :: String -> IO NecControlGUI
loadNecControlGUI guiPath = do
    bdr <- builderNew
    builderAddFromFile bdr guiPath
    let bget = builderGetObject bdr
    NecControlGUI <$> bget castToAdjustment "adjBalance"
                  <*> bget castToWindow "winNecControl"

编译输出以下错误:

.../src/NecControlGUI.hs:16:23: error:
    • Couldn't match type ‘Adjustment’ with ‘Window’
      Expected type: IO Window
        Actual type: IO Adjustment
    • In the second argument of ‘(<*>)’, namely
        ‘bget castToWindow "winNecControl"’
      In a stmt of a 'do' block:
        NecControlGUI <$> bget castToAdjustment "adjBalance"
        <*> bget castToWindow "winNecControl"
      In the expression:
        do { bdr <- builderNew;
             builderAddFromFile bdr guiPath;
             let bget = builderGetObject bdr;
             NecControlGUI <$> bget castToAdjustment "adjBalance"
             <*> bget castToWindow "winNecControl" }

.../src/NecControlGUI.hs:16:28: error:
    • Couldn't match type ‘Window’ with ‘Adjustment’
      Expected type: GObject -> Adjustment
        Actual type: GObject -> Window
    • In the first argument of ‘bget’, namely ‘castToWindow’
      In the second argument of ‘(<*>)’, namely
        ‘bget castToWindow "winNecControl"’
      In a stmt of a 'do' block:
        NecControlGUI <$> bget castToAdjustment "adjBalance"
        <*> bget castToWindow "winNecControl"

编辑2016-09-20 2

如果我摆脱let bdr = ...声明,一切都按预期工作。

1 个答案:

答案 0 :(得分:1)

它不是你想要的,但它更短。使用Applicative实例将对builderGetObject的调用与数据构造函数结合起来。

module GUI where

import Graphics.UI.Gtk

data NecControlGUI = NecControlGUI
    { ...
    }

loadGUI :: String -> IO NecControlGUI
loadGUI guiPath = do
    bdr <- builderNew

    builderAddFromFile bdr guiPath

    let bget = builderGetObject bdr

    NecControlGUI <$> bget castToWindow "winNecControl"
                  <*> bget castToEntry "entIPAddress"
                  <*> bget castToButton "btnConnection"
                  <*> bget castToComboBox "cbtVideoInput"
                  <*> bget castToComboBox "cbtPIPInput"
                  <*> bget castToScale "sclSharpness"
                  <*> bget castToScale "sclContrast"
                  <*> bget castToScale "sclBrightness"
                  <*> bget castToScale "sclBlackLevel"
                  <*> bget castToScale "sclColorTemparature"
                  <*> bget castToComboBox "cbtGamma"
                  <*> bget castToScale "sclBalance"
                  <*> bget castToScale "sclTreble"
                  <*> bget castToScale "sclBass"
                  <*> bget castToScale "sclVolume"
                  <*> bget castToComboBox "cbtLanguage"
                  <*> bget castToScale "sclMenuDisplayTime"
相关问题