none
Mehrere Forms sollen sich gegenseitig beeinflussen RRS feed

  • Frage

  • Servus. Ich bin ein kleiner grüner Anfänger was Visual C++ angeht, und bin dabei in meinem allerersten Spaßprojekt an ein Problem geraten, von dem ich angenommen habe, dass das eigentlich völlig alltägliche Programmierpraxis ist... aber mittlerweile suche ich mir schon fünf Tage lang einen Wolf, habe in Lehrbüchern geblättert, in Foren gepostet und ein halbes dutzend programmierbewanderter Freunde ausgefragt. Und noch immer findet sich keine funktionierende Lösung!

    Situation:
    - Ich habe zwei UI-Fenster, Form1 und Form2.
    - Die Hauptoberfläche meiner Anwendung ist Form1. Dort befindet sich auch ein Button, der Form2 aufruft. Das funktioniert auch alles schon wunderbar.
    - In Form2 möchte ich Einstellungen vornehmen können, die Form1 direkt betreffen: zum Beispiel eine Progress Bar zurücksetzen oder ein Textfeld mit neuem Text versehen. Man kann quasi sagen, dass ich selten genutzte Funktionalitäten von Form1 nach Form2 auslagern möchte, weil auf Form1 für so eine Menge Knöpfe und Felder kein Platz ist bzw. es einfach wild unübersichtlich werden würde.

    ...Und das ist auch schon alles. Bis jetzt konnten weder echte Menschen noch Suchroboter mir eine Antwort darauf geben, wie ich Form2 dazu bringen kann, Dinge in Form1 zu verändern. Das muss doch möglich sein? Ich hab doch schon dutzende Anwendungen gesehen die das machen...

    Wie genau es implementiert wird ist mir übrigens relativ egal. Meine Anwendung ist (da ich Anfänger bin) sowieso nur ganz grausam zusammengehackt, guten Programmierstil oder eleganten Code sucht man dort vergebens. Also selbst wenn es sicherheitstechnisch bedenklich ist, wenn es hässlich aussieht oder das Problem in irgendeiner Art und Weise umschifft, bin ich glücklich damit. Hauptsache es läuft endlich mal, damit ich weiterkomme!


    Schonmal Danke für Lösungsversuche! :)
    Dienstag, 23. Juni 2009 20:57

Antworten

  • Es gibt verschiedene Ansätze:

    1. Der Einfache und zugleich schöne:
    - Du übergibst die Referenzen auf diese Dinge beim erzeugen des Form2:
      Form2^ frm2 = gcnew Form2(this->textBox1, this->button1, this->progressBar2);
    Im Form2.h sieht das das so aus (du musst den Konstruktor ändern):

    private: TextBox^ mainFormTextBox1;
    private: Button^ mainFormButton1;
    private: Button^ mainFormPrograssBar2;
    public: Form2(TextBox^ tb, Button^ btn, ProgessBar^ pb)
    {
      mainFormTextBox1 = tb;
      mainFormButton1 = btn;
      mainFormPrograssBar2 = pb;
    }
    Jetzt kannst Du in Deiner Form2 auf die Instanzen der Form1 zugreifen, ohne dass Form2 direkt etwas über das Form1 wissen muss (das ist das schöne daran).

    2. Du kannst Direkt das Form1 dem Form2 übergeben.
    Dies erfordert zwei Dinge: Die Felder in Form1 müssen zumindest als "internal" markiert werden und nicht wie per Default "private". Und Du musst die beiden Header gegenseitig includieren, was Forwards bedeutet, die es für einen Anfänger relativ schwer machen; auch kann es sein, dass Du Codeteile aus der h-Datei in die cpp-Verlagern musst, da sich die h-Dateien gegenseitig includieren.

    3. Vollkommene kapselung durch Properties
    Der aus Design-Sicht am besten Weg ist die vollkommene Trennung von Form1 und Form2. Im Form2 gibt es nur public Properties, welche den Inhalt der zu verändernden Daten repräsentiert. Damit ist im Form2 kein Wissen über die Form1 nötig (es ist z.B. unerheblich, ob die Form1 eine ProgressBar hat um einen Zahlenwert anzuzeigen, oder ob dies durch eine TextBox gemacht wird).
    Der schönste Weg ist aber auch der Aufwendigste. Du musst zuerst alle Daten analysieren und im Form2 entsprechende Properties einbauen. Diese werden dann vor Aufruf der "ShowDialog"-Methode im Form1 gesetzt. Ändert der Bediener jetzt Werte, so werden nur diese Properties geändert. Drückt er "Ok", so kann das Form1 dies auswerten und die Properties wieder den einzelnen Controls im Form1 zuweisen.


    Für Dich am einfachsten ist vermutliuch die Lösung 1
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 24. Juni 2009 05:48

Alle Antworten

  • Es gibt verschiedene Ansätze:

    1. Der Einfache und zugleich schöne:
    - Du übergibst die Referenzen auf diese Dinge beim erzeugen des Form2:
      Form2^ frm2 = gcnew Form2(this->textBox1, this->button1, this->progressBar2);
    Im Form2.h sieht das das so aus (du musst den Konstruktor ändern):

    private: TextBox^ mainFormTextBox1;
    private: Button^ mainFormButton1;
    private: Button^ mainFormPrograssBar2;
    public: Form2(TextBox^ tb, Button^ btn, ProgessBar^ pb)
    {
      mainFormTextBox1 = tb;
      mainFormButton1 = btn;
      mainFormPrograssBar2 = pb;
    }
    Jetzt kannst Du in Deiner Form2 auf die Instanzen der Form1 zugreifen, ohne dass Form2 direkt etwas über das Form1 wissen muss (das ist das schöne daran).

    2. Du kannst Direkt das Form1 dem Form2 übergeben.
    Dies erfordert zwei Dinge: Die Felder in Form1 müssen zumindest als "internal" markiert werden und nicht wie per Default "private". Und Du musst die beiden Header gegenseitig includieren, was Forwards bedeutet, die es für einen Anfänger relativ schwer machen; auch kann es sein, dass Du Codeteile aus der h-Datei in die cpp-Verlagern musst, da sich die h-Dateien gegenseitig includieren.

    3. Vollkommene kapselung durch Properties
    Der aus Design-Sicht am besten Weg ist die vollkommene Trennung von Form1 und Form2. Im Form2 gibt es nur public Properties, welche den Inhalt der zu verändernden Daten repräsentiert. Damit ist im Form2 kein Wissen über die Form1 nötig (es ist z.B. unerheblich, ob die Form1 eine ProgressBar hat um einen Zahlenwert anzuzeigen, oder ob dies durch eine TextBox gemacht wird).
    Der schönste Weg ist aber auch der Aufwendigste. Du musst zuerst alle Daten analysieren und im Form2 entsprechende Properties einbauen. Diese werden dann vor Aufruf der "ShowDialog"-Methode im Form1 gesetzt. Ändert der Bediener jetzt Werte, so werden nur diese Properties geändert. Drückt er "Ok", so kann das Form1 dies auswerten und die Properties wieder den einzelnen Controls im Form1 zuweisen.


    Für Dich am einfachsten ist vermutliuch die Lösung 1
    Jochen Kalmbach (MVP VC++)
    Mittwoch, 24. Juni 2009 05:48
  • Okay, schonmal vielen Dank für die Antworten! Ich werde versuchen, mich an Lösung 1 zu halten, da mir allein schon die Fachbegriffe in 2 und 3 nichts sagen ;)

    Ich habe das mal in der Form wie angegeben probiert:

    public ref class Form2 : public System::Windows::Forms::Form
    {
    	private: progressBar^ Form1progressBar1;    // wirft Fehler C2143
       	public: Form2(progressBar^ bar1)
    	{
    		InitializeComponent();
    		Form1progressBar1 = bar1;
    	}
    
    	// etc...

    Allerdings wirft schon die dritte Zeile hier Fehler: " error C2143: Syntaxfehler: Es fehlt ';' vor '^' ". Offenbar mag er an dieser Stelle keine Deklarationen.

    Und das ist nur der erste von insgesamt 14 Fehlermeldungen (auch wenn die, wie ich den Compiler kenne, wahrscheinlich alle zusammenhängen).

    • Bearbeitet lOmicronl Mittwoch, 24. Juni 2009 17:07
    Mittwoch, 24. Juni 2009 17:02
  • C/C++ (und auch C++/CLI) ist eine Sprache, welche Case-Sensitiv ist... somit musst Du das "ProgressBar" schon exact so schreiben, wie es auch definiert ist:
    http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx

    Also
    public ref class Form2 : public System::Windows::Forms::Form
    {
    private: ProgressBar^ Form1progressBar1;
      public: Form2(ProgressBar^ bar1)
      {
        InitializeComponent();
    Form1progressBar1 = bar1; }

    Jochen Kalmbach (MVP VC++)
    Mittwoch, 24. Juni 2009 18:14
  • Aaaahhh, genau das war es! Ich hatte bis jetzt immer mit den Objekten selbst gearbeitet, und die schreibt Visual Studio am Anfang klein. Ist mir gar nicht in den Sinn gekommen, dass sich die Klasse selbst großschreiben könnte.

    Da fehlt eben die Erfahrung...

    Mein Form2 tut jetzt genau was es soll, vielen Dank :)
    Mittwoch, 24. Juni 2009 18:29