简体   繁体   English

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

[英]How to deal with lots of widgets in Haskell+GTK?

I have a Glade file describing my interface.我有一个描述我的界面的 Glade 文件。 Its goal is to control a Nec monitor through local network.它的目标是通过本地网络控制一个 Nec 监视器。 Therefore there are lots of widgets controlling how the monitor works:因此有很多小部件控制监视器的工作方式:

在此处输入图片说明

I need to create the link between what I get/set from/to the monitor and the widgets.我需要在我从/向监视器获取/设置的内容与小部件之间创建链接。 This means getting/setting values and attaching functions to widgets.这意味着获取/设置值并将功能附加到小部件。

The Builder from GTK library requires to use IO () and cast every widget in order to call specific functions on them. GTK 库中的Builder需要使用 IO() 并强制转换每个小部件,以便在它们上调用特定函数。 This is kinda boring and add (unnecessary) lines of code.这有点无聊并添加(不必要的)代码行。

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
        }

Is there a way to automate this part?有没有办法使这部分自动化?

I heard of LGtk, but is it the only way to do it?我听说过 LGtk,但这是唯一的方法吗?

Edit 2016-09-20 1编辑 2016-09-20 1

I tried to go the applicative way, but it doesn't seem that Haskell like combining applicative IO ?我尝试采用适用的方式,但 Haskell 似乎不喜欢结合应用 IO ? (but it's probably me) (但可能是我)

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"

Compiling outputs the following errors:编译输出以下错误:

.../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"

Edit 2016-09-20 2编辑 2016-09-20 2

If I get rid of the let bdr = ... statement, everything works as expected.如果我去掉let bdr = ...语句,一切都会按预期进行。

It's not what you are looking for, but it is shorter.这不是你要找的,但它更短。 Use the Applicative instance to combine the calls to builderGetObject with the data constructor.使用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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM