2015-11-12 2 views
9

Ich schreibe ein Haskell-Programm mit Click-and-Drag-Funktionalität, so dass bei jedem Mausbewegungsereignis ein Update auf das Fenster gemalt wird. Im Moment verwende ichWas ist der richtige Weg, um Cairo Updates in Gtk2hs zu rendern?

renderWithDrawable myCanvas update 

Allerdings flimmert dies sehr. Mein Verständnis ist, dass ich eine separate zeichnende (eine "Oberfläche"?) Verursachen muss, zu ihr rendern, und dann sie in einer einzelnen Operation auf das Bildschirmfenster blit. Allerdings bin ich verwirrt über den richtigen Weg, dies zu tun.

Ich habe drawWindowBeginPaintRegion gefunden, die über die Beseitigung von Flimmern spricht. Es ist jedoch in Gtk3 gemäß der Haddock-Dokumente entfernt. Also bin ich mir nicht sicher, ob ich das verwenden soll, da es veraltet zu sein scheint.

Ich habe auch renderWithSimilarSurface in Kairo gefunden, die etwas ähnliches zu tun scheint.

Ich bin mir auch nicht sicher, wie diese Funktionen zu renderWithDrawable beziehen: muss ich sie in dieser Funktion verwenden, oder was?

Was ist der richtige Weg?

bearbeiten

Dies scheint eine bekannte Sache, in Kairo zu sein. Ich versuche herauszufinden, wie ich das in Haskell handhaben soll.

+0

Können Sie ein minimales eigenständiges Beispiel veröffentlichen? – Cactus

+0

@Cactus, nicht leicht. Eine Demo des Flicker-Problems würde eine Art Animations- oder Maus-Event-Handler benötigen, um wiederholtes Neuzeichnen durchzuführen, so dass es nicht zu klein wird. Auch der Grad des Flackerns scheint mit der Plattform zu variieren. Stattdessen aktualisiere ich den Beitrag mit Hinweisen zu Diskussionen über das Thema in anderen Sprachen.Das Zeichnen auf eine PixMap und das Blitting auf den Bildschirm scheinen in anderen Sprachen Standard zu sein, also hoffte ich, dass es in Haskell eine kanonische Methode dafür gibt. –

+2

Sie können sich die Funktion 'clip' anschauen. Dadurch können Sie nur das neu Zeichnen, was Sie benötigen (in Ihrem Fall das ursprüngliche Rechteck (alte Position) des gezogenen Objekts und sein neues Rechteck (neue Position)). – antoyo

Antwort

4

Der richtige Weg, dies zu tun ist, um sicherzustellen, dass alle Ihre Zeichnung von innen kommt Ereignisse aussetzen, und arbeitet auf der Auslosung Fenster durch den Fall vorgesehen, . Sie können eine Region als "schmutzig" markieren und ein synthetisches Exposure-Ereignis mit drawWindowInvalidateRect, drawWindowInvalidateRegion oder widgetQueueDraw auslösen.

Es folgt ein schnelles Beispiel für das Einrichten der Zeichnungspipeline. Es ist aus einem benutzerdefinierten Viewport Typ, der Google-Maps-Stil Schwenken mit glatten Bewegungen bei Drag-and-Release-Operationen, die ich für ein Side-Projekt vor einiger Zeit gebaut hat. Um dies zu unterstützen, muss es bei Mausbewegungsereignissen neu gezeichnet werden, sodass es einen ähnlichen Anwendungsfall wie das beschriebene Problem behandelt. Ich habe irrelevante Sachen mit ... ausgeklammert, um die wichtigen Bits hervorzuheben. Ich habe gerade das komplette Projekt auf github hochgeladen, so dass Sie das Repo durchsuchen können, um die vollständigen Details von Viewport zu sehen. (Es ist Jahre her, aber, so gibt es wahrscheinlich ein gutes Stück von bitrot - nicht erwarten, das Projekt nur mit modernen GHCs/Pakete zu bauen und zu betreiben.)

viewportNew :: Viewport -> IO DrawingArea 
viewportNew v = do 
    da <- drawingAreaNew 
    -- ... 
    on da exposeEvent $ exposeViewport posRef (draw v) 
    -- ... 

exposeViewport :: IORef Position -> RegionRenderer -> EventM EExpose Bool 
exposeViewport posRef draw = do 
    dw  <- eventWindow 
    region <- eventRegion >>= liftIO . regionGetRectangles 
    -- ... 
    liftIO . renderWithDrawable dw $ do 
     -- Cairo() action goes here 
     -- can reference region to decide which things to draw 
     draw region 
    return True -- see documentation of exposeEvent for what this means 

Diese Vorlage sollte Vorteil der integrierten des gtk nehmen in Doppelpufferung und arbeiten mit den gtk und gtk3 Paketen.

+0

Danke. Ich werde es versuchen, und wenn es funktioniert, werde ich dies als akzeptiert markieren. –

Verwandte Themen