Geflacker trotz double buffering?



  • Naja, wie der threadtitel schon sagt hab ich ein kleines Problem mit meinem Fensterchen. Meine WM_PAINT Message wird folgender maßen behandelt

    case WM_PAINT:
            {
                PAINTSTRUCT ps;
                ps.fErase = 0;
                HDC hdc = BeginPaint(hwnd, &ps);
                HDC hdc2 = CreateCompatibleDC(hdc);
                HBITMAP hbm = CreateCompatibleBitmap(hdc, 400, 216);
                SelectObject(hdc2, hbm);
                for(int i = 0; i < POLY_COUNT; ++i)
                {
                    if(polys[i] != NULL)
                    {
                        HBRUSH brush;
                        if(polys[i]->hasFlag(FLAG_GUESSED))
                        {
                            brush = CreateSolidBrush(RGB(200,200,255));
                        }
                        // hier sind noch nen paar else ifs die aber genauso aus sehn wie das hier drüber...
                        else
                        {
                            brush = CreateSolidBrush(RGB(255,255,255));
                        }
    
                        HPEN pen = CreatePen(PS_SOLID, 2, RGB(0,0,0));
    
                        SelectObject(hdc2, brush);
                        SelectObject(hdc2, pen);
    
                        Polygon(hdc2, polys[i]->poly, polys[i]->polyVertices);
    
                        DeleteObject(brush);
                        DeleteObject(pen);
                    }
                }
                BitBlt(hdc, 0, 0, 400, 216, hdc2, 0, 0, SRCCOPY);
                DeleteObject(hbm);
                DeleteDC(hdc2);
                EndPaint(hwnd, &ps);
                return 0;
            }
    

    Wenn ich nur ein oder wenige Polygone (die sind nicht all zu groß und es sind ca. 70 stk. mit jewels 6 Ecken falls das wichtig is) update fällt es noch nicht auf. Sobald jedoch das ganze Fenster neu gezeichnet werden soll, flackert das Fenster einmal merkbar in weiss auf.

    Muss/Kann ich evtl. an irgend einer zusätzlichen Stelle einstellen, dass der background nie "gecleared" wird?

    Hab ich beim double buffering irgendwas falsch gemacht?



  • Also ich kenn mich mit WinAPI nicht gut aus, mir ist nur grad langweilig 😉

    Aber meine Vermutung: es gibt in deinem Programm wahrscheinlich sehr viele WM_PAINT-Messages. Und da du ja bei jeder WM_PAINT Message das Fenster neu gezeichnet wird, gibts flackern, besonders weil dein WM_PAINT ja relativ lang braucht (es muss immerhin jedes mal den offscreen-buffer neu zeichnen und dann den offscreen-buffer auf den Bildschirm kopieren).

    Deine Polygone scheinen sich aber eh innerhalb von WM_PAINT nicht zu aendern, also: zeichne dir deinen offscreen-buffer anderswo (z. B. bei jeder Aenderung der Polygone) , dann brauchst du innerhalb von WM_PAINT nur noch den offscreen auf den Bildschrim kopieren. Das sollte schneller gehen und damit wahrscheinlich weniger flackern. Oder wenn du's noch weiter optimieren willst: zeichne bei jedem WM_PAINT nur den Teil neu, der auch wirklich neu zu zeichnen ist (da ich mich mit WinAPI nicht auskenne weiss ich nicht, ob das ueberhaupt moeglich ist 😉 ).

    DISCLAIMER: ich hab wie gesagt keine Ahnung von WinAPI, mir ist nur der Threadtitel ins Auge gesprungen... kann also sein dass ich komplett daneben lieg mit meiner Vermutung 😉



  • Auf die Nachricht WM_ERASEBKGND einfach mit { return 1 ;} antworten.
    Es gibt noch andere Möglichkeiten. Guck da: ➡ http://www.catch22.net/tuts/flicker.asp



  • Du kannst Objekte, die im DC selektiert sind, nicht löschen (DeleteObject).
    Daher bekommst Du auch GDI-Leaks...

    MSDN schrieb:

    Return Values
    If the function succeeds, the return value is nonzero.

    If the specified handle is not valid or is currently selected into a DC, the return value is zero.



  • vielen dank, das mit dem WM_ERASEBKGND hat geholfen. Nen paar von den anderen Hinweisen aus dem Link werd ich mir auch noch mal zu herzen nehmen, auch, wenn das Zeichnen des Fensters jetzt schon recht fix geht...

    wegen den GDI leaks, was kann ich da tun?
    und warum wurde der beitrag zum double buffer im faq dann noch nicht angepasst?



  • Blue-Tiger schrieb:

    [...]
    Aber meine Vermutung: es gibt in deinem Programm wahrscheinlich sehr viele WM_PAINT-Messages. Und da du ja bei jeder WM_PAINT Message das Fenster neu gezeichnet wird, gibts flackern, besonders weil dein WM_PAINT ja relativ lang braucht (es muss immerhin jedes mal den offscreen-buffer neu zeichnen und dann den offscreen-buffer auf den Bildschirm kopieren).
    [...]

    Nop das kann nicht sein, da das flackern nur entsteht, wenn der Bildschirminhalt, sprich der DC, der
    über BeginPaint(...) ermittelt wurde, neu gezeichnet wird und dies in geringen Zeitabständen sehr oft
    geschieht. Den 'offscreen-buffer' (eigentlich: Back-Buffer^^) kannste so oft wie du willst 'bemalen';
    Davon wird nix flackern. 😉

    Du kannst Objekte, die im DC selektiert sind, nicht löschen (DeleteObject).
    Daher bekommst Du auch GDI-Leaks...
    [...]

    Genau! 💡 Das würd ich persönlich so lösen:

    HDC hdcDest = ...;
    HPEN hpOldPen = reinterpret_cast<HPEN>(SelectObject(hdcDest, CreatePen(...));
    // ...
    // Hier kannste dann in hdcDest mit dem erstellten 'Pen' rumalen ...
    // ...
    DeleteObject(SelectObject(hdcDest, hpOldPen));
    


  • [edit] ähm, zu langsam... [/edit]

    Wenn du einen DC erstellst (zB. mit CreateDC( )) enthält dieser einen Satz von default-Objekten für Brush, Palette, Font, Pen und Region. Wenn du diese default-Objecte mit SelectObject( sonstwas ) ersetzt, sind diese nicht mehr zugreifbar -> GDI-Leak. Die default-Objekte werden bei einem DeleteDC( ) automatisch gelöscht.

    Abhilfe:

    HDC dc = CreateDC( "DISPLAY", 0, 0, 0 );
    
    HBRUSH old_brush = reinterpret_cast< HBRUSH >( SelectObject( CreateSolidBrush( RGB( 0xff, 0xff, 0 ) ) ) );
    
    // do some painting with the selected brush...
    
    DeleteObject( SelectObject( old_brush ) );
    DeleteDC( dc );
    

    Greetz, Swordfish



  • Hähä, doppelt gemoppelt hält ja bekanntlich immer besser 😃

    EDIT: @Swordfish: Haste jetzt die neue I-Net Leitung ( ➡ ICQ) ?



  • nö, leider noch nicht.

    Greetz, Swordfish



  • ok vielen Dank für eure Hilfe.

    Jetzt funzt alles perfekt, genau so hatte ich mir das vorgestellt 😃


Anmelden zum Antworten