Использование IORef в трехпенном графическом интерфейсе

Я пытаюсь установить IORef в Threepenny-GUI, но я не могу заставить его работать. В моем приложении сам IORef будет более сложным и не будет отображаться сам по себе - но этот пример демонстрирует проблему, я думаю.

Вот моя попытка:

testIORef2 :: IORef String -> Window -> UI ()
testIORef2 ref window = void $ do
    return window # set title "Test IORef"

    inCell <- UI.input
    outCell   <- UI.input

    getBody window #+ [
            column [
                grid [[string " In cell::", element inCell]
                     ,[string "Out cell::"  , element outCell  ]]
            , string "Cells should update while typing."
            ]]

    -- When value changes write to IORef
    on  UI.valueChange inCell $ \_ -> do
        inValue <- get value inCell
        liftIO $ writeIORef ref inValue    

    -- Read the IORef
    refVal <- liftIO $ readIORef ref

    -- Behaviour which holds the string value in the input cell
    inValue <- stepper "0" $ UI.valueChange inCell
    -- Behaviour which holds the value in the ref
    let outValue = (const refVal) <$> inValue

    -- Set the value of the output cell to the outValue
    element outCell # sink value outValue

Код вроде работает, но outValue не совсем в курсе.

Как это исправить, чтобы обновления были вовремя. Также приветствуются любые улучшения в коде.

Благодарю.

2 ответа

Решение

Код, который вы написали, вероятно, не то, что вы намеревались сделать. Линия

let outValue = (const refVal) <$> inValue

указывает, что outValue это Behavior значение которого является постоянным и равным refValue, В свою очередь, последнее значение получается из

refVal <- liftIO $ readIORef ref

Это означает, что его значение хранится IORef на данный момент в UI монада.


Когда используешь IORefвы хотите прочитать значение ссылки, когда что-то меняется, и использовать это значение для изменения содержимого пользовательского интерфейса, например, так:

on  UI.valueChange inCell $ \_ -> do
    inValue  <- get value inCell
    liftIO $ writeIORef ref inValue
    outValue <- liftIO $ readIORef ref    
    element outCell # set value outValue

Из соображений согласованности (порядка операций) не рекомендуется использовать IORef в качестве источника для Behavior - это либо последний, либо первый.

Я не эксперт по трипенни-гуй, но вот мое предположение.

Код, который вы пишете вне on Обработчик событий выполняется только один раз. Поэтому вы хотите включить outValue обновить внутри указанного обработчика, например

-- When value changes write to IORef
on  UI.valueChange inCell $ \_ -> do
    inValue <- get value inCell
    liftIO $ writeIORef ref inValue    
    ... -- compute outValue
    element outCell # sink value outValue
Другие вопросы по тегам