{VC++2005.NET] Label Text laufend aktualisieren


McMicha

Grünschnabel
Moin Forums Mitglieder,

ich bin der Micha und recht neu hier.
Ich habe da eine Frage zum Thema Windows Forms im allgemeinen und zum Aktualisieren von Labels im besonderen.

Bin in ANSI C/C++ gut bewandert habe aber von Windows Programmierung und besodners von .NET keine Ahnung, und finde da leiter auch nicht wirklich was zu.

Mein problem ist das ich eine Windows Anwendung programmieren will die laufend von einem Messfühler Daten empfängt diese auswertet oder umrechnet und dann darstellt.
Dazu habe ich mir mal zum testen eine Windows Form Projekt mit VS 2005 angelegt und dort ein Formular designt was ein Label Objekt für die Ausgabe und ein Button zum Starten der Anwendung hat.

Nach einem klick auf den Start Button springt er in die entsprechende Methode und liest die Daten vom Messfühler aus. Nun sollen die im Formular, in dem Label, dargestellt werden, dazu werden die Daten in einer Schleife ständig aus dem Buffer ausgelesen und in die Text Eigenschaft des Labels geschrieben.
Soweit sogut leider ändert sich auf dem Formular nichts, ausser das beim wiederholten starten und stoppen der Methode mal gelegenlich ein werd in dem Label auftaucht.

Ich habe da nun schon diverse sachen erlesen und ausprobiert (Invalid und Refresh), aber nichts führte zu einem Erfolg.

Wer könnte nun die Lösung zu meinem Problem beisteuern oder mich auf den richtigebn Weg bringen.
Ich habe ja auch noch die Befürchtung das ich da irgendwie föllig falsch liege da die oben beschrieben Schleife sich in der Click Methode im Form Header befindet.

Also Leute helft mir ein wenig...

MfG Micha
 

Christian Kusmanow

Erfahrenes Mitglied
Hi Micha!

Willkommen im Forum!

Wenn deine Schleife in dem MainThread deiner Anwendung läuft, bekommt das Form keine Chance seinen Inhalt neu zu zeichnen, da die Schleife ja permanent abgearbeitet wird.

Daher hast nur 3 Möglichkeiten:
  1. Du führst nach jedem Aktualisieren des Labels ein Application.DoEvents() aus. Damit gibst Du dem Programm die Möglichkeit, alle anstehenden Ereignisse die aktuell im MessageLoop des Forms anstehen auszuführen (WndProc). Somit wird dann auch das Label aktualisiert.
  2. Du kannst dafür auch einen simplen Timer verwenden. Der folgende Link erläutert Dir die 3 verschiednen Timer-Klassen des .NET Frameworks.
    Multithreading bei Windows Forms mit Timer-Klassen - ein Blick hinter die Kulissen - dot.net Magazin
  3. Oder Du realisierst das Abrufen der Messdaten in einem Thread und stellst dem Form die Werte in einem Event bereit. In dem folgenden Thread findest Du diesbezüglich nützliche Infos, einen Link zu meinem Threading-Tutorial sowie ein Beispielprogramm. [thread=261587]C# threading - Probleme - Thread[/thread]
 
Zuletzt bearbeitet:

the incredible Leitman

Erfahrenes Mitglied
Was ist mit einfach Invalidate() :confused:

Wär das nicht am naheliegendsten?
Sobald sich ein Property ändert oder bei Label gibts eh Events wie "TextChanged"

In welchen Abständen ändert sich denn immer der Wert des Label->Text?
 

Christian Kusmanow

Erfahrenes Mitglied
Hier geht es nicht darum Steuerelemente zu bauen Leitman. Das Control.Invalidate() dient lediglich dazu, das Neuzeichnen eines Steuerelements zu veranlassen. Das verwendet man idR wenn man Eigenschaften für ein eigenes Control definiert hat, bei deren Änderung das Neuzeichnen des Controls notwendig ist.
Und da er das Contol.Text Property verwendet, wird das Neuzeichnen eh ausgelöst, was diesen Aufruf ergo überflüssig macht. ;)
 

McMicha

Grünschnabel
Oh schon Antworten, das geht abe schnell hier....

so das mit den Application::DoEvents() erscheint mir als der richtige Weg, da ja wirklich sonst das Programm nicht dazu kommt mal die MessageLoop durch zu arbeiten.
Leider hat dies aber auch nicht funktioniert. Zu mindest gab es keine Verbesserung gegen über vorher.
Das mit den aufteilen in Thread erscheint mir momentan noch zu kompliziert, vorallem da dies ja nur ein ganz kleines Programm ist.

Die Methoden Invalidate und Refresh habe ich ja schon ausprobiert, hatten aber auch nichts gebracht.

Ich weisse nochmal daraufhin das ich mir nicht sicher bin ob die Schleife an der richtigen Stelle ist, denn ich habe sie in der Click Methode des Buttons geschrieben und die befindet sich ja in der Form Header Datei.
Ich habe bis jetzt keine einzige Codezeile in der Main Funktion geschriebn sondern alles in der Formular Header Datei gemacht.
Ich weis halt nicht ob dies so richtig ist.

Zu der Frage "In welchen Abständen ändert sich denn immer der Wert des Label->Text?" ständig, da es sich um einer Endlos Schleife handelt die erst durch ein erneutest drücken des Button beendet wird.
 

McMicha

Grünschnabel
Dank des von Christian Kusmanow verlinkten Artikel zum Thema Timer habe ich jetzt zumindest eine gelegentlích funktionierendes Programm hinbekommen.

Leider funktioniert es nicht immer wenn man auf den Start Button drück.
Gibt es da noch irgend was zu beachten, denn ich setzt beim klick auf den Button via "timer1->Enabled = true;" Timer Enable auf True.
Beim schritweisen debuggen funktioniert es immer, nur halt beim so ausführen nicht immer. Dahilft dann halt nur ein wiederholtes klicken auf den Button.
 

McMicha

Grünschnabel
Ich poste mal Auszüge aus den Quellcode.

Code:
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
		int i_fehler_activate, i_mode_max;
		long l_buffersize = 65000;
		if(button1->Text == "Stop")
		{
			button1->Text = "Start";
			button1->Invalidate();
			GSVrelease(i_portnummer);
			timer1->Enabled = false;
		}
		else
		{
			button1->Text = "Stop";
			i_fehler_activate = GSVactivate(i_portnummer, l_buffersize);
			if(i_fehler_activate != GSV_ERROR)
			{										
				GSVclearBuffer(i_portnummer);
				i_mode_max = GSVgetModeMax(i_portnummer);
				if(i_mode_max == 1)
					GSVsetModeMax(i_portnummer, 0);
					
				i_fehler_received = GSVreceived(i_portnummer);
				if(i_fehler_received == GSV_TRUE)
				{
					timer1->Enabled = true;
					Application::DoEvents();
				}
			}
		}
	 }
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
		double d_gsv_wert, d_norm, d_temp;
		if(i_fehler_received == GSV_TRUE)
		{
			d_norm = GSVDispGetNorm(i_portnummer);
			if(GSVread(i_portnummer, &d_gsv_wert ))
			{
				d_temp = d_gsv_wert * d_norm;
				textBox1->Text = ""+ Math::Round(d_temp, 2)+" kg";
				textBox1->Invalidate();
				textBox1->Refresh();
				Application::DoEvents();
			}
		}
	 }

Zu Erklärung, alles was mit GSV anfängt sind Funktionen die eine DLL zu Verfügung stellt, i_portnummer enthält die Nummer des COM Ports an dem der Messfühler hängt, ansonsten gibs noch das Label Objekt textBox1 wo ich die Daten reinschreiben will und das Button Objekt button1 dass das alles auslösen soll.
Und der ganze Qulletext Bereich stammt aus der Datei Form1.h (also eine Header Datei), in der Datei wo die main Funktion steht habe ich eigentlich nichts weiter geändert.
 

McMicha

Grünschnabel
Habe eine Problem Lösung gefunden, zwischen GSVactivate und GSVreceived musste
Code:
Thread::Sleep(125);
ansosnsten befinden sich noch keine Daten im Buffer und das Programm bricht da Regelkomform ab.Finde ich zwar mergwürdig, ist aber so.
 

Christian Kusmanow

Erfahrenes Mitglied
Das Application.DoEvents() am Ende der Methode kannst Dir spaaren, da die Methode dann eh abgearbeitet wird und danach alle Messages sofort verarbeitet werden.

Kannst den Thread als Erledigt markieren. :)