DrawLine: Gezeichnete Linie gelöscht nach Minimieren!?



  • Betrifft: MS Visual C++ 2008 Express: CLR Windows Form Anwendung.

    Problem: Per Timer zeichne ich eine zusammenhängende Linie (Temperaturverlauf).
    Klappt ganz gut aber nachdem die Form minimiert wurde ist die Linie bis zur aktuellen Position weg!? Muss ich die gezeichneten Linien irgendwo hin schreiben daß sie nicht verloren gehen?

    private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
    				 Pen^ p2 = gcnew Pen(Color::Red); // Farbe des Stiftes.
    				 p2->Width = 2; // Breite des Stiftes.
    				 ++x2; // Startwert 21. y1 u. y2 sind (noch) konstant 80.
    				 ++x1; // Startwert 20.
    				 if (x2 == 300) this->timer1->Enabled = false; // Damit die Linie nicht ins unendliche läuft.				 
    				 this->label1->Text = String::Format("{0}", x2); // x2 als String auf die Form.
    				 this->pictureBox1->CreateGraphics()->DrawLine(p2, x1, y1, x2, y2); // Und Linie zeichnen!
    			 }
    

    Weiß leider nicht wonach ich suchen muss. 😕



  • Du MUSST in OnPaint/Paint-Event Zeichnen und nicht im Timer-Tick...



  • Nee, leider nicht: Nicht ein Pünktchen hat er mir behalten.

    BTW: Das PaintEvent tritt doch auf wenn die Form wieder hergestellt wird. Oder?



  • Du musst DIch auf den "this->pictureBox1->Paint" Eriegnis registrieren und dort zeichnen...
    Und er behält natürlich *nichts*, sondern DU musst alles nochmals neu Zeichnen!



  • Folgendes hatte ich gemacht:
    In den Eigenschaften/Ereignisse von pictureBox1 bei Paint neu 'On_paint2' als Sprungmarke eingetragen. Und bei...

    private: System::Void On_paint2(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
    

    ... die DrawLine Zeilen noch mal hin kopiert und getestet.

    Leider ohne Erfolg.



  • Du hast da was gänzlich falsch verstanden.
    Windows merkt sich NICHT was du früher mal gezeichnet hast, sondern teilt dir nur mit, dass du jetzt alles neu zeichnen musst.

    D.h. wenn du "stückchenweise" einen Graphen zeichnest, dann muss dein Programm sich irgendwo alle diese Stückchen merken, damit du ALLE NEU zeichnen kannst, wenn Windows dir nen Paint-Event schickt.

    Natürlich gibt es Mittel & Wege das zu umgehen. z.B. kannst du dir eine Bitmap machen, immer nur in die Bitmap reinzeichnen, und danach immer die Bitmap auf den Bildschirm kopieren. Der Inhalt der Bitmap bleibt dir erhalten wenn dein Fenster minimiert oder verdeckt wird, d.h. es reicht in dem Fall dann die Bitmap neu auf den Schirm zu kopieren.

    Hat aber einige Nachteile, z.B. dass es unnötig Speicher frisst, und vermutlich auch unnötig Performance vernichtet. Und natürlich kannst du so eine Bitmap nicht schön auf die Fenstergrösse skalieren. Wenn du dagegen noch die "Rohdaten" hast, aus denen du deinen Graph gezeichnet hast, dann kannst du jederzeit einen hübschen neuen Graphen zeichnen der an die neue Fenstergrösse angepasst ist.



  • Pöses Windows! 😉

    Danke für die Ausführliche Erleuterung. Hatte es schon befürchtet das ich alles mitführen muss um es neu in die pictureBox zu schreiben. Also packe ich mir alle Werte in ein Array und Zeichne bei onPaintEvent neu. In diesem Beispiel muss dann das Array 300 Felder beinhalten.
    Ich rechne mit rund 800 Messungen. -Ein Array mit dieser Größe: Macht das Performance Probleme im letzten drittel?

    Edit: Oder überhaupt?



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum C++/CLI mit .NET verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Macht keine Probleme...



  • Funktioniert einwandfrei! Array mit den Daten merken und bei onPaintEvent neu zeichnen.

    Euch beiden ein dickes Danke!

    Edit: Ergebnis dieser Anfrage:

    private: System::Void On_paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
    				 // Plot neu zeichnen nach onPaintEvent. (Nach Minimierung z.B.)
    				 Pen^ p2 = gcnew Pen(Color::YellowGreen); // Farbe des Stiftes.
    				 p2->Width = 1; // Breite des Stiftes.
    				 int t1, i; // i = Zeitlinie: privat.
    				 t1 = 0; // Temperatur Array Startpunkt zum neu zeichnen: privat.
    
    				 for (i = 30; i < x1; ++i){
    					 if (i <= X_MAX){
    						 this->pictureBox1->CreateGraphics()->DrawLine(p2, i, Temperatur[t1], i+1, Temperatur[t1+1]); // Linie zeichnen!
    						 ++t1;
    					 }
    				 }
    			 }
    


  • Also da sind noch ein paar "Schönheitsfehler" drinnen...

    private: System::Void On_paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
                //     Pen^ p2 = gcnew Pen(Color::YellowGreen); 
                     // ein Pen sollte disposed werden. das geht in C++/CLI am einfachsten so:
                     Pen p2(Color::YellowGreen); // Farbe des Stiftes.
    
                     p2.Width = 1; // Zugriff dann nimmer über -> sondern über .
                     int t1, i;
                     t1 = 0;
    
                     // für jede Linie ein neues Graphics Objekt ist Overkill, also 1x eins vor der Schleife anlegen
                     // auch das Graphics-Objekt will freigegeben (disposed) werden, hier machen wir es mit der "klassischen" Variante,
                     // d.h. mit "delete" (siehe unten)
                     Graphics^ g = this->pictureBox1->CreateGraphics();
                     for (i = 30; i < x1; ++i){
                         if (i <= X_MAX){
                             g->DrawLine(%p2, i, Temperatur[t1], i+1, Temperatur[t1+1]); // statt p2 müssen wir hier %p2 schreiben um wieder einen Pen^ (GC-referenz) zu bekommen
                             ++t1;
                         }
                     }
                     delete g; // und weg damit
                 }
    

Log in to reply