私が達成したいこと:
ユーザーがキャンバスをクリックするたびに、そのクリックからマウス座標を取得して を構築し、Point x y
この状態を に保存[Point]
して、後でユーザーがボタンをクリックしたときに、それ[Point]
を何らかの関数の入力として使用できるようにします。
私がやったこと:
Point
次のような単一値コンストラクターを使用して、データ型を定義しました。
data Point = Point {
x :: Int,
y :: Int
} deriving (Show, Eq)
UI
ユーザーインターフェイスを定義するために3ペニー(モナド?)をセットアップしまし400 x 400 canvas
たbutton
。
import qualified Graphics.UI.Threepenny as UI
import Graphics.UI.Threepenny.Core
import Control.Monad
canvasSize = 400
setup :: Window -> UI ()
setup window = do
return window # set title "Haskell GUI"
canvas <- UI.canvas
# set UI.height canvasSize
# set UI.width canvasSize
# set style [("border", "solid black 1px"), ("background", "#eee")]
button <- UI.button #+ [string "Do stuff"]
getBody window #+
[
column [element canvas],
element canvas,
element button
]
on UI.mousedown canvas $ \(x, y) -> do
-- Need to create a point x y and add it to a list here
on UI.click button $ const $ do
-- Need to get the list of points here
return ()
次に、main 内で UI を実行する関数を定義します。
runGui :: IO ()
runGui = startGUI defaultConfig setup
なので、最初はユーザーがクリックした場所に点を描く作業をしていました。これはかなり簡単に実現できPoint x y
ました。ラムダ引数で a をmousedown
作成し、キャンバスに描画しました。私はそれを解決したのでそのコードを省略しています。現在の問題がそれに関連しているとは思いません(つまり、そのラムダのスコープ内でポイントを構築して描画する)。
そのラムダのスコープへのバインドを描画してから破棄する代わりに、Point
そのポイントをリストに保存したいと思います。ユーザーがボタンをクリックしたときにそのリストを読み取れるようにしたいと思います。
私はFRPスタイルについて少し調査をBehaviour
行いましたEvent
(http://hackage.haskell.org/package/threepenny-gui-0.4.2.0/docs/Reactive-Threepenny.html )。これは何かであると理解していますこれは、還元パターンのようなものを作成するのに役立ちますが、私の脳は溶け始めています.
別の StackOverflow の投稿 ( Mixing Threepenny-Gui and StateT ) に基づいて、Threepenny UI イベントに接続してイベント ストリームを作成し、accumB
そのストリームからの各イベントをいくつかの状態動作のストリームに蓄積するために使用することになっていることを収集します。次に、その状態の動作を適用してイベントストリームに戻し、その最終ストリームで観察してUIを更新します(単純だと思います... xD)
少なくともそれが私が集めたものであり、リンクされた StackOverflow の質問への回答でコードをテストし、その特定の質問で提起された問題を解決しました。しかし、イベントストリーム (そのスニペットではカバーされていません) でx y
マウスの位置をキャプチャし、それを使用してストリームを構築する必要があり、それが私が立ち往生している場所です。受け入れられた回答コードを目的に合わせて変更して実装しようとしましたが、ピースがどのように組み合わされるかを明らかに誤解しているため、大量の型エラーが発生しました。mousedown
Point
リンクされたStackOverflowの質問で受け入れられた回答のコードを変更しようとしたのは次のとおりです。
-- This *should* be the bit that converts
-- (x, y) click events to Point x y Event stream
let canvasClick = UI.mousedown canvas
newPointStream = (\(x, y) -> Point x y) <$ (canvasClick)
-- This *should* be the bit that turns the
-- Point x y Event stream into a "behaviour" stream
counter <- accumB (Point 0 0) newPointStream
誰でも光を当てることができますか?私は壁にいます:-(