2

2 つのウィンドウを作成し、それらを 2 つの異なるスレッド (ウィンドウごとに 1 つ) で再描画すると、すべての描画が最初に作成されたウィンドウに移動するように見えます。両方のウィンドウに表示されるものを常に切り替えます。そして2つ目はほとんど黒のままです。

コードは 1 つのウィンドウだけでうまく機能していたので、それを更新してcurrentWindow $= Just glWindow、コールバックを設定し、レンダリング メソッドを呼び出す関数の先頭に挿入しました。

問題の原因は何だと思いますか?

編集:

コードの骨組み:

module Chart.Window where

import Graphics.UI.GLUT hiding (Window, postRedisplay, <etc>)
import qualified Graphics.UI.GLUT as GLUT
import qualified Graphics.Rendering.OpenGL as GL

data Window = Window
  { glWindow :: GLUT.Window
  , viewListRef :: IORef [Line]
  }

main = do
  forkOS start <params1>
  forkOS start <params2>

start <params> = do
  win <- new <params>
  run win
  mainLoop

new :: Strict -> (Int, Int) -> (Int, Int) -> IO Window
new name (posx, posy) (w, h) = do
  initGLUT
  glWindow <- createWindow name
  currentWindow $= Just glWindow
  windowSize $= Size (fromIntegral w) (fromIntegral h)
  windowPosition $= Position (fromIntegral posx) (fromIntegral posy)
  return Window {..}

initGLUT :: IO ()
initGLUT = do
  beenInit <- get initState
  unless beenInit $ void getArgsAndInitialize 
  initialDisplayMode $= [WithDepthBuffer, DoubleBuffered, RGBAMode]
  initialWindowSize $= Size 100 100
  initialWindowPosition $= Position 100 100
  actionOnWindowClose $= ContinueExectuion

run :: Window -> IO ()
run win@Window{..} = do
  -- this will fork (with forkIO) threads 
  -- which will call "repaint" when chart needs to be updated
  initListeners repaint 
  initCallbacks win
  where
  repaint :: [Line] -> IO ()
  repaint viewList = do
    writeIORef viewListRef viewList
    postRedisplay win

postRedisplay Window{..} = GLUT.postRedisplay $ Just glWindow

initCallbacks win@Window{..} = do
  currentWindow $= Just glWindow
  GLUT.displayCallback $= display win
  GLUT.idleCallback $= Just (postRedisplay win)

display Window{..} = do
  currentWindow $= Just glWindow
  Size w h <- get windowSize
  viewList <- readIORef viewListRef
  drawChart viewList otherOptions

reshapeCallback :: Window -> GLUT.ReshapeCallback
reshapeCallback win@Window{..} size@(Size w h) = do
  currentWindow $= Just glWindow
  GL.viewport $= (Position 0 0, size)
  GL.matrixMode $= GL.Projection
  GL.loadIdentity
  GL.ortho2D 0 (fromIntegral w) 0 (fromIntegral h)
  GL.matrixMode $= GL.Modelview 0
  GL.loadIdentity
  ... -- send command for listener thread to change internal state and postRedisplay

drawChart viewList otherOptions = do
  ...
  -- chart consists of several horizontal panels. Call this for each panel:
  glViewport 0 panelYPosition width winHeight
  glScissor 0 panelYPosition (fromIntegral width) (fromIntegral panelHeight)
  GL.clear [GL.ColorBuffer]
  ...
  -- and then for each line=(Vertex2 v1 v2) from viewList
  GL.renderPrimitive GL.Lines $ do
    GL.vertex v1
    GL.vertex v2
  ...

ところで、reshapeCallback を設定する行にコメントを付けて (ウィンドウは最初に再形成されます)、ウィンドウを 1 つだけ使用してチャートを起動すると、マルチウィンドウ起動とまったく同じ効果が得られました。つまり、(唯一の)ウィンドウは、2番目に作成されたかのようにほとんど空でした。

4

1 に答える 1

0

同様の問題がありました。私は遺伝的アルゴリズムの反復を計算するスレッドで作業し、各反復で「GL.postRedisplay (Just window)」を呼び出しますが、何も描画しませんでした。

アイドル関数から「GL.postRedisplay (Just window)」を呼び出すことで問題を解決しました。

idle window = CC.threadDelay (1000*500) >> GL.postRedisplay (Just window)

次のようにアイドル コールバック関数を設定することを忘れないでください。

GL.idleCallback GL.$= Just (idle window) >>

CC と GL の意味:

import qualified Control.Concurrent as CC
import qualified Graphics.UI.GLUT as GL
于 2014-05-26T10:46:23.217 に答える