Использование 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