下面似乎工作......但它似乎很笨拙。
data Point = Point Int Int
data Box = Box Int Int
data Path = Path [Point]
data Text = Text
data Color = Color Int Int Int
data WinPaintContext = WinPaintContext Graphics.Win32.HDC
class CanvasClass vc paint where
drawLine :: vc -> paint -> Point -> Point -> IO ()
drawRect :: vc -> paint -> Box -> IO ()
drawPath :: vc -> paint -> Path -> IO ()
class (CanvasClass vc paint) => TextBasicClass vc paint where
basicDrawText :: vc -> paint -> Point -> String -> IO ()
instance CanvasClass WinPaintContext WinPaint where
drawLine = undefined
drawRect = undefined
drawPath = undefined
instance TextBasicClass WinPaintContext WinPaint where
basicDrawText (WinPaintContext a) = winBasicDrawText a
op :: CanvasClass vc paint => vc -> Box -> IO ()
op canvas _ = do
basicDrawText canvas WinPaint (Point 30 30) "Hi"
open :: IO ()
open = do
makeWindow (Box 300 300) op
winBasicDrawText :: Graphics.Win32.HDC -> WinPaint -> Point -> String -> IO ()
winBasicDrawText hdc _ (Point x y) str = do
Graphics.Win32.setBkMode hdc Graphics.Win32.tRANSPARENT
Graphics.Win32.setTextColor hdc (Graphics.Win32.rgb 255 255 0)
Graphics.Win32.textOut hdc 20 20 str
return ()
windowsOnPaint :: (WinPaintContext -> Box -> IO ()) ->
Graphics.Win32.RECT ->
Graphics.Win32.HDC ->
IO ()
windowsOnPaint f rect hdc = f (WinPaintContext hdc) (Box 30 30)
makeWindow :: Box -> (WinPaintContext -> Box -> IO ()) -> IO ()
makeWindow (Box w h) onPaint =
Graphics.Win32.allocaPAINTSTRUCT $ \ lpps -> do
hwnd <- createWindow w h (wndProc lpps (windowsOnPaint onPaint))
messagePump hwnd
现在,似乎首选的方法就是简单地拥有
data Canvas = Canvas {
drawLine :: Point -> Point -> IO (),
drawRect :: Box -> IO (),
drawPath :: Path -> IO ()
}
hdc2Canvas :: Graphics.Win32.HDC -> Paint -> IO ( Canvas )
hdc2Canvas hdc paint = Canvas { drawLine = winDrawLine hdc paint ... }
然而...
我们喜欢在整个绘图过程中保留颜料并对其进行变异,因为它们的创建和销毁成本很高。绘画可能只是一个像 [bgColor red, fgColor blue, font "Tahoma"] 之类的列表,或者它可能是指向绘画系统使用的内部结构的指针(这是对 windows GDI 的抽象,但最终会抽象在 direct2d 和 coregraphics 上),它们具有“绘制”对象,我不想一遍又一遍地重新创建然后绑定。
在我看来,存在主义的美妙之处在于它们可以不透明地包裹一些东西以抽象它,我们可以将它保存在某个地方,将它拉回来,无论如何。当您部分应用时,我认为存在您部分应用的东西现在“卡在”容器内的问题。这是一个例子。说我有一个像这样的油漆对象
data Paint = Paint {
setFg :: Color -> IO () ,
setBg :: Color -> IO ()
}
我可以在哪里放置指针?当我将 Paint 赋予 Canvas 中的某个函数时,他如何获得指针?设计此 API 的正确方法是什么?