Komunikacja w aplikacji wielookienkowej. Znaczenie zmiennych globalnych (publicznych)
Materiał jest kontynuacją tematu poprzedniego Aplikacja wielookienkowa, stąd sposobu dodawania kolejnych formatek okien nie będę w tym temacie opisywać. Temat obejmuje zagadnienia wykorzystania zmiennych publicznych w aplikacji wielookienkowej MDI.
Cel: Napisz aplikację wielookienkową przy pomocy której będzie można zamykać lub otwierać okna dzieci z innych okien potomnych oraz wykonując działania na zmiennych publicznych zadeklarowanych w różnych oknach.
Krok 1. Układ komponentów w oknach dzieci
Ze względu na tematyczne podzielenie okien potomnych na dwie grupy w poprzednim temacie układ komponentów w oknach dzieci będzie dobrany pod metodę ich wywołania. Czyli wywołanie bezpośrednie i poprzez instancję klasy okna formatki dziecka.
Okna wywoływane bezpośrednio powinny zawierać układ komponentów jak poniżej
Okno numer 1 (formatka Form2) zawiera dwa komponenty Button. Przy ich pomocy będzie można otwierać okno 2 (Form3) i okno 4 (Form4)
Okno numer 2 (formatka Form3) zawiera jeden komponent Button, przy pomocy którego zamknie się okno 1 (Form2)
Okno numer 3 (formatka Form4) zawiera jeden komponent Button, przy pomocy którego zamknie się okno 2 (Form3)
Układ komponentów na formatkach okien wywoływanych przez instancję klasy
Okno pierwsze instancji (formatka Form5) zawiera dwa komponenty Button, przy pomocy których można otworzyć okno 2 instancji (Form6) i okno 4 instancji (Form7)
Okno 2 instancji (formatka Form6) zawiera po dwa komponenty Label, TextBox i Button.
W komponentach TextBox będzie można wprowadzić zmienne publiczne zapisane w oknie 3 instancji (Form7).
Komponenty Button pozwolą wykonać odpowiednie działanie i pokazać wynik w oknie 3 po jego wywołaniu. Sposób przeprowadzenia tych działań będzie bazować na różnych sposobach obsługi zmiennych publicznych.
Okno 3 instancji (formatka Form7) zawiera dwa komponenty Label. Komponent label1 zawiera statyczny tekst "Wynik działania z okna II". Komponent label2 będzie służyć do przedstawienia tego wyniku
Krok 2. Polecenie otwarcia okna dziecka z innego okna dziecka w metodzie wywołania bezpośredniego
Rozwiązanie oparte jest na wywołaniu publicznej funkcji RobOkno zapisanej w kodzie klasy okna głównego (ojca aplikacji wielookienkowej). Ciało funkcji RobOkno znajduje się w poprzednim temacie
Dla przycisku wywołującego okno 2 (Form3)
Wskazówka:
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form3 == null) {
f.form3 = new Form3();
f.RobOkno(f.form3, "okno2");
//lub taką konstrukcję
//f.RobOkno(f.form3 = new Form3(), "okno2");
}
else f.form3.Activate();
}
Dla przycisku wywołującego okno 3 (Form4) przedstawię nieznaczną modyfikację wywołania funkcji RobOkno
Wskazówka:
private void Button2_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form4 == null)
f.RobOkno(f.form4 = new Form4(), "okno3");
else f.form4.Activate();
}
Skompiluj program i sprawdź efekt działania
Krok 3. Zamknięcie okna dziecka z poziomu innego okna dziecka w aplikacji wielookienkowej w metodzie wywołania bezpośredniego
Zamykamy okno 1 (Form2) z okna 2 (Form3). Kod zdarzenia Click dla przycisku button1 w formatce Form3
Wskazówka:
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno1
if(f.form2!=null)f.form2.Close();
}
W podobny sposób zamkniemy okno 2 (Form3) z okna 3 (Form4). Kod zdarzenia Click dla przycisku button1 w formatce Form4
Wskazówka:
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno2
if (f.form3 != null) f.form3.Close();
}
Skompiluj program i sprawdź efekt działania.
Rozwiązanie dla okien wywoływanych poprzez instancję klasy
Metoda używania instancji jest wygodniejsza przy obsłudze zmiennych i funkcji publicznych pomimo, że wymaga powtórzenia tego samego kodu w kolejnych klasach dodawanych okien dzieci.
Krok 1. Wywołanie okna dziecka z poziomu innego okna dziecka
Kod zdarzenia Click przycisku button1 formatki Form5
Wskazówka:
private void Button1_Click(object sender, EventArgs e)
{
Form6.Instancja.MdiParent = this.MdiParent;
Form6.Instancja.Text="Okno II otwarte z okna I";
Form6.Instancja.Show();
Form6.Instancja.Activate();
}
Kod zdarzenia Click przycisku button2 formatki Form5
Wskazówka:
private void Button2_Click(object sender, EventArgs e)
{
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna I";
Form7.Instancja.Show();
Form6.Instancja.Activate();
}
Skompiluj program i sprawdź efekt działania. Działająca aplikacja pozwoli otworzyć okna dzieci z poziomu okna pierwszego dziecka
Krok 2. Deklarujemy zmienne publiczne i funkcję publiczną w Form7
W oknie 2 (Form6) będziemy pracować na zmiennych zadeklarowanych w innej klasie. Zmienne te muszą mieć charakter publiczny. Deklarujemy dwie publiczne zmienne typu rzeczywistego
Wskazówka:
public partial class Form7 : Form
{
public float a, b;
Ze względu na ćwiczeniowy charakter tej aplikacji pokażę dwie metody użycia komponentu Label z poziomu innego okna dziecka. Do tego celu będzie potrzebna publiczna zmienna rzutowania na komponent Label
Wskazówka:
public float a, b;
public Label _label2 => label2;
I dla drugiego sposobu- publiczna funkcja
Wskazówka:
public void Dodawanie()
{
label2.Text = a.ToString()+"+"
+b.ToString()+"="
+(a + b).ToString();
}
Krok 3. Użycie publicznej funkcji w innej klasie okna dziecka
W zdarzeniu Click przycisku button1 w Form6 odwołamy się do zmiennych a i b oraz funkcji Dodaj z klasy okna Form7. Po przypisaniu im wartości w oknie klasy Form6 wyślemy wynik dodawania do okna Form7. Kod, który to umożliwi może przyjąć poniższą postać
Wskazówka:
private void Button1_Click(object sender, EventArgs e)
{
Form7.Instancja.a = (float)Convert.ToDouble(textBox1.Text);
Form7.Instancja.b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja.Dodawanie();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
Skompiluj program i sprawdź efekt działania. Prawidłowo działając aplikacja zachowuj się jak poniżej
Krok 4. Użycie publicznego rzutowania na komponent okna dziecka
Tu przedstawię inne podejście do sterowani zmiennymi zewnętrznej klasy okna dziecka w oknie klasy innego dziecka. Działanie jest bardzo podobne jak w kroku 3, z tą różnicą, że wykorzystujemy bezpośrednio właściwości komponentu poprzez jego rzutowanie.
Kod zdarzenia Click drugiego przycisku button2 formatki Form6 zawiera poniższe wiersze
Wskazówka:
private void Button2_Click(object sender, EventArgs e)
{
float a = (float)Convert.ToDouble(textBox1.Text);
float b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja._label2.Text= a.ToString() +
"*" + b.ToString() +
"=" + (a * b).ToString();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
Kompilacja aplikacji pozwoli uzyskać poniższe zachowanie się programu
Ćwiczenie sprawdzające: Zabezpiecz aplikację przed błędami konwersji
Kody plików formatek okna głownego i okien potomnych
Okno główne
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form1 : Form
{
public Form2 form2;
public Form3 form3;
public Form4 form4;
public Form1()
{
InitializeComponent();
}
private void ZamknijToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void Okno1ToolStripMenuItem_Click(object sender, EventArgs e)
{
//otwarcie jednego konkretnego okna
//zabezpiecz przed wielokrotnym powielaniem tworzenia okna
if (form2 == null)
{
form2 = new Form2();
form2.MdiParent = this;
form2.Tag = "okno1";
form2.FormClosed += new FormClosedEventHandler(zwolnijUchwyt);
form2.Show();
}
else form2.Activate();
}
//uniwersalna funkcja otwierająca nowe okno dla metody pierwszej
public void RobOkno(Form f, string tag)
{
f.MdiParent = this;
f.Tag = tag;
f.FormClosed += new FormClosedEventHandler(zwolnijUchwyt);
f.Show();
f.Activate();
}
public void zwolnijUchwyt(object sender, FormClosedEventArgs e)
{
Form f =sender as Form;
switch (f.Tag.ToString())
{
case "okno1": form2 = null; break;
case "okno2": form3 = null; break;
case "okno3": form4 = null; break;
}
}
private void Okno2ToolStripMenuItem_Click(object sender, EventArgs e)
{
//zabezpiecz przed wielokrotnym powielaniem tworzenia okna
if (form3 == null) RobOkno(form3 = new Form3(), "okno2");
else form3.Activate();
}
private void Okno3ToolStripMenuItem_Click(object sender, EventArgs e)
{
//zabezpiecz przed wielokrotnym powielaniem tworzenia okna
if (form4 == null) RobOkno(form4 = new Form4(), "okno3");
else form4.Activate();
}
//Uniwersalna funkcja tworząca instancję okna metoda druga
void RobOknoInstancji(Form f,string tag)
{
f.MdiParent = this;
f.Tag = tag;
f.Show();
f.Activate();
}
private void OknoInstancja1ToolStripMenuItem_Click(object sender, EventArgs e)
{
RobOknoInstancji(Form5.Instancja, "OknoInstnacj1");
//przykład wypełnienia metody Text instnacji nowego okna
Form5.Instancja.Text = "Okno Instancji 1";
}
private void OknoInstancja2ToolStripMenuItem_Click(object sender, EventArgs e)
{
RobOknoInstancji(Form6.Instancja, "OknoInstnacj2");
//przykład wypełnienia metody Text instnacji nowego okna
Form6.Instancja.Text = "Okno Instancji 2";
Form6.Instancja.Width = this.Width / 2;
Form6.Instancja.Height = this.Height / 2;
}
private void OknoInstancja3ToolStripMenuItem_Click(object sender, EventArgs e)
{
RobOknoInstancji(Form7.Instancja, "OknoInstnacj3");
//przykład wypełnienia metody Text instnacji nowego okna
Form7.Instancja.Text = "Okno Instancji 3";
Form7.Instancja.Width = this.Width / 2;
Form7.Instancja.Height = this.Height / 2;
}
}
}
Okno potomne Form2.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form3 == null) {
f.form3 = new Form3();
f.RobOkno(f.form3, "okno2");
//lub taką konstrukcję
//f.RobOkno(f.form3 = new Form3(), "okno2");
}
else f.form3.Activate();
}
private void Button2_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form4 == null)f.RobOkno(f.form4 = new Form4(), "okno3");
else f.form4.Activate();
}
}
}
Okno potomne Form3.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno1
if(f.form2!=null)f.form2.Close();
}
}
}
Okno potomne Form4.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno2
if (f.form3 != null) f.form3.Close();
}
}
}
Okno potomne Form5.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form5 : Form
{
private static Form5 instancja;
public static Form5 Instancja {
get
{
//zabezpiecz przed wielokrotnym tworzeniem klasy okna
if (instancja == null) instancja = new Form5();
return instancja;
}
}
public Form5()
{
InitializeComponent();
}
private void Form5_FormClosed(object sender, FormClosedEventArgs e)
{
//zwolnij uchwyt instancji klasy w momencie zamykania okna
instancja = null;
}
private void Button1_Click(object sender, EventArgs e)
{
Form6.Instancja.MdiParent = this.MdiParent;
Form6.Instancja.Text="Okno II otwarte z okna I";
Form6.Instancja.Show();
Form6.Instancja.Activate();
}
private void Button2_Click(object sender, EventArgs e)
{
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna I";
Form7.Instancja.Show();
Form6.Instancja.Activate();
}
}
}
Okno potomne Form6.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form6 : Form
{
private static Form6 instancja;
public static Form6 Instancja
{
get
{
//zabezpiecz przed wielokrotnym tworzeniem klasy okna
if (instancja == null) instancja = new Form6();
return instancja;
}
}
public Form6()
{
InitializeComponent();
}
private void Form6_FormClosing(object sender, FormClosingEventArgs e)
{
instancja = null;
}
private void Button1_Click(object sender, EventArgs e)
{
Form7.Instancja.a = (float)Convert.ToDouble(textBox1.Text);
Form7.Instancja.b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja.Dodawanie();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
private void Button2_Click(object sender, EventArgs e)
{
float a = (float)Convert.ToDouble(textBox1.Text);
float b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja._label2.Text= a.ToString() +
"*" + b.ToString() +
"=" + (a * b).ToString();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
}
}
Okno potomne Form7.cs
Wskazówka:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace wieleOkien
{
public partial class Form7 : Form
{
public float a, b;
public Label _label2 => label2;
private static Form7 instancja;
public static Form7 Instancja
{
get{
if (instancja == null) instancja = new Form7();
return instancja;
}
}
public void Dodawanie()
{
label2.Text = a.ToString()+"+"
+b.ToString()+"="
+(a + b).ToString();
}
public Form7()
{
InitializeComponent();
}
private void Form7_FormClosed(object sender, FormClosedEventArgs e)
{
instancja = null;
}
}
}