GDI+ - Löschen von gezeichnet Objekten



  • Hallo,
    ich bin gerade dabei mit der GDI+ ein paar Objekte in Fenster zu zeichnen. Das funktioniert ja auch wunderbar.

    aber kann man die Objekte irgendwie einzeln wieder löschen? oder vielleicht nur einen Teil des Fensters neu zeichnen?

    denn wenn ich zB mit InvalidateRect() das gesamte Fenster neu zeichne werden ja alle gezeichneten objekte gelöscht. Kann man also irgendwie nur einen Teil eines Fenster neu zeichnen oder gdi-objakte sogar mit irgendeinem befehl löschen? oder unsichtbar machen würde ja reichen^^

    danke schonmal,
    andi01.



  • ich hab so dass gefühl dass man im zweiten parameter von InvalidateRect ein Rect Objekt angeben kann wenn man es nicht tut wird alles gelöscht sonst nur dass RECT object



  • danke, ich werde das mal testen 🙂

    mfg,
    andi01.



  • also ich habe es jetzt auf verschiedene Arten mit deiesem Code probiert:

    #include <windows.h>  
    #include <gdiplus.h>  
    #include<conio.h>
    #include<iostream>
    #pragma comment(lib, "gdiplus.lib")
    #include<wchar.h>
    
    using namespace Gdiplus;
    using namespace std;
    
    HDC hdc=GetWindowDC(FindWindow(NULL, L"Unbenannt - Editor"));
    
    void rechteck(int x, int y, int width, int length)
    {
    	Graphics graphics(hdc);
    	Rect rect(x, y, width, length);
    	Pen pen(Color(255, 255, 0, 0), 1);
    	graphics.DrawRectangle(&pen, rect);
    }
    
    int main() 
    { 
    	for(;;)
    	{
    	system("cls");
       GdiplusStartupInput gdiplusStartupInput; 
       ULONG_PTR           gdiplusToken;   
       GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
       //...
       system("PAUSE");
       cout<<"zeichne rechteck 1\n";
       rechteck(50, 50, 10, 10);
       Sleep(2000);
       rechteck(10, 10, 10, 10);
       cout<<"zeichne rechteck 2\n";
       Sleep(2000);
       RECT rect;
       rect.left=50;
       rect.top=50;
       rect.right=600;
       rect.bottom=600;
       bool success=InvalidateRect(FindWindow(NULL, L"Unbenannt - Editor"), /*&rect*/NULL, FALSE);
       if(success==true)
       {
    	   cout<<"rect successfull invalidated\n";
       }
       if(success==false)
       {
    	   cout<<"error while trying to invalidate rect\n";
       }
       Sleep(2000);
       // ... 
       GdiplusShutdown(gdiplusToken);
    	}
    }
    

    zuerst habe ich es in Notepad getestet:

    -wenn ich in Zeile 46 meines Codes NULL statt &rect schreibe wird natürlich einfach die gesamte textbox von notepad neu gezeichnet, klar.
    -wenn ich jetzt aber in Z.46 statt NULL mein Rechteck (&rect) angebe, wird dieses leider nicht neu gezeichnet sondern es passiert gar nichts.

    woran liegt das? das Rechteck wurde doch korrekt erstellt und übergeben 😕

    dann habe ich es noch am desktop getestet: dort funktioniert leider keine der beiden Möglichkeiten 😞

    was ist an dem codebeispiel denn falsch? als Rückgabewert von invalidateRect() erhalte ich nämlich immer true, also erfolgreich, eigentlich müsste es gehen.´

    danke schonmal,
    andi01.



  • weiß jetzt nicht direkt woran dass liegen könnte aber es kann sein dass das notepad garnicht auf deine Nachricht reagiert oder einfach nur dass fenster neuzeichnet hast du dass auch mal bei einem von dir geschriebenem Programm ausprobiert?
    ansonsten dieh dir mal dass an:
    http://www.cpp-tutor.de/mfc/mfc/kap2/_intern/invrect.htm



  • also mein eigenes Programm (ich habe einfach mal die Konsolenanwendung genommen) reagiert zwar auf Invalidate Rect, aber nicht so wie es sollte:

    hier mal ein screen: http://rapidshare.de/files/48973845/fehler.bmp.html

    eigentlich sollte nämlich das 2.(untere) rechteck laut code komplett gelöscht werden und nicht nur teilweise! im code wurden nämlich für das zu löschende RECT genau dieselben Koordinaten angegeben wie für das gezeichnete!

    hier nochmal nur der relevante(veränderte) codeausschnitt, der Rest ist gleich geblieben:

    system("PAUSE");
       cout<<"zeichne rechteck 1\n";
       rechteck(80, 80, 30, 30);
       Sleep(2000);
       rechteck(110, 110, 110, 110);
       cout<<"zeichne rechteck 2\n";
       Sleep(2000);
       RECT rect;//=new RECT();
       rect.left=110;
       rect.top=110;
       rect.right=220;
       rect.bottom=220;
       bool success=InvalidateRect(GetConsoleWindow(), &rect /*NULL*/, FALSE);
       if(success==true)
       {
    	   cout<<"rect successfull invalidated\n";
       }
       if(success==false)
       {
    	   cout<<"error while trying to invalidate rect\n";
       }
    

    irgendwie tut InvalidateRect() nicht das was es soll, immerhin wird der falsche bereichn gelöscht 😞

    woran liegt das und was kann ich verbessern?

    danke schonmal,
    andi01.



  • sieh mal nach ob sich wenn du denn rect veränderst auch der übermalte Bereich ändert vielleicht hat dass was damit zu tun dass du in der Console arbeitest
    ....
    initialisierst du dein Graghics auch mit GetConsoleWindow()?



  • klg71 schrieb:

    sieh mal nach ob sich wenn du denn rect veränderst auch der übermalte Bereich ändert

    ja, tut er.

    klg71 schrieb:

    vielleicht hat dass was damit zu tun dass du in der Console arbeitest

    das wäre aber sowieso nicht so wichtig da ich eigentlich die grafik am desktop machen will^^das mit der Konsole war nur zu testzwecken weil es in editor gar nicht ging und ich den code prüfen wollte.

    klg71 schrieb:

    initialisierst du dein Graghics auch mit GetConsoleWindow()?

    ja.

    mfg,
    andi01.



  • und wann übermalt der bereich genau dein 2. Rechteck? Bei welchem Rect?



  • also:

    bei diesem codeabschnitt wird rechteck 2 gezeichnet:

    rechteck(110, 110, 110, 110);
     cout<<"zeichne rechteck 2\n";
    

    und zwar so, dass die Koordinaten der oberen linken Ecke (110/110) sind; das rechteck ist 110 breit und 110 hoch, damit sind die Koordinaten der unteren rechten Ecke (220/220).

    und mit diesem Codeteil hier soll Rechteck 2 durch neuzeichnen des entsprechenden Fensterteils gelöscht werden:

    RECT rect;//=new RECT();
       rect.left=110;
       rect.top=110;
       rect.right=220;
       rect.bottom=220;
       bool success=InvalidateRect(GetConsoleWindow(), &rect /*NULL*/, FALSE);
    

    hier wird das fenster im bereich des neu erstelten rechtecks neu gezeichnet. die Koordinaten der oberen linken Ecke des neuen Rechtecks sind (110/110), die Koordinaten der unteren rechten Ecke des neuen Rechtecks sind (220/220);

    --> Die Eckpunkte der Rechtecke sind gleich:
    Rechteck1: oben links: (110/110), unten rechts: (220/220);
    Rechteck2: oben links: (110/110), unten rechts: (220/220);

    -->gleiche Position beider Rechtecke

    --> das Rechteck für InvalidateRect() (das war auch mit RECT gemeint 😉 ) sollte eigentlich das 2. gezeichnete Rechteck (oberer Codeausschnitt) überschreiben!

    meine Frage war jetzt, da beide Rechtecke dieselbe Position haben, warum wird Rechteck 2 nicht vollständig überschrieben sondern nur teilweise?

    EDIT: aber wie schon oben erwähnt, dass es in der Konsolenanwendung nicht geht wäre mir ja gar nicht soo wichtig da ich es eh in win-forms fenstern bzw. am desktop machen will.

    die viel interessantere Frage ist deshalb warum es bei notepad mit InvalidateRect() nur teilweise geht:

    das geht leider gar nicht(es passiert einfach nichts 😞 ):

    RECT rect;//=new RECT();
    rect.left=110;
    rect.top=110;
    rect.right=220;
    rect.bottom=220;
    
    InvalidateRect(GetConsoleWindow(), &rect , FALSE);
    

    und das hier geht zwar, d.h. InvalidateRect() wird nicht ignoriert, aber es wird eben das ganze Fenster neu gezeichnet:

    InvalidateRect(GetConsoleWindow(), NULL, FALSE);
    

    mfg,
    andi01.



  • Also zeichen mal was auf den Desktop und probiere dasselbe nur mit GetDesktopWindow() als HDC und probiere da mal invalidateRect:)



  • Euch ist aber schon klar, dass der letzte Parameter von InvalidateRect() TRUE sein muss, damit der Hintergrund gelöscht wird? Außerdem führt InvalidateRect() nicht direkt zum Neuzeichnen, sondern kennzeichnet den angegebenen Bereich nur als "Neuzeichnungsbedürftig". Mit einem nachfolgenden Sleep() blockiert Ihr die MessageLoop, so dass das Neuzeichnen vorerst nicht durchgeführt werden kann. In einem solchen Fall kann man das Neuzeichnen erzwingen mit UpdateWindow().



  • By the way: seine eigenen Maloperationen baut man üblicherweise in die Behandlung von WM_PAINT ein.



  • man muss kein true nehmen der hdc wird auch so gelöscht nur wird bei true der hdc wieder neu gezeichnet und bei false nicht:) und in der Consolenanwendung lässt sich nur mit viel Aufwand ein WM_PAINT reinquetschen:)



  • Lies die Dokumentation.



  • steht da so drin:

    Wenn bErase auf TRUE gesetzt wird, wird beim Aufruf von BeginPaint(...) der Fensterhintergrund neu gezeichnet.

    außerdem hat man an dem Bild dass er hochgeladen hat gesehen dass es dass gezeichnete löscht:) schonmal angesehen und dass war garnicht unser prob sonder will er dass auf nem Desktop oder Notepad bewerkstelligen



  • Sag ich doch: TRUE ...

    Natürlich kann es sein, dass eine Applikation in der WM_PAINT den Hintergrund immer löscht, egal ob es angefordert wurde oder nicht. Aber verlassen kannst Du Dich darauf nicht!



  • gut ok mein fehler:D



  • ok, ich werde es jetzt mal mit TRUE als Parameter und UpdateWindow() danach versuchen und euch das Ergebnis mitteilen.

    bg,
    andi01.



  • also: am desktop habe die Veränderungen leider gar nix gebracht,er reagiert weder auf InvalidateRect() noch auf UpdateWindow() noch auf eine Kombination aus beidem, egal ob das parentsprechende Parameter bei InvalidateRect() TRUE oder FALSE ist 😞 .

    In editor ist es mit InvalidateRect() genau wie in der Konsole.

    hier nochmal ein screen wie das in editor aussieht: http://rapidshare.de/files/48980071/fehler.bmp.html

    dadurch ergebn sich jetzt 2 grundlegendes Fragen:

    1.wie man anhand meines vorletzten Beitrags hoffentlich nachvollziehen kann sind die Koordinaten und die Positionen des 2. gezeichneten Rechteck und des Rechtecks, das an invalidateRect() übergeben wird genau gleich! warum wird also das gezeichnete Rechteck nicht vollständig gelöscht?

    muss/kann ich die Koordinaten dann irgendwie umrechnen?

    2.Da es am Desktop gar nicht geht:

    a)insofern der code nicht falsch ist, gibt es noch eine andere Möglichkeit einen Fensterteil neu zu zeichnen?
    b)oder kann ich den desktop irgendwie dazu bringen auf InvalidateRect zu reagieren (zB durch éinstellungen oder andere api-funktionen)?

    um die Möglichkeit auszuschließen, dass mein Code falsch ist, hier nochmal der (diesmal komplette) Code:

    // Rechteckrotation mit bzw ohne radius.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    
    #include <windows.h>  // für die GDI+ wird auch windows.h benötigt 
    #include <gdiplus.h>  // dieser Header ist für alle GDI+ Klassen, Funktionen usw. 
    #include<conio.h>
    #include<cmath>
    #include<iostream>
    #include<string>
    #include<sstream>
    #pragma comment(lib, "gdiplus.lib")
    #include<wchar.h>
    
    using namespace Gdiplus; // 01 
    using namespace std;
    
    HDC hdc=GetWindowDC(FindWindow(NULL, L"Unbenannt - Editor"));//=GetWindowDC(FindWindow(NULL, L"Unbenannt - Editor"));
    
    void rechteck(int x, int y, int width, int length)
    {
    	Graphics graphics(hdc);
    	Rect rect(x, y, width, length);
    	Pen pen(Color(255, 255, 0, 0), 1);
    	graphics.DrawRectangle(&pen, rect);
    }
    
    int main() 
    { 
    	for(;;)
    	{
    	system("cls");
       GdiplusStartupInput gdiplusStartupInput; 
       ULONG_PTR           gdiplusToken;   
       GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // 02 
       //...
       system("PAUSE");
       cout<<"zeichne rechteck 1\n";
       rechteck(80, 80, 30, 30);
       Sleep(2000);
       rechteck(110, 110, 110, 110);
       cout<<"zeichne rechteck 2\n";
       Sleep(2000);
       RECT rect;//=new RECT();
       rect.left=110;
       rect.top=110;
       rect.right=220;
       rect.bottom=220;
       bool success=InvalidateRect(FindWindow(NULL, L"Unbenannt - Editor"), &rect /*NULL*/, TRUE);
       if(success==true)
       {
    	   cout<<"rect successfull invalidated\n";
       }
       if(success==false)
       {
    	   cout<<"error while trying to invalidate rect\n";
       }
       bool update_success=UpdateWindow(FindWindow(NULL, L"Unbenannt - Editor"));
       if(update_success==true)
       {
    	   cout<<"window successfull updated\n";
       }
       if(update_success==false)
       {
    	   cout<<"error while trying to update window\n";
       }
       Sleep(2000);
       // ... 
       GdiplusShutdown(gdiplusToken);  // 03 
    	}
    }
    

    edit: sowohl bei InvalidateRect() als auch bei UpdateWindow() kommt true als Rückgabewert.

    mfg,
    andi01.


Anmelden zum Antworten