Für GDI+ HDC nur für Teil eines Fensters Fensters?



  • Ich habe vor kurzem mal angefangen, mit der GDI+ zu arbeiten. Mit BeginPaint kann man sich ja einen Device Content Handle für ein Fenster schaffen. Bei mir ist es aber nun abzusehen, dass ich nur in einen Teil des Fenster zeichnen werde. Es wäre also praktischer, wenn ich den HDC nur für einen Teil des Fensters schaffen könnte, denn das würde die Positionsangaben sehr erleichtern.

    Ist da in die Richtung was möglich?



  • Naja du kannst den DC von einer Bitmap mit der entsprechenden Größe holen und die Bitmap dann am Ende einfach auf deinen normalen DC malen ... sollte eigentlich gehen.



  • Gibt es denn da wirklich nichts eigens dafür vorgesehenes? Das finde ich schwer vorstellbar, denn es ist doch bestimmt nicht so selten, dass man seie Objekte nicht anhand der Fensterdimensionen positionieren will.



  • Hmm in wie weit soll das überhaupt die Positionsangabe erleichtern? Und doch normal orientiert man sich an einem RECT und arbeitet damit ... dann kannst du auch auf vergrößerungen/verkleinerungen deines Fensters reagieren usw.



  • Und wo ist eig. das Problem?

    // HDC oder der gleichen als Ausgangspunkt.
    Gdiplus::Graphics graphic_wnd(hDC);
    Gdiplus::Bitmap* pBitmap = new Gdiplus::Bitmap(100, 200);
    Gdiplus::Graphics* pGraphic = new Gdiplus::Graphics::FromImage(pBitmap);
    // pGraphic nutzen
    delete pGraphic;
    graphic_wnd.DrawImage(pBitmap, 0, 0); // oder halt anstelle der Nullen einfach die Position für die komplette Grafik angeben.
    delete pBitmap;
    

    So wäre das mit dem Weg über ne Bitmap ...

    Edit
    Achja ... am besten ist es, da du ja nicht auf irgendwas reagierst, die Bitmap dann nur am Anfang einmal zu erstellen und zu bemahlen und dann im Zeichenvorgang immer nur die Bitmap drauf zeichnen.



  • Wie gesagt, ich bin absoluter Anfänger, was die GDI angeht.

    Wenn es dir nicht zu viel Arbeit ist, könntest du dann mal kurz erläutern, wie du deine Methode mit dem Rect meinst?



  • Naja du gehst halt hin und holst dir das RECT vom Fenster ... und dazu passend auch den Device bzw das Graphic Objekt per HDC ... so ... dann gehst du halt hin und passt dir das Rect so an das du nur den Bereich hast und gehst davon dann immer aus:

    Gdiplus::Graphics graphic_wnd(hDC);
    RECT rect;
    GetClientRect(hWnd, &rect);
    
    // Beispiel
    rect.left += 40;
    rect.top += 40;
    rect.bottom -= 120;
    rect.right -= 20;
    

    so damit hast du dir den Bereich festgelegt ... und das Graphic-Objekt geholt. Jetzt nimmst du bei der X Koordinate halt immer rect.right oder rect.left und bei der Y Koordinate immer rect.top und rect.bottom wenn de was zeichnen willst.



  • Stimmt, das geht wohl so. Bis jetzt hatte ich es einfach vor jegliche Draws mit dem Graphics-Objekt eine Translation vorangestellt, die von der oberen linken Ecke des Fensters entsprechend verschiebt.

    Aber was mir gerade noch in den Sinn gekommen ist: Gibt es irgendwie eine Beschränkung, wie oft man pro verarbeiteter Message BeginDraw und EndDraw ausführen darf? Denn ich habe hier gerade folgendes gemacht:

    void Anzeige::Zeichnen(HWND hwnd) {
        PAINTSTRUCT ps;
        HDC hdc;
        hdc = BeginPaint(hwnd, &ps);
        Graphics graphics(hdc);
        /*Zeichenoperationen...*/
        EndPaint(hwnd, &ps);
        EinzelteilZeichnen(hwnd);
    }
    
    void Anzeige::EinzelteilZeichnen(HWND hwnd) {
        PAINTSTRUCT ps;
        HDC hdc;
        hdc = BeginPaint(hwnd, &ps);
        Graphics graphics(hdc);
        /*Zeichenoperationen...*/
        EndPaint(hwnd, &ps);
    }
    

    Aber dabei wird alles, was in der zweiten Funktion gezeichnet werden sollte, einfach unterschlagen und taucht nicht auf. Müsste man da irgendwas beachten?



  • void Display::draw(HWND hWnd) 
    {
        PAINTSTRUCT ps;
        HDC hDC = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);
    
        Gdiplus::Graphics graphics(hDC);
        // Double Buffering ...
        Gdiplus::Bitmap* pMemBitmap = new Gdiplus::Bitmap(rect.right - rect.left, rect.bottom - rect.top);
        Gdiplus::Graphics* pMemGraphics = new Gdiplus::Graphics::FromImage(pMemBitmap);
        // Ab hier kannst du mit pMemGraphics zeichnen!
    
        draw_items(pMemGraphics);
        delete pMemGraphics;
        graphics.DrawImage(pMemBitmap, 0, 0);
        delete pMemBitmap;
    
        EndPaint(hWnd, &ps);
    }
    
    void Display::draw_items(Gdiplus::Graphics* graphics) 
    {
        graphics->DrawRectangle(...); // oder so was in der art ^^
    }
    

    ... so würde ich es machen ... ich würde eigentlich sogar noch einen Schritt weiter gehen und das pMemGraphics und das pMemBitmap Objekt als Memebervariablen anlegen und dann bei WM_SIZE nur neu erstellen ... damit sparst du Zeit beim Zeichnen und verhinderst gleichzeitig noch das Flickern durchs Double Buffering.



  • Also, so wie ich das verstehe (ohne viel Vorkenntnis), wird vom Graphics-Objekt zuerst alles in das Bild geschrieben, und das dann auf einen Schlag sichtbar gemacht, richtig? Ist diese Methode denn auch nützlich, wenn ich überhaupt nicht mit Bildern irgendeiner Art arbeite, mal abgesehen davon, dass sie Flackern unterdrückt (wobei ich jetzt weder sehr anspruchsvolle Sachen zeichne, noch das Fenster in der Größe veränderbar ist).

    Ansonsten gebe ich mich auch hiermit zufrieden. Bin nur nach wie vor geschockt, wie umständlich so was einfaches wie ein Teil eines Fensters auszuwählen sein kann. Dafür hatte ich sogar eine Funktion erwartet. 😉

    Achja, eins noch: Wo genau liegt denn der Unterschied, ob man die Methode FromImage oder den Konstruktor, der ein Bild einliest, benutzt? Beziehungsweise, wieso sind die beiden Objekte Graphics und Bitmap überhaupt dynamisch allokiert? Würde es nicht ausreichen, wenn sie nach Ende der Funktion einfach Out-of-Scope gehen würden?



  • hmm hab gerade nicht die Konstruktor alle im Kopf ... aber ich nutz das halt oft in Kombination mit Membervariable und kann nur so dann das Resizen bzw neuerstellen des Objektes bewirken ...



  • Okay, eine Frage noch. 😉

    Was hat es mit dem Double Buffering auf sich? Mir ist klar was das ist, aber wieso wird das gerade bei dieser Umsetzung erzeugt?



  • Hmm nicht nur bei dieser Umsetzung. Bei jeder! Wenn de es vollständig optimierst, verringert es die Zeit die zum Zeichnen brauchst und verhindert Flackern usw.


Anmelden zum Antworten