GDI Problem --> InvalidateRect



  • Hallo Leute

    Zur Zeit programmiere ich gerade einen kleinen Timer. Die Zeit wird dabei im digitalen Format als t-Segment Tiffern ins Anwendungsfenster gezeichnet. Die einzelnen segmente werden mit der GDI-Funktion Polygon gezeichnet. Ich habe ein timer, welcher jede Sekunde einw WM_TIMER Message auslöst.
    Am Anfang habe ich einfach jede Sekunde das gesamte Fenster mit der Funktion InvalidateRect ungültig gemacht. Der dritte Parameter dieser Funktion habe ich TRUE gesetzt, also wurde der Background immer gelöscht und neu gezeichnet. So funtionierte eigentlich alles mit einer kleinen Unschönheit, nämlich die, das die Fensterausgabe flackerte, da ich ja immer die hanze Zeit neu gezeichnet habe.
    Um diese Problem zu beheben habe ich eine Logik entwickelt, welche nur die Segmente löscht welche ich nicht mehr brauche und die Segmente zeichnet, welche neu gebraucht werden. Jetzt darf ich aber ja der Hintergrund nicht einfach löschen, weil sonst die alte Zeit ja auch gelöst wird, also habe ich den dritten Parameter der Funktion InvalidateRect auf False gesetzt, damit das nicht passiert. Nun das funktionier jetzt eigentlich ganz gut.
    ABER: Ich habe jetzt das Problem, dass wenn meine Anwendung im Hintergrund war oder von einem anderen Fenster ganz oder teilweise ünerlagert wurde, dass dann diese Region jeweils meine Zeit nacher gelöst ist. Daselbe passiert auch, wenn ein Menu meiner eigenen Anwendung aufgerufen wird. Das kann ich natürlich nicht so auf sich belassen, wie ihr sicher verstehen könnt.

    mfg

    Sputnik



  • Du setzt InvalidateRect wieder auf TRUE und gibst bei WM_ERASEBKND return 0; zurück.



  • oder nimm einfach nen BackBuffer 😉



  • Vielen Dank. Ich werde mal diesen Beiden Varianten nachgehen und dann posten, was sich so ergeben hat.

    mfg

    Sputnik



  • also zum Backbuffer, oder auch Doublebuffer hab ich in nem anderen Thread mal was feines verfasst.
    da ich jetzt nicht alles nochmal schreiben will, hier der Link:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-189381-and-highlight-is-.html

    vielleicht hilfts dir ja

    MfG DrakoXP

    PS.: das ganze funzt auch, wenn man bei InvalidateRect nur einen Teil des Fensters angibt.
    dann wird eben auch nur dieses Rechteck neugezeichnet.
    alles natürlich Flackerfrei 😃



  • Hmm, ich wollte mal die Möglichkeit mit dem Buffering ausprobieren, aber leider hatte ich nicht so richtig erfolg dabei. Jetzt wird gar nix mer gezeichnet, ausser dem Hintergrund. Das heisst, es werden überhaupt keine grünen Digits mehr gezeichnet.

    Hier mein Listing der WM_PAINT:

    case WM_PAINT:
        /* create a devise context */
        hDC = BeginPaint(hWnd, &ps);
    
        /* set the mapping mode as defined from the menu */
        if(bIsotropic)
            /* set the mapping mode to isotropic */
            SetMapMode(hDC, MM_ISOTROPIC);
        else
            /* set the mapping mode to anisotropic */
            SetMapMode(hDC, MM_ANISOTROPIC);
    
        /* set the logical coordinate system of the window */
        SetWindowExtEx(hDC, 276, 72, NULL);
        SetViewportExtEx(hDC, iCXClient, iCYClient, NULL);
    
        /* set the origin of the coordinate system in the window */
        SetWindowOrgEx(hDC, 138, 36, NULL);
        /* set the origin of the coordinate system in the viewport */
        SetViewportOrgEx(hDC, iCXClient / 2, iCYClient / 2, NULL);
    
        /* load the pen to the devise context */
        SelectObject(hDC, GetStockObject(NULL_PEN));
        /* load the brush for digits to the devise contex */
        SelectObject(hDC, GetHandleToBrush(rgbDigits));
    
        /* create a buffer for the window outbut */
        HDC hDC2 = CreateCompatibleDC(hDC);
        HBITMAP hBM = CreateCompatibleBitmap(hDC, iCXClient, iCYClient);
    
        SelectObject(hDC2, hBM);
    
        /* print the time */
        if(bRedrawAll)
        {
            /* print the time complete new */
            DPrintFullTime(hDC2);
            bRedrawAll = FALSE;
        }
        else
        {
            /* print only the digits who has changed */
            DPrintFragTime(hDC2);
        }
    
        /* load the buffer to the window outbut */
        BitBlt(hDC, 0, 0, iCXClient, iCYClient, hDC2, 0, 0, SRCCOPY);
    
        /* cleaning up the objects */
        DeleteObject(hBM);          /* delet the bitmap buffer */
        DeleteDC(hDC2);             /* delet the devise context buffer */
    
        /* end painting and release the devise context */
        EndPaint(hWnd, &ps);
    return(0);
    

    Kann mir jemand sagen, an was das liegt?

    mfg

    Sputnik



  • looool, devise - outbut und diesen Fehler ständig, göul ^^

    wie erzwingst du den das WM_PAINT jede Sekunde ?



  • Ich starte am Anfang ein Timer, welcher mir jede Sekunde ein WM_TIMER schickt, in wechler ich dann mit der Funktion InvalidateRect das das gesamte Fenster ungültig mache.

    Was ist mit der devise und output? Sich nur darüber lustig zu machen bringt mir nichts.

    mfg

    Sputnik



  • die Schreibweise, es schreibt sich: device

    Ich wollte wissen, wie du die WM_PAINT Message erzwingst?



  • Du musst Deine Modifikationen (SetWindowOrgEx, SetMapMode, etc) auch für den BackBuffer durchführen.

    BTW:
    delet -> to delete
    devise -> device
    outbut -> output
    😉

    PS: Da fehlt ein SelectObject am Ende. Du musst den ehemaligen Inhalt des BackBuffer-DC's auch wiederherstellen.



  • @CodeFinder:
    Ich verstehe nicht so ganz, was muss ich wie wieder herstellen?



  • hast du dir eig mal meinen Post angeguckt?

    im Gegensatz zu deiner Version funzt meins nähmlich 👍



  • @DrakoXP
    Ich habe mir dein Post mal angeschaut, aber ich finde das ein wenig aufwendig für mein Problem.

    @all
    Mein Problem ist ja nicht das Flackern, das habe ich ja behoben. Mein Problem ist, dass mein Fenster-Inhalt nicht wiederhergestellt wird, wenn mein Fenster von einem Anderen Fenster überlager wurde. Ich denke nicht, dass ich da ein BackBuffer brauche, sondern ich will einfach, dass es wieder hergestellt wird. Das ist also mein eigentliches Problem.

    mfg

    Sputnik



  • Als ich noch WinAPI-Nutzer war hab ich den Backbuffer nur bei Programmstart und bei Änderung der Fenstergröße neu angelegt (Du machst das zur Zeit bei jedem WM_PAINT?) - Vor allem das Erzeugen der Backbuffer-Bitmap kann je nach Fenstergröße sonst zum Flaschenhals werden.
    Abgesehen davon bleibt dir dann bis zu einem Resize alles vorher gezeichnete erhalten.

    Wenn du das auslagerst kannst du dir das DPrintFragTime() vermutlich sparen, es sei denn es ist aus Geschwindigkeitsgründen nötig 😉

    Ab WinXP bietet Windows auch WS_EX_COMPOSITED an:

    msdn - CreateWindowEx schrieb:

    WS_EX_COMPOSITED
    Windows XP: Paints all descendants of a window in bottom-to-top painting order using double-buffering. For more information, see Remarks. This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC.



  • Sputnik schrieb:

    @CodeFinder:
    Ich verstehe nicht so ganz, was muss ich wie wieder herstellen?

    Beispiel:

    HBITMAP hbmpOldBits = reinterpret_cast<HBITMAP>(SelectObject(hdcBackBuffer, CreateCompatibleBitmap(...)));
    // ... hier mit hdcBackBuffer arbeiten ...
    DeleteObject(SelectObject(hdcBackBuffer, hbmpOldBits);
    DeleteDC(hdcBackBuffer);
    

    👍


Anmelden zum Antworten