Thread in WindowsForms
-
Hallo,
danke für die Antwort, aber könnest Du mir bitte mal ein Beispiel geben.
Werde aus der MSDN Hilfe nicht wirklich schlau, bitte.Weder mit Invoke() noch BeginInvoke()
Gruß, Käsekrümel
-
Das einfachste ist, Du verwendest die "BackgroundWorker" Klasse anstelle den Thread selsbt zu erzeugen. Dort kannst Du dann den "Fortschritt" selber melden und in der Doku sind genügend Beispiele dabei.
http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
-
Schade, ich hätte das gerne mal selber gemacht um das mit dem Thread zu verstehen.
Ist aber wohl nicht so einfach, schade.Aber danke nochmal.
Gruß, Käsekrümel
-
Habt das jetzt mal versucht, aber der zweite Buttn lässt sich immer noch nicht anklicken.
Kann mir jemand vlt. helfen, bitte.public ref class Form1 : public System::Windows::Forms::Form { public: bool abort; private: System::Windows::Forms::Button^ button2; public: int y; delegate void InvokeDelegate(); Form1(void) { InitializeComponent(); // //TODO: Konstruktorcode hier hinzufügen. // abort = false; y=0; } void DoWork() { //label1->BeginInvoke(gcnew InvokeDelegate( this, &Form1::InvokeMethod )); progressBar1->BeginInvoke(gcnew InvokeDelegate( this, &Form1::InvokeMethod )); button2->BeginInvoke(gcnew InvokeDelegate(this, &Form1::InvokeMethod)); } void StopWork() { //label1->BeginInvoke(gcnew InvokeDelegate( this, &Form1::InvokeMethod )); //progressBar1->BeginInvoke(gcnew InvokeDelegate( this, &Form1::InvokeMethod )); button2->BeginInvoke(gcnew InvokeDelegate(this, &Form1::InvokeStopMethod)); } void InvokeMethod() { do { y++; this->Text = y.ToString(); } while(!abort); } void InvokeStopMethod() { abort = false; } private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ newThread = gcnew Thread( gcnew ThreadStart( this,&Form1::DoWork) ); newThread->Start(); newThread->Join(); } private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ newThread = gcnew Thread( gcnew ThreadStart( this,&Form1::StopWork) ); newThread->Start(); newThread->Join(); }
-
Ja, das newThread->Join(); ist zuviel.
Das veranlasst den aufrufenden Thread auf die beendigung des newThreads zu warten.
-
Hab ich rausgenommen, aber der Klick auf Button2 bleibt ohne Wirkung.
Warum?
Hab das Gefühl, dass System ist voll blockiert.
Ich komm einfach nicht weiter.
Hat jemand noch eine Idee?
In der Konsole funktionierte das ja alles.
Warum nicht in der Forms?void DoWork() { if(progressBar1->InvokeRequired) { progressBar1->BeginInvoke(gcnew InvokeDelegate( this, &Form1::DoWork )); } else { do { if(y > 99) { y=0; progressBar1->Value = 0; } else { y++; progressBar1->Value = y; Thread::Sleep(80); } } while(!abort); } } private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Thread^ newThread = gcnew Thread( gcnew ThreadStart( this,&Form1::DoWork) ); newThread->Start(); } private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { abort == true; }
Gruß, Käsekrümel
-
Du musst die eigentliche Arbeit schon auf einem eigenen Thread ausführen.
Mit Invoke tust Du das eben gerade nicht.Also: Eigentliche Arbeit auf eigenen Thread. Jedoch die Zugriffe auf die GUI Elemente mit Invoke auf den korrekten Thread marshallen.
private: System::Void startButton_Click(System::Object^ sender, System::EventArgs^ e) { abort = false; Thread^ newThread = gcnew Thread( gcnew ThreadStart( this,&Form1::DoWork) ); newThread->Start(); } private: bool abort; private: System::Void abortButton_Click(System::Object^ sender, System::EventArgs^ e) { abort = true; } private: void DoWork() { int y = 0; do { if(y > 99) { y=0; InvokeSetProgressValue(0); } else { y++; InvokeSetProgressValue(y); Thread::Sleep(80); } } while(!abort); } private: delegate void InvokeDelegate(int value); private: void InvokeSetProgressValue(int value) { if(progressBar1->InvokeRequired) { progressBar1->Invoke(gcnew InvokeDelegate(this, &Form1::SetProgressValue), value); } else { Form1::SetProgressValue(value); } } private: void SetProgressValue(int value) { progressBar1->Value = value; }
Simon
-
Danke Simon!
Hat super geklappt.
Wäre das nichts für die FAQ?
Das kleine Projekt werde ich auf einem sicheren Datenträger speichern, so habe ich ihn immer da wenn ich ihn brauche.Vielen Dank nochmal.
Gruß, Käsekrümel
-
Hallo,
ich müsste da auch nochmal kurz nachhaken. Ich bekomme, das nämlich nicht so ganz hin.
Ich habe eine CLI-Anwendung erstellt. In der wird durch einen Button-Klick ein neuer Thread gestartet. Dieser Thread befindet sich aber in einer anderen Klasse, damit ich die Übersicht behalten kann, was zum GUI und was zur Datenverarbeitung gehört. Wie habe ich da mit dem Invoke und mit dem delegate zu arbeiten? Mein Ziel ist es, von dem Thread, wo die Datenauswertung erfolgt, Zwischenmeldungen in eine Listbox hinzuzufügen.
Der Code sieht bei mir so aus
Klasse Form1
Der Button-KlickSystem::Void Form1::bSend_Click(System::Object ^sender, System::EventArgs ^e) { CTransmission^ cTransmit = gcnew CTransmission; Thread^ threadPing = gcnew Thread (gcnew ThreadStart(cTransmit, &CTransmission::SendPing)); threadPing->Start(); }
Das hinzufügen der Items für die Listbox (was public ist):
static void AddListItemMethod(String^ str) { lbResults->Items->Add( str ); lbResults->Update(); }
In der Klasse CTransmission:
delegate void UpdateListItem(String^ str); void CTransmission::SendPing() { UpdateListItem^ callback = gcnew UpdateListItem(&Form1::AddListItemMethod); callback("huhu"); }
Der Compiler meckert jetzt in der Methode AddListItemMethod. Es kommt folgende Fehlermeldung (kommt mehrfach auch für Add und für Update):
error C2227: left of '->Items' must point to class/struct/union/generic type
Das liegt höchstwahrscheinlich daran, dass die Methode static ist. Definiere ich sie nicht als static, kommt allerdings ein anderer Fehler und zwar meckert er dann an dieser Zeile
UpdateListItem^ callback = gcnew UpdateListItem(&Form1::AddListItemMethod);
mit der Meldung
error C3352: 'void PingTest::Form1::AddListItemMethod(System::String ^)' : the specified function does not match the delegate type 'void (System::String ^)'
Und das casten will mir an der Stelle nicht so recht gelingen.
Was mache ich falsch? Liegt es daran, dass ich mit zwei Klassen arbeite? Ich hoffe mir kann jemand helfen. Vielen Dank schon mal im Voraus.
Viele Grüße
Kati82
-
Hallo nochmal,
ich habe noch ein wenig rumprobiert und endlich eine Variante gefunden, mit der auch der Compiler zufrieden ist. Trotzdem funktioniert es nicht ganz so wie ich will.
Hier schon mal der Code:Klasse Form1:
delegate void AddListItemMethod(String^ str); AddListItemMethod^ myDelegate; void AddListItemMethod(String^ str) { lbResults->Items->Add(str); lbResults->Update(); }
Klasse CTransmission (Aufruf im Thread):
PingTest::Form1^ AddListItemDelegate = gcnew PingTest::Form1; AddListItemDelegate->AddListItemMethod("huhu");
Das Problem, was ich jetzt noch habe, ist, dass überhaupt nix in der Listbox angezeigt wird.
Kann mir bitte, bitte jemand erklären warum? Was muss ich noch machen, damit dass endlich mal angezeigt wird.
Vielen Dank im voraus.
Viele Grüße
Kati82
-
Hi,
hast du schon eine lösung dazu?
ich habe nämlich genau das selbe problem, eine Form, und eine extra Threadklasse... und ich bring es einfach nicht zusammen dass der compiler zufrieden ist...gruß