[C++] Labels außerhalb der Form1 Klasse ändern


litlein

Grünschnabel
Hallo,

ich versuche ein Labeltext außerhalb der Form1 Klasse zu verändern, z.B. in der main().
Der Compiler zeigt dabei keine Fehler an, aber das Label bleibt einfach unverändert.
In einem anderen Thread wurde gesagt, dass Application:: DoEvents() das Label aktualisiert, funktioniert aber nicht.
Ich habe auch schon versucht eine extre Funktion zu schreiben, um das Label zu ändern. Auch hier keine Fehlermeldung und kein Ergebniss.

Code:
Die main()
PHP:
int main(array<System::String ^> ^args)
{
	// Aktivieren visueller Effekte von Windows XP, bevor Steuerelemente erstellt werden
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 

	// Hauptfenster erstellen und ausführen
	Form1 ^f1 = gcnew Form1();
	Application::Run(f1);
	f1->label1->Text = "Hallo";
	f1->setLabel1("Hi");

	return 0;
}

Die Form1 (wichtigsten Ausschnitte):
PHP:
public: System::Windows::Forms::Label^  label1;

...
...

public: void setLabel1(System::String ^abcde)
{
	this->label1->Text = abcde;
}

Wenn doch irgendwo im Forum die richtige Antwort rumschwiert entschuldige ich mich, aber ich bin schon extrem lange am suchen.

Mfg,
Flo
 

Spyke

Premium-User
Das Problem ist
Application::Run

Das ist eine Methode die intern eine Endlosschleife laufen lässt solange dein Formular offen ist.
Dadurch wird dein Label eigentlich erst geändert wennn das Programm beendet wird.
 

litlein

Grünschnabel
Wenn ich den Code vor Application::Run() einfüge, änder sich das Label. Aber ich kannes nicht danach machen.

Mit einem Button funktioniert das ganze ja auch. Der ist genauso wie die Funktion setLabel1() in der Form1 Klasse definiert und verändert auch einfach nur den Text.

Gibt es keine Möglichkeit das Label trotz "Endlosschleife" zu ändern? Wäre ja etwas sinnlos, wenn es nicht gehen würde.
 

Spyke

Premium-User
Sag uns lieber was du vor hast.
Das was du vor hast ist Sinnlos ;)

Natürlich kannst du ein Label auch "innerhalb" einer Schleife oder danach ändern.

Die besonderheit hier ist das es sich um die Hauptschleife handelt.
In der werden alle Nachrichten verarbeitet.
 

litlein

Grünschnabel
Okay, dann beschreibe ich das mal.

Ich habe eine Klasse. Eine Funktion daraus liefert einen Wert zurück, den ich in ein Label schreiben will. Ich habe von der Klasse aus jedoch keinen Zugriff auf das Label, bzw. ich kann den zurückgegebenen Wert nicht eintragen. Der Wert soll sich mehrmals automatisch aktualisieren.

Deswegen in der Mainfunktion:
PHP:
	planet ^p = gcnew planet();
										//Liefert etwas wie 23523 zurück.
	f1->label1->Text = Convert::ToString(p->getMaterial('m')) ;

Bei der Zuweisung keine Fehler, jedoch wird der Text nicht im Label angezeigt.
 

Spyke

Premium-User
Was ist planet?
Warum wurde planet nicht in der Form selbst angelegt / instanziiert / speicher angefordert?

Ich würde mir das eher so vorstellen:
Code:
class Form1 : Form
{
   public Form1 ()
   {
      //Initzeugs vom Designer

      meinPlanet = new Planet();
      meinPlanet.StatusChanged += new EventHandler(meinPlanet_StatusChanged);
   }

   private oid meinPlanet_StatusChanged(object sender, EventArgs e)
   {
      Label1.Text = meinPlanet.Material.
   }

   private Planet meinPlanet;
}
(Pseudo C# Code)
 

litlein

Grünschnabel
Ist mir klar, dass es so funktionieren wird, aber es geht mir gerade darum es außerhalb der Form1 zu tun.
Auch eine Buttonfunktion, die bei einem Klick ausgeführt wird und nicht in der Form1 Klasse definiert ist, kann den Text nicht ändern.
Ich verstehe einfach nicht, warum die Zuweisung nur in Form1 funktioniert.
 

Spyke

Premium-User
Läuft ev. eine Schleife wo durch die Nachricht nicht verarbeitet werden kann?
Ansonsten muss wohl mehr Code her.
 

litlein

Grünschnabel
Um das ganze etwas zu vereinfachen, habe ich ein neues Projekt erstellt, mit nur den wichtigsten funktionen:
Das Projekt heißt "test1"


test1.cpp:
PHP:
// test1.cpp: Hauptprojektdatei.

#include "stdafx.h"
#include "Form1.h"
#include "klasse.h"

using namespace test1;

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
	// Aktivieren visueller Effekte von Windows XP, bevor Steuerelemente erstellt werden
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 

	// Hauptfenster erstellen und ausführen
	Form1 ^f1 = gcnew Form1();
	klasse ^k = gcnew klasse();
	f1->button1->Click += gcnew System::EventHandler(k, &klasse::button1click);
	Application::Run(f1);
	return 0;
}

Form1.h:
PHP:
#pragma once


namespace test1 {

	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
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Konstruktorcode hier hinzufügen.
			//
		}

	protected:
		/// <summary>
		/// Verwendete Ressourcen bereinigen.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	public: System::Windows::Forms::Button^  button1;
	protected: 

	public: System::Windows::Forms::Label^  label1;
	private: 
	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->button1 = (gcnew System::Windows::Forms::Button());
			this->label1 = (gcnew System::Windows::Forms::Label());
			this->SuspendLayout();
			// 
			// button1
			// 
			this->button1->Location = System::Drawing::Point(107, 61);
			this->button1->Name = L"button1";
			this->button1->Size = System::Drawing::Size(75, 23);
			this->button1->TabIndex = 0;
			this->button1->Text = L"button1";
			this->button1->UseVisualStyleBackColor = true;
			//this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click_1);
			// 
			// label1
			// 
			this->label1->AutoSize = true;
			this->label1->Location = System::Drawing::Point(118, 122);
			this->label1->Name = L"label1";
			this->label1->Size = System::Drawing::Size(35, 13);
			this->label1->TabIndex = 1;
			this->label1->Text = L"label1";
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(292, 273);
			this->Controls->Add(this->label1);
			this->Controls->Add(this->button1);
			this->Name = L"Form1";
			this->Text = L"Form1";
			this->ResumeLayout(false);
			this->PerformLayout();

		}
#pragma endregion
	};
}

klasse.h:
PHP:
#pragma once

ref class klasse : test1::Form1
{
public:
	klasse(void);
	System::Void button1click(System::Object^  sender, System::EventArgs^  e);
};

klasse.cpp:
PHP:
#include "StdAfx.h"
#include "Form1.h"
#include "klasse.h"

klasse::klasse(void)
{
}

System::Void klasse::button1click(System::Object^  sender, System::EventArgs^  e)
{
	label1->Text = "Hi";

	//Um sicherzusein, dass der Klick auch ausgeführt wird
	System::Windows::Forms::MessageBox::Show("hi");
}


Die Funktion button1click wird ausgeführt (sieht man an der Messagebox). Jedoch bleibt der Inhalt von label1 unverändert.
 

litlein

Grünschnabel
Die "klasse" besitzt doch aber überhaupt kein "label1".

Ich habe die Form1 jetzt mal um die Funktion erweitert:
PHP:
	public : System::Void changeLabel1(System::String ^text) {
				 this->label1->Text = text;
			 }

und den Button verändert:
PHP:
System::Void klasse::button1click(System::Object^  sender, System::EventArgs^  e)
{
	Form1::label1->Text = "Hi";
	changeLabel1("Text");

	//Um sicherzusein, dass der Klick auch ausgeführt wird
	System::Windows::Forms::MessageBox::Show(label1->Text);
}

Erstaunlicherweise wird in der MessageBox wirklich das zuvor gesetzte "Text" ausgegeben. Aber es wird in der Form nicht angezeigt.
Wenn ich wirklich nur das label in meiner Klasse anspreche, wie spreche ich dann das andere an?
 

Cromon

Erfahrenes Mitglied
Die "klasse" besitzt doch aber überhaupt kein "label1".

Doch, du erbst von Form1 und diese Klasse hat einen Member label1, daher wird der weitervererbt.

Erstaunlicherweise wird in der MessageBox wirklich das zuvor gesetzte "Text" ausgegeben. Aber es wird in der Form nicht angezeigt.
Wenn ich wirklich nur das label in meiner Klasse anspreche, wie spreche ich dann das andere an?


Das ist überhaupt nicht erstaunlich. Denn wie gesagt, label1 in deiner Klasse ist eine andere Instanz von System::Windows::Forms::Label als label1 deiner Instanz von Form1. Es sind zwei unterschiedliche Instanzen von Klassen. Du musst einen Zeiger auf die Instanz von Form1 haben, die angezeigt wird. Grundsätzlich liefert dir sender die Möglichkeit an diese Instanz zu kommen, wenn du alles entsprechend castest (Vorsicht: Dabei immer try<->catch zur "Validierung" des Casts verwenden)
 

litlein

Grünschnabel
Das hört sich gut an, könntest du bitte noch ein kurzes Beispiel geben, wie ich an die Instanz von Form1 mithilfe des sender objects komme?
 

Cromon

Erfahrenes Mitglied
Du prüfst zuerst ob sender in System::Windows::Forms::Button^ gecastet werden kann. Anschliessend prüfst du ob der Button bei Parent nicht den nullptr hat. Falls dem so ist versuchst ob du diesen Parent von System::Windows::Forms::Control nach Form1 casten kannst.

Prüfen kannst du das über try und das catchen einer InvalidCastException exception.
 

litlein

Grünschnabel
Ich weiß zwar jetzt genausoviel wie vorher, aber ich habe es anders in den Griff bekommen.
Du hast mir die Augen geöffnet, denn eigentlich enthält ja die "klasse" jetzt die komplette Form.
Also einfach in der Mainfunktion:

PHP:
	klasse ^k = gcnew klasse();
	k->button1->Click += gcnew System::EventHandler(k, &klasse::button1click);
	Application::Run(k);

Funktioniert wunderbar ^^
Vielen dank für die Hilfe.
 

Cromon

Erfahrenes Mitglied
Ja, das ist so, Ich bin davon ausgegangen, dass das einen tieferen Sinn hat dass das zwei unterschiedliche Instanzen sein müssen ;).

A propos:
Jetzt ist dein Setup identisch wie wenn du von vornherein ein Windows Forms Projekt ausgewählt hättest ;)
 

litlein

Grünschnabel
Ist mir nach dem schreiben des Posts auch aufgefallen, aber so gefällt es mir besser.

Ich habe nur ein Buch zur Einführung in Visual C++ gelesen und da wird sowas garnicht behandelt ...
 

Spyke

Premium-User
Du musst einen Zeiger auf die Instanz von Form1 haben, die angezeigt wird. Grundsätzlich liefert dir sender die Möglichkeit an diese Instanz zu kommen, wenn du alles entsprechend castest (Vorsicht: Dabei immer try<->catch zur "Validierung" des Casts verwenden)

Mit try catch würde ich nicht prüfen.
Auch wenn hier Fehler eigentlich nicht auftretten sollten, würde es das Programm doch eher verlangsamen, sollte dies der Fall sein und in einem größerem Umfang.

In C# gibts dafür zum Beispiel den "is" (oder auch "as") Operator, den müsste es in der C++ Version doch auch geben oder?
 

Neue Beiträge