DrawLine() im Konstruktor
-
Hallo,
in dem folgenden Beispiel erzeuge ich im Konstruktor von Form1 ein Graphics-Objekt zu einem Panel (Zeile 25,33), und zeichne dann eine gelbe Linie in das Panel (Zeile 34).
Weiter unten in button1_Click zeichne ich eine rote Linie in das gleiche Panel (Zeile 100). Wenn ich auf Button1 klicke, wird die rote Linie wie erwartet gezeichnet. Aber die gelbe Linie wird nie gezeichnet. Warum geht das nicht?Gruss Michael
#pragma once namespace test_7_7_2010 { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; /// <summary> /// Summary for Form1 /// /// WARNING: If you change the name of this class, you will need to change the /// 'Resource File Name' property for the managed resource compiler tool /// associated with all .resx files this class depends on. Otherwise, /// the designers will not be able to interact properly with localized /// resources associated with this form. /// </summary> public ref class Form1 : public System::Windows::Forms::Form { public: Graphics^ g; Form1(void) { InitializeComponent(); // //TODO: Add the constructor code here // g = panel1->CreateGraphics(); g->DrawLine(gcnew Pen(Color::Yellow),0,0,50,50); } protected: /// <summary> /// Clean up any resources being used. /// </summary> ~Form1() { if (components) { delete components; } } private: System::Windows::Forms::Panel^ panel1; protected: private: System::Windows::Forms::Button^ button1; private: /// <summary> /// Required designer variable. /// </summary> System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> void InitializeComponent(void) { this->panel1 = (gcnew System::Windows::Forms::Panel()); this->button1 = (gcnew System::Windows::Forms::Button()); this->SuspendLayout(); // // panel1 // this->panel1->Location = System::Drawing::Point(72, 32); this->panel1->Name = L"panel1"; this->panel1->Size = System::Drawing::Size(352, 184); this->panel1->TabIndex = 0; // // button1 // this->button1->Location = System::Drawing::Point(80, 248); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(104, 56); this->button1->TabIndex = 1; this->button1->Text = L"button1"; this->button1->UseVisualStyleBackColor = true; this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click); // // Form1 // this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(486, 338); this->Controls->Add(this->button1); this->Controls->Add(this->panel1); this->Name = L"Form1"; this->Text = L"Form1"; this->ResumeLayout(false); } #pragma endregion private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { g->DrawLine(gcnew Pen(Color::Red),50,50,100,100); } }; }
-
Die gelbe Linie wird schon gezeichnet, nur eben nicht angezeigt, da die Form noch nicht erstellt und angezeigt wurde.
Lege ein Event Shown an...
Und Graphics^ g solltest Du nicht als Public deklarieren.
#pragma once namespace Line { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; /// <summary> /// Zusammenfassung für Form1 /// /// Warnung: Wenn Sie den Namen dieser Klasse ändern, müssen Sie auch /// die Ressourcendateiname-Eigenschaft für das Tool zur Kompilierung verwalteter Ressourcen ändern, /// das allen RESX-Dateien zugewiesen ist, von denen diese Klasse abhängt. /// Anderenfalls können die Designer nicht korrekt mit den lokalisierten Ressourcen /// arbeiten, die diesem Formular zugewiesen sind. /// </summary> public ref class Form1 : public System::Windows::Forms::Form { private: Graphics^ g; public: Form1(void) { InitializeComponent(); // //TODO: Konstruktorcode hier hinzufügen. // g = panel1->CreateGraphics(); } protected: /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> ~Form1() { if (components) { delete components; } } private: System::Windows::Forms::Panel^ panel1; private: System::Windows::Forms::Button^ button1; protected: private: /// <summary> /// Erforderliche Designervariable. /// </summary> System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> void InitializeComponent(void) { this->panel1 = (gcnew System::Windows::Forms::Panel()); this->button1 = (gcnew System::Windows::Forms::Button()); this->SuspendLayout(); // // panel1 // this->panel1->Location = System::Drawing::Point(3, 12); this->panel1->Name = L"panel1"; this->panel1->Size = System::Drawing::Size(840, 385); this->panel1->TabIndex = 0; // // button1 // this->button1->Location = System::Drawing::Point(267, 456); this->button1->Name = L"button1"; this->button1->Size = System::Drawing::Size(75, 23); this->button1->TabIndex = 1; this->button1->Text = L"button1"; this->button1->UseVisualStyleBackColor = true; this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click); // // Form1 // this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(875, 532); this->Controls->Add(this->button1); this->Controls->Add(this->panel1); this->Name = L"Form1"; this->Text = L"Form1"; this->Shown += gcnew System::EventHandler(this, &Form1::Form1_Shown); this->ResumeLayout(false); } #pragma endregion private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { g->DrawLine(gcnew Pen(Color::Red),50,50,100,100); } private: System::Void Form1_Shown(System::Object^ sender, System::EventArgs^ e) { g->DrawLine(gcnew Pen(Color::Yellow),0,0,50,50); } };
}
-
Hi,
Doug_HH schrieb:
Die gelbe Linie wird schon gezeichnet, nur eben nicht angezeigt, da die Form noch nicht erstellt und angezeigt wurde.
Lege ein Event Shown an...
Und Graphics^ g solltest Du nicht als Public deklarieren.
Danke, das Problem ist gelöst !
Gruss
Michael
-
Dennoch ist die ganze Vorgehensweise falsch!
Minimiere einfach mal dein Fenster und dann stelle es wieder her oder laß dein Fenster mal kurzzeitig von einem anderen Fenster überdecken...
Gezeichnet werden darf nur in Paint-Ereignis und dort gibt es dann auch im PaintEventArgs-Parameter die Eigenschaft 'Graphics':
private: System::Void panel1_Paint(System::Object^ sender, System::PaintEventArgs^ e) { e->Graphics->DrawLine(gcnew Pen(Color::Red),50,50,100,100); }
P.S. Außerdem sollten GDI-Objekte wie Pen, Brush, etc. nach Benutzung wieder gelöscht werden (in C# wird dies mittels "Dispose" gemacht - in C++/CLI m.E. mittels 'delete'), sonst können Windows irgendwann die 'Handles' ausgehen (sofern der GC nicht rechtzeitig aufgeräumt hat)...
-
Th69 schrieb:
Dennoch ist die ganze Vorgehensweise falsch!
Minimiere einfach mal dein Fenster und dann stelle es wieder her oder laß dein Fenster mal kurzzeitig von einem anderen Fenster überdecken...Nicht ganz, was spricht gegen das Show-Event.
Das Fenster zu minimieren und es dann wieder herstellen oder es zu überdecken um ein neu zeichnen zu erzwingen halte ich für eine sehr schlechte Lösung.
-
Hallo,
Th69 schrieb:
Dennoch ist die ganze Vorgehensweise falsch!
Dass da noch der Wurm drin ist merke ich auch gerade. Das Beispiel war insofern stark vereinfacht, weil das Zeichnen einer einzigen Linie sehr schnell geht.
Im konkreten Fall zeichne ich aber viele Linien, deren Koordinaten Ergebnis einer komplizierten Berechnung sind. Diese Berechnung soll nicht jedesmal neu gemacht werden, wenn das Panel neu gezeichnet werden muss.
Kann man irgendwie erreichen, dass der Inhalt des Panels intern gespeichert wird und bei Bedarf aus dem internen Speicher neu gezeichnet wird?Gruss
Michael
-
Hallo Doug_HH, du hast mich mißverstanden:
er soll dies mal von Hand machen, damit man sieht, daß dann die Linien weg sind!Hallo micha7,
wenn du eine große Anzahl von Linien hast, die angezeigt werden sollen (und nicht einzeln mehr gelöscht), dann zeichne diese direkt in eine Bitmap und zeige dann im Paint-Ereignis nur diese Bitmap an (mittels DrawImage).P.S. hier noch ein Link bzgl. der Freigabe von GDI-Objekten: http://msdn.microsoft.com/en-us/magazine/cc163630.aspx#S9
(in C++/CLI also einfach lokale Variablen für die GDI-Objekte benutzen)Dort sind unter dem Punkt "Painting Performance" bzw. "Text and Images" noch ein paar hilfreiche Tipps bzgl. deiner Zeichen-Performance-Probleme...
noch ein P.S.: bezüglich WinForms solltest du evtl. besser direkt in C# programmieren (s.a. ersten Beitrag hier im Forum: http://www.c-plusplus.net/forum/viewtopic-var-t-is-263084.html).
-
Hallo,
Th69 schrieb:
wenn du eine große Anzahl von Linien hast, die angezeigt werden sollen (und nicht einzeln mehr gelöscht), dann zeichne diese direkt in eine Bitmap und zeige dann im Paint-Ereignis nur diese Bitmap an (mittels DrawImage).
Gut, das hört sich sinnvoll an, führt mich aber direkt zum nächsten Problem:
Ich weiss, wie man in Graphics-Objekte zeichnen kann, z.B. mit DrawLine().
Ich weiss auch, wie man in Bitmap-Objekte mit SetPixel() zeichnen kann.
Aber bei einem Bitmap-Objekt gibt's keine DrawLine() Funktion.
Muss ich zuerst ein Graphics-Objekt zu der Bitmap erzeugen? Wenn ja, wie geht das?
Oder geht es andersrum, zu dem bereits vorhandenen Graphics-Objekt die passende Bitmap erzeugen? Wenn ja, wie geht das?Gruss
Michael
-
Th69 schrieb:
Hallo Doug_HH, du hast mich mißverstanden:
er soll dies mal von Hand machen, damit man sieht, daß dann die Linien weg sind!Ach so meintest Du das, vollkommen richtig.
-
Hallo micha7,
Graphics::FromImage(...)
ist dein Freund (also erst die Bitmap erzeugen und dann mit obiger Methode das Graphics-Objekt holen und darauf zeichnen)!
P.S. Doug_HH, ich hätte hinter meinen Satz wohl besser einen Smilie (
) anzeigen sollen statt der '...'
-
Hallo,
Th69 schrieb:
Graphics::FromImage(...)
ist dein Freund (also erst die Bitmap erzeugen und dann mit obiger Methode das Graphics-Objekt holen und darauf zeichnen)!
Dieser Hinweis war sehr gut, es funktioniert !!!
Gruss
Michael