18. fejezet - Windows Form (szerző: Radványi Tibor)

Tartalom

A form és tulajdonságai
Alapvető komponensek, adatbekérés és megjelenítés
Választások
Listák kezelése
Egyéb eszközök, idő, dátum, érték beállítás
Menük és eszköztárak
Több info egy formon
Dialógusok
Modális és nem modális formok
Időzítés és üzenetek

A form és tulajdonságai

18.1. feladat (Form sarokba igazítása gombnyomásraszint: 1). Készíts WindowsForm alkalmazást, mely a képernyő 4 sarkába ugorhat. Legyen rajta 4 button, amelyre kattintva a form – a feliratának megfelelő – sarokba ugrik.

18.1. ábra. Működés közben.

Magyarázat: Figyeljünk arra, hogy ne adjuk meg előre a lehetséges felbontás értékeit, helyette használjuk a Screen.PrimeryScreen objektum Bounds tulajdonságait.

18.1. forráskód. A Form sarokba igazítása

     
public partial class Frm_Sarokba : Form 
{ 
      private void Bt_BF_Click(object sender, EventArgs e) 
      { 
            Left = 0; 
            Top = 0; 
      } 
 
      private void Bt_JF_Click(object sender, EventArgs e) 
      { 
            Left = Screen.PrimaryScreen.Bounds.Width - Width; 
            Top = 0; 
      } 
 
      private void Bt_BL_Click(object sender, EventArgs e) 
      { 
            Left = 0; 
            Top = Screen.PrimaryScreen.Bounds.Height - Height; 
      } 
 
      private void Bt_JL_Click(object sender, EventArgs e) 
      { 
            Left = Screen.PrimaryScreen.Bounds.Width - Width; 
            Top = Screen.PrimaryScreen.Bounds.Height - Height; 
      } 
}
    

18.2. feladat (Szöveg igazításaszint: 1). Készíts WindowsForm alkalmazást, amely a label komponens szövegigazításait demonstrálja. A formon egy label legyen található, ami a form egész területét elfoglalja. A label egyes részeire kattintva változtathatjuk a szöveg igazítását.

18.2. ábra. Működés közben.

Magyarázat: A 9 külön lehetőség miatt ne hozzunk létre komponenseket, és írjunk külön eseménykezelőket. Helyette képzeletben osszuk fel a form területét, és a kattintásokkor ez alapján állítsuk be a label komponens szövegének elrendezését.

18.2. forráskód. A szöveg igazítása

     
private void label_MouseClick(object sender, MouseEventArgs e) 
{ 
   int n = e.X / (label.Width / 3); 
   int m = e.Y / (label.Height / 3); 
   switch (m * 3 + n) 
   { 
      case 0: label.TextAlign = ContentAlignment.TopLeft; break; 
      case 1: label.TextAlign = ContentAlignment.TopCenter; break; 
      case 2: label.TextAlign = ContentAlignment.TopRight; break; 
      case 3: label.TextAlign = ContentAlignment.MiddleLeft; break; 
      case 4: label.TextAlign = ContentAlignment.MiddleCenter; break; 
      case 5: label.TextAlign = ContentAlignment.MiddleRight; break; 
      case 6: label.TextAlign = ContentAlignment.BottomLeft; break; 
      case 7: label.TextAlign = ContentAlignment.BottomCenter; break; 
      case 8: label.TextAlign = ContentAlignment.BottomRight; break; 
   } 
}
    

18.3. feladat (Form és Label koordinátáinak kiírásaszint: 1). Írjon WindowsForm alkalmazást, amely az egér aktuális pozícióját írja ki. A pozíció rögtön frissüljön a fejlécben, ahogy az egér megmozdul. Legyen a form közepén egy panel, ami fölé érve az egér pozíciója a panelhez relatív legyen, vagyis a panel bal felső sarkában 0,0.

18.3. ábra. Működés közben.

Magyarázat: Figyeljünk arra, hogy a panel a form közepén mindig pontosan középen legyen, és a form méretének negyedét foglalja csak el, akkor is, ha átméretezik az ablakot, ehhez iratkozzunk fel a form átméretezésének eseményére.

18.3. forráskód. Egér koordinátáinak kiírása

     
private void Frm_Holmozog_MouseMove(object sender, MouseEventArgs e) 
{ 
   Text = String.Format("Az egér koordinátái X:{0}, Y:{1}", e.X, e.Y); 
} 
 
private void Frm_Holmozog_Resize(object sender, EventArgs e) 
{ 
   PanelIgazit(); 
} 
 
private void Frm_Holmozog_Load(object sender, EventArgs e) 
{ 
   PanelIgazit(); 
} 
 
private void PanelIgazit() 
{ 
   panel.Left = (ClientSize.Width - panel.Width) / 2; 
   panel.Top = (ClientSize.Height - panel.Height) / 2; 
}
    

18.4. feladat (Form mozgatásaszint: 2). Írjon WindowsForm alkalmazást, amellyel a form pozíciójának, méretének és átlátszóságának változásait mutathatja be. Két gomb szolgáljon a form méretének csökkentésére és növelésére. Adjunk meg minimális méretet a formnak, ami alá nem csökkenhet. Az átlátszóság 20% alá ne mehessen. A teljesen gombok-ra ugorjon a form teljesen a képernyő szélére a megfelelő irányba, majd tűnjön el, hogy ne lehessen megnyomni ha már az ablak szélére került a form, viszont jelenjen meg újra, ha elhagytuk azt valamelyik másik gomb segítségével. A balra, fel, jobbra, le gombok konstansként meghatározott mértékben mozgassák az ablakot, és ugyancsak ne látszódjanak, ha már a képernyő szélére került a form. A középre gomb hatására a form foglalja el pontosan a képernyő közepét (ilyenkor látszódjon minden gomb).

18.4. ábra. Működés közben.

Magyarázat: Akárcsak az első feladatnál, itt is használjuk a Screen.PrimeryScreen.Bounds tulajdonságot a képernyő méreteihez. Figyeljünk arra, hogy ha elértük a határokat tüntessük el a megfelelő gombokat.

18.4. forráskód. Form jellemzői

     
private void Bt_M_Cso_Click(object sender, EventArgs e) 
{ 
   Width -= meretezo; 
   Height -= meretezo; 
} 
 
private void Bt_Atl_No_Click(object sender, EventArgs e) 
{ 
   if (Opacity < 1.0) 
      Opacity += 0.1; 
} 
 
private void Bt_Kozep_Click(object sender, EventArgs e) 
{ 
   Left = (Screen.PrimaryScreen.Bounds.Width - Width) / 2; 
   Top = (Screen.PrimaryScreen.Bounds.Height - Height) / 2; 
   Bt_Le.Visible = Bt_Le_T.Visible = 
   Bt_Fel.Visible = Bt_Fel_T.Visible = 
   Bt_Bal.Visible = Bt_Bal_T.Visible = 
   Bt_Jobb.Visible = Bt_Jobb_T.Visible = true; 
}
    
                                                                                                                                     

                                                                                                                                     
    

18.5. forráskód. Form mozgatása

 
private void Bt_Fel_T_Click(object sender, EventArgs e) 
{ 
   Top = 0; 
   Bt_Fel.Visible = Bt_Fel_T.Visible = false; 
   Bt_Le.Visible = Bt_Le_T.Visible = true; 
} 
 
private void Bt_Fel_Click(object sender, EventArgs e) 
{ 
   if (Top - meretezo > 0) 
   { 
      Top -= meretezo; 
   } 
   else 
   { 
      Top = 0; 
      Bt_Fel.Visible = Bt_Fel_T.Visible = false; 
   } 
   Bt_Le.Visible = Bt_Le_T.Visible = true; 
}

Alapvető komponensek, adatbekérés és megjelenítés

18.5. feladat (ScrollBar használataszint: 2). Írjon programot, amely az additív színkeverést mutatja be. Egy négyzet alakú label háttérszíne mutassa a kevert színt. Három scrollbar komponenssel lehessen állítani a szín piros, kék, és zöld összetevőjét. Akármelyik csúszka pozíciója változik, rögtön frissüljön a szín. A színt mutató label méretét szintén egy csúszkával lehessen változtatni, ez 10 és 300 pixel közötti érték lehet.

Magyarázat: Ne felejtse el beállítani a scrollbarok minimum és maximum értékeit.

18.5. ábra. Működés közben.

18.6. forráskód. ScrollBar használata

     
public partial class Frm_Csuszka : Form 
{ 
   private void Sb_Piros_ValueChanged(object sender, EventArgs e) 
   { 
      Lb_Negyzet.BackColor = Color.FromArgb(Sb_Piros.Value, 
                       SB_Zold.Value, SB_Kek.Value); 
   } 
 
   private void Sb_Oldal_ValueChanged(object sender, EventArgs e) 
   { 
      Lb_Negyzet.Width = Lb_Negyzet.Height = Sb_Oldal.Value; 
      Lb_Oldal.Text = Sb_Oldal.Value.ToString(); 
   } 
}
    

18.6. feladat (Képet forgatszint: 1). Írjon programot, mely köralakban jelenít meg képeket, és mindkét irányba körbe léptethetőek.

18.6. ábra. Működés közben.

Magyarázat: A képek egymás közti forgatásához vegyünk fel egy Image típusú segédváltozót.

18.7. forráskód. Forgat

     
public partial class Frm_Kepforog : Form 
{ 
   private void Pb_Bal_Click(object sender, EventArgs e) 
   { 
      Image s = Lb_1.Image; 
      Lb_1.Image = Lb_2.Image; 
      Lb_2.Image = Lb_3.Image; 
      Lb_3.Image = Lb_4.Image; 
      Lb_4.Image = Lb_5.Image; 
      Lb_5.Image = Lb_6.Image; 
      Lb_6.Image = Lb_7.Image; 
      Lb_7.Image = Lb_8.Image; 
      Lb_8.Image = s; 
   } 
}
    

18.7. feladat (Futásidejű komponensekszint: 2). Készítsen programot, ami minden egérkattintáskor egy-egy új label komponenst hoz létre dinamikusan. Az új label felirata legyen egy véletlen szám 1 és 100 között. Számoljuk, hogy mennyi új komponens jött létre, mi a véletlen számok összege, átlaga, minimuma és maximuma.

18.7. ábra. Működés közben.

Magyarázat: A min és max változók inicializálásánál célszerű az int típus szélsőértékeit használni, hiszen pl. a int.MinValue-nál csak nagyobb számot generálhatunk. Véletlen szám generálásnál figyeljünk a határokra, a Random(100) 0 és 99 közötti számot generál, ezt még el kell tolni egyel. Az újonnan létrehozott label komponenst ne felejtsük el hozzáadni a form Controls tömbjéhez, hisz csak ekkor fog megjelenni. Átlagszámításnál figyeljünk arra, hogy az osztót (db) lebegőpontosra kell alakítani, mert különben egész osztást alkalmaz a fordító.

18.8. forráskód. Futás idejű létrehozás

     
public partial class Frm_Dinamikus : Form 
{Random random = new Random(); 
double atlag; int osszeg, db, min = int.MaxValue, max = int.MinValue;} 
private void Frm_Dinamikus_MouseClick(object sender, MouseEventArgs e) 
{  int i = random.Next(100) + 1; 
   Label lb = new Label(); 
   lb.Location = new Point(e.X, e.Y); 
   lb.Text = i.ToString(); 
   lb.AutoSize = true; 
   Controls.Add(lb); 
   db++; 
   osszeg += i; 
   atlag = osszeg / (double)db; 
   if (min > i) min = i; 
   if (max < i) max = i; 
   lb_Eredmeny.Text = 
    String.Format("Darabszám: {0}, összeg: {1}, átlag: {2}," 
              +"minimum: {3}, maximum: {4}.", 
              db, osszeg, atlag, min, max); } }
    

18.8. feladat (Halmazokszint: 3). Írjon programot, amely bemutatja két halmaz közötti műveleteket. Egy-egy halmaznak egy-egy listbox komponensek feleljen meg. Kezdetben legyen üres mind az A, és B halmaz is. Mindkét halmaz elemszámát kérjük be, majd töltsük fel őket véletlen számokkal, és számoljuk ki A unió B -t, A metszet B-t, A-B és B-A eredményét is.

Magyarázat: A feltöltésnél figyeljünk arra, hogy nem csak egyszerű adatsorozatot készítünk, hanem halmazt, melynek fő tulajdonsága, hogy egy elem csak egyszer szerepelhet benne.

18.9. forráskód. Halmaz generálása

     
private void Bt_Eloall_Click(object sender, EventArgs e) 
{ 
   HalmazGeneral(LBx_A, Convert.ToInt32(TBx_A.Text)); 
   HalmazGeneral(LBx_B, Convert.ToInt32(TBx_B.Text)); 
   Metszet(LBx_A, LBx_B, LBx_Metsz); 
   Unio(LBx_A, LBx_B, LBx_Unio); 
   Minusz(LBx_A, LBx_B, LBx_A_B); 
   Minusz(LBx_B, LBx_A, LBx_B_A); 
} 
 
private void HalmazGeneral(ListBox LB, int N) 
{ 
   int elem; 
   LB.Items.Clear(); 
   for (int i = 0; i < N; i++) 
   { 
      do 
      { 
       elem = random.Next(N * 5); 
      } 
      while (Bennevan(LB, elem)); 
      LB.Items.Add(elem); 
   } 
} 
 
private bool Bennevan(ListBox LB, object elem) 
{ 
   for (int i = 0; i < LB.Items.Count; i++) 
      if (LB.Items[i].Equals(elem)) 
            return true; 
   return false; 
}
    

18.8. ábra. Működés közben.

18.10. forráskód. Halmazműveletek

 
private void Unio(ListBox LBx_A, ListBox LBx_B, ListBox LBx_Unio) 
{ 
   LBx_Unio.Items.Clear(); 
   for (int i = 0; i < LBx_A.Items.Count; i++) 
   { 
      if (!Bennevan(LBx_Unio, LBx_A.Items[i])) 
      { 
         LBx_Unio.Items.Add(LBx_A.Items[i]); 
      } 
   } 
   for (int i = 0; i < LBx_B.Items.Count; i++) 
   { 
      if (!Bennevan(LBx_Unio, LBx_B.Items[i])) 
      { 
         LBx_Unio.Items.Add(LBx_B.Items[i]); 
      } 
   } 
} 
 
private void Metszet(ListBox LBx_A, ListBox LBx_B, ListBox LBx_Metsz) 
{ 
   LBx_Metsz.Items.Clear(); 
   for (int i = 0; i < LBx_A.Items.Count; i++) 
   { 
      if (Bennevan(LBx_B, LBx_A.Items[i])) 
      { 
         LBx_Metsz.Items.Add(LBx_A.Items[i]); 
      } 
   } 
}

18.9. feladat (Mátrixszint: 4). Készítsen programot, mely egy mátrix elemeit feltölti véletlen számokkal, majd kiírja melyik a legkisebb, ill. legnagyobb szám, és hol vannak. A mátrixot jelenítse meg egy DataGridView komponensben, oszlopainak és sorainak száma 2 és 10 közötti - nem feltétlenül egyenlő - számok legyenek, és a felhasználó adhassa meg NumericUpDown komponenssel.

Magyarázat: A NumericUpDown komponensnél ne felejtsük el beállítani a határokat. A grid kialakításánál figyeljünk oda, hogy letiltsuk azt (ReadOnly property), illetve ne látszódjanak az oszlop- és sorfejlécek (ColumnHeadersVisible, RowHeadersVisible property-k).

18.9. ábra. Működés közben.

Magyarázat: Feltöltéskor ne felejtsük el létrehozni az oszlopokat a táblázatba, és csak ezután adjuk hozzá a véletlen számokból álló sorokat.

18.11. forráskód. Feltölt

     
private void AdatokFeltolt(int N, int M) 
{ 
   dataGridView.Columns.Clear(); 
   dataGridView.Rows.Clear(); 
 
   for (int j = 0; j < M; j++) 
   { 
      dataGridView.Columns.Add(String.Empty, String.Empty); 
      dataGridView.Columns[j].Width = 35; 
   } 
   for (int i = 0; i < N; i++) 
   { 
      object[] intArrray = new object[M]; 
      for (int j = 0; j < M; j++) 
      { 
         intArrray[j] = random.Next(N * M * 10) + 1; 
      } 
      dataGridView.Rows.Add(intArrray); 
   } 
}
    

Magyarázat: A táblázat feldolgozásakor ne felejtsük, hogy a táblázat cellái object típusúként vannak eltárolva, felhasználásukkor át kell alakítani (castolni) int típusúra őket.

A eredmény kiárásához használt RichTextBox komponens szövegét ne felejtsük el alaphelyzetbe állítani (ResetText metódus), és csak ezután írjunk bele (AppendText).

18.12. forráskód. Eredmény

     
private void EredmenyKiir(int N, int M) 
{ 
   int max = int.MinValue, 
      min = int.MaxValue; 
 
   int maxi, maxj, mini, minj; 
   maxi = maxj = mini = minj = 0; 
 
   for (int i = 0; i < N; i++) 
   { 
      for (int j = 0; j < M; j++) 
      { 
         if ((int)dataGridView[j, i].Value > max) 
         { 
            max = (int)dataGridView[j, i].Value; 
            maxi = i; 
            maxj = j; 
         } 
         if ((int)dataGridView[j, i].Value < min) 
         { 
            min = (int)dataGridView[j, i].Value; 
            mini = i; 
            minj = j; 
         } 
      } 
   } 
   richTextBox.ResetText(); 
 
   richTextBox.AppendText(String.Format("A legnagyobb elem: {0}{1}", 
            max, Environment.NewLine)); 
   richTextBox.AppendText(String.Format("A legnagyobb elem indexe:" 
        +"({0},{1}){2}", maxi + 1, maxj + 1, Environment.NewLine)); 
   richTextBox.AppendText(String.Format("A legkisebb elem: {0}{1}", 
            min, Environment.NewLine)); 
   richTextBox.AppendText(String.Format("A legkisebb elem indexe:" 
        +"({0},{1}){2}", mini + 1, minj + 1, Environment.NewLine)); 
}
    

18.10. feladat (Szorzótáblaszint: 4). Készítsen programot a szorzótábla gyakorlására. A program véletlenszerűen kérdezzen rá a szorzatokra, jelezze az első sorban és oszlopban más háttérszínnel, hogy éppen melyik két szám szorzatára vagyunk kíváncsiak. Ugyancsak legyen más színű az a cella, ahová az eredményt várjuk, és rajta kívül egyetlen másik cella se legyen szerkeszthető. Elhagyva a cellát a program értékelje a számításunkat, ha jó számot adunk meg, akkor kérje a következő szorzatot, ha rosszat, akkor kérje be újra. A felhasználó két label-ben lássa, hogy hány jó, ill. rossz választ adott meg eddig. Ha minden cellát helyesen kitöltött egy üzenetablakban gratuláljunk neki.

18.10. ábra. Működés közben.

Magyarázat: A 9. feladathoz hasonlóan itt is tiltsuk le a gridben a sor és oszlop fejléceket, de ne állítsuk csak szerkeszthetőre (readonly). A grid szerkesztési módját (EditMode) állítsuk EditOnEnter-re.

18.13. forráskód. Sorsol egy pozíciót

     
private void Sorsol() 
{ 
   do 
   { 
      aktI = random.Next(N) + 1; 
      aktJ = random.Next(N) + 1; 
   } while (dataGridView[aktJ, aktI].Value != null); 
   dataGridView[aktJ, aktI].Style.BackColor = 
      dataGridView[0, aktI].Style.BackColor = 
      dataGridView[aktJ, 0].Style.BackColor = Color.PowderBlue; 
}
    

18.14. forráskód. Feltölti a fejléceket

 
private void TablaEpit() 
{ 
   dataGridView.Columns.Clear(); 
   dataGridView.Rows.Clear(); 
   dataGridView.Width = 35 * (N + 1) + 3; 
   for (int j = 0; j <= N; j++) 
   {  dataGridView.Columns.Add(String.Empty, String.Empty); 
      dataGridView.Columns[j].Width = 35; } 
   for (int i = 0; i <= N; i++) 
   {  object[] intArrray = new object[N]; 
      dataGridView.Rows.Add(intArrray); } 
   for (int i = 1; i <= N; i++) 
   {  dataGridView[i, 0].Value = i; 
      dataGridView[i, 0].Style.Font = new Font(dataGridView.Font, 
                                    FontStyle.Bold); } 
 
   for (int j = 1; j <= N; j++) 
   {  dataGridView[0, j].Value = j; 
      dataGridView[0, j].Style.Font = new Font(dataGridView.Font, 
                                    FontStyle.Bold); } 
}

Magyarázat: Az új kérdés sorsolásakor figyeljünk arra, hogy olyan szorzatot válasszunk, amit még nem töltött ki a felhasználó, és sor-, ill. oszlopindexét tároljuk el változókban, ezek alapján tudjuk figyelni a grid CellBeginEdit eseményében, hogy a megfelelő cellát kezdi-e el szerkeszteni a felhasználó.

18.15. forráskód. Ellenőriz

 
private void dataGridView_CellEndEdit(object sender, 
                  DataGridViewCellEventArgs e) 
{ 
   if (dataGridView[aktJ, aktI].Value == null) return; 
 
   if (aktI * aktJ == Convert.ToInt32(dataGridView[aktJ, aktI].Value)) 
   {  dataGridView[aktJ, aktI].Style.BackColor = 
              dataGridView.DefaultCellStyle.BackColor; 
      dataGridView[0, aktI].Style.BackColor = 
         dataGridView[aktJ, 0].Style.BackColor = 
         dataGridView.DefaultCellStyle.BackColor; 
      joValasz++; 
      lb_Joalasz.Text = String.Format("Jó válaszaid száma: {0}", 
                              joValasz); 
      if (joValasz < N * N) 
      { Sorsol(); } 
      else 
      { MessageBox.Show("Gratulálok, kész a szorzótábla!"); 
       dataGridView.Enabled = false; } 
   } 
   else 
   {  dataGridView[aktJ, aktI].Value = null; 
      rosszValasz++; 
      lb_Rosszvalasz.Text = String.Format("Rossz válaszaid száma:" 
                                 +"{0}", rosszValasz); 
      MessageBox.Show("Rossz válasz!"); } 
}

Választások

18.11. feladat (LNKO LKKTszint: 1). Írjon programot, mely bekér két egész számot, és kiszámolja azok legnagyobb közös osztóját (LNKO) és legkisebb közös többszörösét (LKKT). Hogy épp melyiket számolja ki, azt rádiógombokkal lehessen beállítani. Külön gomb szolgáljon a kilépésre.

18.11. ábra. Működés közben.

Magyarázat: Elég megírjuk az lnko algoritmusát, hiszen a legkisebb közös többszöröst az (a*b)/LNKO(a,b) képlet megadja.

18.16. forráskód. Kiszámolás

     
public int LNKO(int a, int b) 
{ 
   if (a == 0) 
      return b; 
   if (b == 0) 
      return a; 
 
   if (a > b) 
      return LNKO(a % b, b); 
   else 
      return LNKO(a, b % a); 
}
    

Magyarázat: Az int.TryParse(...) metódusával ellenőrizzük le hogy tényleg számot adott-e meg a felhasználó, és csak ez után számoljunk.

18.17. forráskód. Művelet elvégzése

 
private void button1_Click(object sender, EventArgs e) 
{ 
   int a, b; 
 
   // Adatok ellenőrzése számítás előtt 
 
   if (!int.TryParse(TBx_A.Text, out a)) 
   { 
      MessageBox.Show("Nem megfelelő szám!"); 
      TBx_A.Text = String.Empty; 
      TBx_A.Focus(); 
      return; 
   } 
 
   if (!int.TryParse(TBx_B.Text, out b)) 
   { 
      MessageBox.Show("Nem megfelelő szám!"); 
      TBx_B.Text = String.Empty; 
      TBx_B.Focus(); 
      return; 
   } 
 
   if (Rb_LNKO.Checked) 
   { 
      MessageBox.Show(String.Format( 
         "A két szám legnagyobb közös osztója: {0}", 
         LNKO(a, b))); 
   } 
   else 
   { 
      MessageBox.Show(String.Format( 
         "A két szám legkisebb közös többszöröse: {0}", 
         (a * b) / LNKO(a, b))); 
   } 
}
                                                                                                                                     

                                                                                                                                     
    

18.12. feladat (Formázásszint: 2). Készítsünk alkalmazást, mely egy szöveg betűtípusának beállításait mutatja be. Lehessen beállítani a betűtípus méretét, stílusát (dőlt, aláhúzott, félkövér), típusát (3 választás: Arial, Times New Roman, Comic Sans). Használjunk ComboBox és CheckBox komponenseket. Állítható legyen továbbá a label szövegének és hátterének színe is. Adjon lehetőséget a program a label szövegének átírására is.

18.12. ábra. Működés közben.

18.18. forráskód. Változtatás kezelése

 
private void Cbx_Piros_CheckedChanged(object sender, EventArgs e) 
{ 
  if (Comb_Mit.SelectedIndex == 0) 
  { 
     Lb_Proba.ForeColor = SzinBeallit(); 
  } 
  else 
  { 
     Lb_Proba.BackColor = SzinBeallit(); 
  } 
}

18.19. forráskód. Font beállításai

     
private void FontBeallit() 
{ 
   Lb_Proba.Font = new Font(GetFontName(), 
      (int)NDD_Fontmeret.Value, GetFontStyle()); 
} 
 
private FontStyle GetFontStyle() 
{ 
   FontStyle result = FontStyle.Regular; 
   if (Cbx_Alahuz.Checked) 
      result |= FontStyle.Underline; 
   if (Cbx_Dolt.Checked) 
      result |= FontStyle.Italic; 
   if (Cbx_Felk.Checked) 
      result |= FontStyle.Bold; 
   return result; 
} 
 
private string GetFontName() 
{ 
   if (Rb_Arial.Checked) 
      return Rb_Arial.Text; 
   else if (Rb_CS.Checked) 
      return Rb_CS.Text; 
   else if (Rb_TNR.Checked) 
      return Rb_TNR.Text; 
   return String.Empty; 
}
    

Magyarázat: A GetFontStyle metódusban használjuk ki, hogy a FontStyle felsorolástípus maszkolható, vagyis az aláhúzás, dőlt betű és a vastag betűs tulajdonságokat egymástól függetlenül is be lehet állítani a ’|’ operátor segítségével.

18.20. forráskód. Szín beállítás és ComboBox

 
private Color SzinBeallit() 
{ 
   return Color.FromArgb( 
      Cbx_Piros.Checked ? 255 : 0, 
      Cbx_Zold.Checked ? 255 : 0, 
      Cbx_Kek.Checked ? 255 : 0 
   ); 
} 
 
private void Comb_Mit_SelectedIndexChanged(object sender, EventArgs e) 
{ 
   GB_Font.Enabled = GB_Stilus.Enabled = NDD_Fontmeret.Enabled = 
      (Comb_Mit.SelectedIndex == 0); 
   CheckBoxokBeallit((Comb_Mit.SelectedIndex == 0) ? 
      Lb_Proba.ForeColor : Lb_Proba.BackColor); 
}

Magyarázat: A színek beállításánál a kijelöléstől függően állítsuk a szín adott komponensét 0, vagy 255 értékre.

18.13. feladat (Logikai műveletekszint: 2). Készítsen programot, mely bemutatja a matematikai logikai műveleteket. Egy combobox-ból lehessen kiválasztani az aktuális műveletet, az operandusok (A és B, vagy csak A) értékét checkbox komponenssel állítsuk be. Ezen kívül a program írja ki a számolási szabályokat a műveletek között: kommutativitás, asszociativitás, disztributivitás.

18.13. ábra. Működés közben.

Magyarázat: Figyeljünk arra, hogy attól függően, hogy 1 vagy 2 operandusú az operátor, csak annyi bemeneti adat (CheckBox) legyen kötelező.

18.21. forráskód. ComboBox kezelése

     
private void Frm_Logika_Load(object sender, EventArgs e) 
{ 
   comboBoxMuvelet.SelectedIndex = 0; 
} 
 
private void comboBoxMuvelet_SelectedIndexChanged(object sender, 
      EventArgs e) 
{ 
   Cbx_B.Enabled = comboBoxMuvelet.SelectedIndex != 0; 
}
    

18.22. forráskód. Logikai műveletek

 
private void Bt_Eredmeny_Click(object sender, EventArgs e) 
{ 
   switch (comboBoxMuvelet.SelectedIndex) 
   { 
   case 0: MessageBox.Show(String.Format("not A = {0}", 
                             !Cbx_A.Checked)); 
         break; 
   case 1: MessageBox.Show(String.Format("A and B = {0}", 
                     Cbx_A.Checked & Cbx_B.Checked)); 
         break; 
   case 2: MessageBox.Show(String.Format("A or B = {0}", 
                     Cbx_A.Checked | Cbx_B.Checked)); 
         break; 
   case 3: MessageBox.Show(String.Format("A nand B = {0}", 
                  !(Cbx_A.Checked & Cbx_B.Checked))); 
         break; 
   case 4: MessageBox.Show(String.Format("A nor B = {0}", 
                  !(Cbx_A.Checked | Cbx_B.Checked))); 
         break; 
   case 5: MessageBox.Show(String.Format("A xor B = {0}", 
                     Cbx_A.Checked ^ Cbx_B.Checked)); 
         break; 
   } 
} 
 
 
private void Rb_Komm_CheckedChanged(object sender, EventArgs e) 
{ 
   if (Rb_Komm.Checked) 
   { 
      Lb_SzSz.Text = "A and B = B and A" + Environment.NewLine + 
                  "A or B = B or A"; 
   } 
   else if (Rb_Assz.Checked) 
   { 
      Lb_SzSz.Text = "A and (B and C) = (A and B) and C" + 
                  Environment.NewLine + 
                  "A or (B or C) = (A or B) or C"; 
   } 
   else if (Rb_Disz.Checked) 
   { 
      Lb_SzSz.Text = "A and (B or C) = (A and B) or (A and C)" + 
                  Environment.NewLine + 
                  "A or (B and C) = (A or B) and (A or C)"; 
   } 
}

18.14. feladat (Jegykiadó programszint: 2). Írjon programot, ami különböző paraméterek alapján kiszámol egy vonatjegy árat. Lehessen megadni, hogy hova utazunk (Budapest 1500Ft, Hatvan 1300Ft, Székesfehérvár 2000Ft, Kecskemét 2800Ft), milyen kedvezményünk van (nappali tagozatos diák 50%, nyugdíjas 50%, törzsutas kártya 70%), és hogy milyen egyéb szolgáltatásokat kell igénybe vennünk (kutya 800Ft, bicikli 600Ft, túlméretes poggyász 400Ft). A beállítások után egy gombra kattintva írja ki a program a fizetendő árat, egy másik gomb pedig adjon lehetőséget a beállítások törlésére.

18.14. ábra. Működés közben.

Magyarázat: Nem lehet igénybe venni egyszerre nappali tagozatos diák és nyugdíjas kedvezményt.

18.23. forráskód. Számol

     
private void NyomtatásButton_Click(object sender, EventArgs e) 
{ 
   double díj = 0; 
 
   if (Cbx_Napp.Checked && Cbx_Nyug.Checked) 
   {  Lb_Koltseg.Text = "Hiba!"; 
      return; 
   } 
   if (Rb_Bud.Checked) díj = 1500; 
   if (Rb_Hat.Checked) díj = 1300; 
   if (Rb_Szek.Checked) díj = 2000; 
   if (Rb_Kecs.Checked) díj = 2800; 
   if (Cbx_Kutya.Checked) díj = díj + 800; 
   if (Cbx_Bicikli.Checked) díj = díj + 600; 
   if (Cbx_Poggy.Checked) díj = díj + 400; 
   if (Cbx_Napp.Checked) díj = díj * 0.5; 
   if (Cbx_Nyug.Checked) díj = díj * 0.5; 
   if (Cbx_Torzs.Checked) díj = díj * 0.7; 
   Lb_Koltseg.Text = díj + " Ft"; }
    

Listák kezelése

18.15. feladat (Rendezések hatékonyságaszint: 3). Készítsen programot, mely rendezéseket hasonlít össze. Generáljunk egy ListBox komponensbe 10000 és 20000 közti véletlen darabszámú 0 és 1000 közötti véletlenszámot. Ezeken az elemeken mérjük le a minimumkiválasztos, beszúrásos, buborékos rendezéseket, valamint a ListBox beépített rendezését (.Sort()). Írjuk ki az egyes rendezések után, hány másodpercbe kerültek. 1-1 ProgressBar komponensen érzékeltessük az arányokat. Ha új számokat generálunk, töröljük az eddigi időeredményeket.

18.15. ábra. Működés közben.

Magyarázat: Amíg nincs meg az adott rendezéshez tartozó időeredmény, addig a hozzá tartozó label és progressbar ne látszódjon a felületen.

18.24. forráskód. Véletlen számok generálása

                                                                                                                                     

                                                                                                                                     
     
private void Btn_General_Click(object sender, EventArgs e) 
{ 
   Random rnd = new Random(); 
   Int32 db = rnd.Next(10000) + 10000, akt; 
   listBox.Items.Clear(); 
   listBox.BeginUpdate(); 
   for (Int32 i = 0; i < db; i++) 
   { 
      akt = rnd.Next(1000); 
      listBox.Items.Add(akt); 
      list.Add(akt); 
   } 
   listBox.EndUpdate(); 
   MessageBox.Show(String.Format("Generált elemek száma: {0}", db)); 
   gombok.ForEach(bt => bt.Enabled = true); 
   LB_Beszurasos.Visible = LB_Buborek.Visible = 
       LB_Gyors.Visible = LB_Minkiv.Visible = 
       PB_Beszurasos.Visible = PB_Buborek.Visible = 
       PB_Gyorsrend.Visible = PB_Minkiv.Visible = false; 
   eredmenyek.ForEach(pb => pb.Maximum = Int32.MaxValue); 
}
    

Magyarázat: A számok generálása közben érdemes kikapcsolni a ListBox komponens azonnali frissítését, hogy ne villogjon, és görgessen minden új elem hozzáadásakor. Ezt a BeginUpdate metódussal tehetjük meg, és a feltöltés után az EndUpdate hatására frissül a felületen a listbox. A gombok tömbben található Button objektumok mindegyikének engedélyezéséhez használjuk a generikus List<> adatszerkezet ForEach metódusát, ami egy delegate-et vár, és megadható neki lambda-kifejezés is (bt => bt.Enabled = true).

18.25. forráskód. Minimumkiválasztásos rendezés

 
private void Btn_Minkiv_Click(object sender, EventArgs e) 
{ 
   gombok.ForEach(bt => bt.Enabled = false); 
   DateTime start = DateTime.Now; 
   MinKivRend(new List<Int32>(list)); 
   Double eredmeny = (DateTime.Now - start).TotalSeconds; 
   LB_Minkiv.Text = String.Format("{0} mp", eredmeny); 
   LB_Minkiv.Show(); 
   PB_Minkiv.Value = PB_Minkiv.Maximum = 
      (Int32)Math.Round(eredmeny * 100); 
   Maxok(); 
   PB_Minkiv.Show(); 
   gombok.ForEach(bt => bt.Enabled = true); 
}

18.16. feladat (Lista karbantartásaszint: 3). Készítsünk programot, mely két ListBox karbantartását végzi el. Mindkét ListBox-on a következő műveleteket végezhetjük el: új elem felvétele, kijelölt elem törlése, kijelölt elem mozgatása (felülre, fel, le, alulra) Ehhez készítsünk külön komponenst, mely tartalmaz egy ListBox-ot, és a fenti műveletekhez 1-1 gombot. Egy TextBox-on kérje be az új elemet, és ez is legyen része a komponensnek. A főablakra két ilyen komponenst tegyünk fel, majd egészítsük ki még két publikus metódussal: RemoveSelectedItem, AddNewItem. Ezek segítségével oldjuk meg a két komponens között az elemek átadását.

18.16. ábra. Működés közben.

Magyarázat: A komponens készítésekor ügyeljünk arra, hogy a funkciókat letiltsuk, ha azoknak nincs értelme, pl. üres listából értelmetlen törölni, és a legfelső elemet sem lehet feljebb mozgatni.

18.26. forráskód. Komponensek közti mozgatás

     
private void button3_Click(object sender, EventArgs e) 
{ 
   Object item = listBoxControl1.RemoveSelectedItem(); 
   if (item != null) 
   { 
      listBoxControl2.AddNewItem(item); 
   } 
} 
 
private void button4_Click(object sender, EventArgs e) 
{ 
   Object item = listBoxControl2.RemoveSelectedItem(); 
   if (item != null) 
   { 
      listBoxControl1.AddNewItem(item); 
   } 
}
    

18.27. forráskód. Komponens főbb funkciói

 
private void Btn_Hozzaad_Click(object sender, EventArgs e) 
{  if (TB_Uj.Text != String.Empty) 
   { 
      LB.Items.Add(TB_Uj.Text); 
      TB_Uj.Text = String.Empty; 
      LB.SelectedIndex = LB.Items.Count - 1; 
      GombokFrissit(); 
   } 
   TB_Uj.Focus(); 
} 
 
private void Btn_Torles_Click(object sender, EventArgs e) 
{  Int32 selIndex = LB.SelectedIndex; 
   if (selIndex >= 0) 
   { 
      LB.Items.RemoveAt(selIndex); 
      if (selIndex < LB.Items.Count) 
         LB.SelectedIndex = selIndex; 
      else 
         LB.SelectedIndex = LB.Items.Count - 1; 
      GombokFrissit(); 
   } 
} 
 
private void Btn_Fel_Click(object sender, EventArgs e) 
{  Int32 selIndex = LB.SelectedIndex; 
   if (selIndex > 0) 
   { 
      Object selItem = LB.SelectedItem; 
      LB.Items.RemoveAt(selIndex); 
      LB.Items.Insert(selIndex - 1, selItem); 
      LB.SelectedIndex = selIndex - 1; 
   } 
}

18.17. feladat (Fájl kereséseszint: 3). Írjunk programot, amely megadott elérési úton keres egy maszknak megfelelő fájlokat. Egy TextBox-ban kérjük be az elérési utat és a maszkot, pl. "C:\*.txt". Meg lehessen adni egy CheckBox komponens segítségével, hogy rekurzívan keressünk-e, vagy csak az adott könyvtárban. A talált fájlokat egy ListBox komponensben jelenítsük meg.

18.17. ábra. Működés közben.

18.28. forráskód. Könyvtárszerkezet bejárása

     
public void GetFileList(String dir, String mask, Boolean recursive, 
                  Action<String> action) 
{DirectoryInfo di = new DirectoryInfo(dir); 
   try { 
      FileInfo[] rgFiles = di.GetFiles(mask); 
      foreach (FileInfo fi in rgFiles) 
            action(fi.FullName); 
      if (recursive) 
      { DirectoryInfo[] dirs = di.GetDirectories(); 
         foreach (DirectoryInfo dirInfo in dirs) 
          GetFileList(Path.Combine(dir, dirInfo.Name), 
                     mask, recursive, action); } } 
   catch (UnauthorizedAccessException) 
   {   } 
} 
private void Btn_Lista_Click(object sender, EventArgs e) 
{  String dir = Path.GetDirectoryName(textBox.Text); 
   String mask = textBox.Text.Substring(dir.Length); 
   listBox.Items.Clear(); listBox.BeginUpdate(); 
   GetFileList(dir, mask, checkBox1.Checked, 
            name => listBox.Items.Add(name)); 
   listBox.EndUpdate(); }
    

Magyarázat: A bejárás paramétere egy Action<String> típusú delegate, ezt a fájlnevet váró akciót fogja végrehajtani a bejárás minden találatra. A bejárás során kivételt kaphatunk, ha olyan könyvtárat akarunk megnyitni, amihez nincs jogunk, készüljünk fel erre is.

18.18. feladat (Számok kiválogatásaszint: 3). Írjunk programot, amely egy ListBox-ba generál véletlen számokat és egy CheckListBox-ban megadott feltételek alapján szűri egy másik ListBox-ba.

18.18. ábra. Működés közben.

Magyarázat: A szűrőfeltételeket érdemes egy listában eltárolni (Egy int paramétert váró és logikai értéket visszaadó függvény Predicate<int> típusú.) Ezek után végig kell menni az összes elemen, és megnézni a szűrőfeltételeket (elég addig vizsgálni egy adott elemet, míg az egyik feltétel nem teljesül).

18.29. forráskód. Generálás és szűrés

     
private void Btn_General_Click(object sender, EventArgs e) 
{ 
  Btn_General.Enabled = false; 
  Random rnd = new Random(); 
  HashSet<Int32> voltak = new HashSet<Int32>(); 
  LBx_Ossz.Items.Clear(); 
  LBx_Ossz.BeginUpdate(); 
  Int32 akt; 
  for (Int32 i = 0; i < 1000; i++) 
  { 
    do 
    { 
      akt = rnd.Next(10000); 
    } while (voltak.Contains(akt)); 
    voltak.Add(akt); 
    LBx_Ossz.Items.Add(akt); 
  } 
  LBx_Ossz.EndUpdate(); 
  Btn_General.Enabled = true; 
} 
 
private void Btn_Mutat_Click(object sender, EventArgs e) 
{ List<Predicate<Int32>> feltetelek = new List<Predicate<Int32>>(); 
 if (checkedListBox1.CheckedIndices.Contains(0)) 
    feltetelek.Add(Prim); 
 if (checkedListBox1.CheckedIndices.Contains(1)) 
    feltetelek.Add(Paros); 
 if (checkedListBox1.CheckedIndices.Contains(2)) 
    feltetelek.Add(Paratlan); 
 if (checkedListBox1.CheckedIndices.Contains(3)) 
    feltetelek.Add(Oszt3); 
 if (checkedListBox1.CheckedIndices.Contains(4)) 
    feltetelek.Add(Oszt6); 
 if (checkedListBox1.CheckedIndices.Contains(5)) 
    feltetelek.Add(Oszt9); 
 if (checkedListBox1.CheckedIndices.Contains(6)) 
    feltetelek.Add(Negyzet); 
 LBx_Valogat.Items.Clear(); 
 for (Int32 i = 0; i < LBx_Ossz.Items.Count; i++) 
 { 
    Boolean kell = false; 
    foreach (Predicate<Int32> feltetel in feltetelek) 
    { 
       kell = kell || feltetel((Int32)LBx_Ossz.Items[i]); 
       if (kell) 
          break; 
    } 
    if (kell) 
       LBx_Valogat.Items.Add(LBx_Ossz.Items[i]); 
 } 
 LB_Eredm.Text = String.Format("{0}/{1}", 
          LBx_Valogat.Items.Count, LBx_Ossz.Items.Count); 
}
    

Egyéb eszközök, idő, dátum, érték beállítás

18.19. feladat (Napok számaszint: 1). Írjon programot, melynek a segítségével bekér két dátumot, és meghatározza a két megadott dátum közötti napok számát!

18.19. ábra. Működés közben.

18.30. forráskód. Különbség kiszámítása

     
private void monthCalendar_DateChanged(object sender, 
                             DateRangeEventArgs e) 
{ 
   if (MC_kezd.SelectionStart.CompareTo(MC_veg.SelectionStart) > 0) 
   { 
      LB_kulonbseg.Text = "A keződátum nagyobb, mint a végdátum."; 
   } 
   else 
   { 
      LB_kulonbseg.Text = 
         String.Format("A két dátum között eltelt napok száma: {0}", 
         MC_veg.SelectionStart.Subtract(MC_kezd.SelectionStart).Days); 
   } 
}
    

18.20. feladat (Horoszkópszint: 1). Írjon programot, melynek a segítségével bekér egy születési dátumot, és meghatározza, hogy a felhasználó melyik csillagjegyben született. Az ablak fejlécében üdvözöljön minket napszaknak megfelelően.

18.20. ábra. Működés közben.

Magyarázat: Érdemes egy-egy tömbben a csillagjegyeket, és az azokat határoló dátumokat felsorolni. Ezek után a megadott dátum hónapjának és napjának figyelembevételével megkeresni melyik két határ közé esik.

18.31. forráskód. Csillagjegy megadása

 
private void Btn_Horoszkop_Click(object sender, EventArgs e) 
{ label1.Text = Csillagjegy(dateTimePicker1.Value);} 
 
private String Csillagjegy(DateTime dateTime) 
{  dateTime = new DateTime(2011, dateTime.Month, dateTime.Day); 
   DateTime[] dates = new DateTime[12] { 
      new DateTime(2011, 01, 20), 
      new DateTime(2011, 02, 19), 
      new DateTime(2011, 03, 21), 
      new DateTime(2011, 04, 20), 
      new DateTime(2011, 05, 21), 
      new DateTime(2011, 06, 22), 
      new DateTime(2011, 07, 23), 
      new DateTime(2011, 08, 23), 
      new DateTime(2011, 09, 23), 
      new DateTime(2011, 10, 23), 
      new DateTime(2011, 11, 22), 
      new DateTime(2011, 12, 22) }; 
   String[] jegyek = new String[12]{ 
      "Vízöntő","Halak","Kos", 
      "Bika","Ikrek","Rák", 
      "Oroszlán","Szűz","Mérleg", 
      "Skorpió","Nyilas","Bak" }; 
   int i = 0; 
   Boolean found = false; 
   while (i < 11 && !found) 
   { 
      found = ((dates[i] < dateTime) && (dateTime < dates[i + 1])); 
      i++; 
   } 
   return (found) ? jegyek[i - 1] : jegyek[11]; }

18.21. feladat (Időpontszint: 1). Írjon programot, melynek a segítségével megnövelhető a dátum. Kiválasztható legyen melyik részét növelje a dátumnak vagy időnek (év, hónap, nap, óra, perc, másodperc).

18.21. ábra. Működés közben.

Magyarázat: Az óra, perc, másodperc megadását egy MaskedTextBox komponensben oldjuk meg "00:00:00" maszkkal. Figyeljen arra, hogy értelmezhető-e a megadott idő.

18.32. forráskód. Dátum növelése

     
private void BT_hozzaad_Click(object sender, EventArgs e) 
{  DateTime ido; 
   try 
   { ido = DateTime.ParseExact(maskedTextBox1.Text, "HH:mm:ss", 
                         CultureInfo.InvariantCulture);} 
   catch (FormatException) 
   { MessageBox.Show("Nincs megadva idő!"); return; } 
   DateTime uj_datum_es_ido = new DateTime( 
   datum.Value.Year, datum.Value.Month, datum.Value.Day, 
   ido.Hour, ido.Minute, ido.Second ); 
   Int32 noveles = (int)numericUpDown1.Value; 
   if (RB_ev.Checked) 
      uj_datum_es_ido = uj_datum_es_ido.AddYears(noveles); 
   else 
      if (RB_honap.Checked) 
         uj_datum_es_ido = uj_datum_es_ido.AddMonths(noveles); 
      else 
      if (RB_nap.Checked) 
         uj_datum_es_ido = uj_datum_es_ido.AddDays(noveles); 
      else 
         if (RB_ora.Checked) 
            uj_datum_es_ido = uj_datum_es_ido.AddHours(noveles); 
         else 
         if (RB_perc.Checked) 
            uj_datum_es_ido = uj_datum_es_ido.AddMinutes(noveles); 
         else if (RB_masodperc.Checked) 
           uj_datum_es_ido = uj_datum_es_ido.AddSeconds(noveles); 
   label3.Text = String.Format("A növelt dátum és idő: 
            {0:yyyy MM dd, HH:mm:ss}", uj_datum_es_ido); }
    

18.22. feladat (Stopperszint: 1). Írj stoppert, mely jobb egérgombbal indítja és állítja, bal egérgombbal pedig részeredményeket ad.

18.22. ábra. Működés közben.

18.33. forráskód. Egérkattintás kezelése

     
private void Stopper_MouseClick(object sender, MouseEventArgs e) 
{ 
   if (e.Button == System.Windows.Forms.MouseButtons.Right) 
   { 
      if (started) 
      {  label1.Text = "Jobbgomb: stopper indítása"; 
         lb_mert.Text = String.Format("Mért idő: {0:t}", 
                        (DateTime.Now - startTime)); } 
      else 
      {  label1.Text = "Jobbgomb: stopper leállítása"; 
         startTime = DateTime.Now; 
         listBox1.Items.Clear(); 
         lb_mert.Text = String.Empty; } 
      started = !started; 
   } 
   else if (e.Button == System.Windows.Forms.MouseButtons.Left) 
   { 
      if (started) 
        listBox1.Items.Add((DateTime.Now - startTime).ToString("t")); 
   } 
}
    

Menük és eszköztárak

18.23. feladat (Három szám átlagaiszint: 1). Kérjünk be 3 egész számot. Különböző műveleteket lehessen végezni velük, melyek eredményét a művelet nevével egy ListBox-ba gyűjtse a program. A műveleteket lehessen a formon lévő menüsorból kiválasztani, illetve a ListBox területén megjelenő helyi menüből is. A műveletek: A 3 szám összege, a 3 szám számtani, mértani, harmonikus közepe. A legnagyobb szám a 3 közül.

18.23. ábra. Három szám átlagai.

Magyarázat: A menük és helyi menü használatánál hangoljuk össze a működést. Elég az eseménykezelőket egyszer megírni, pl. a menüpontoknál, és a helyimenü menüpontjainak eseménykezelőit irányítsuk ezekre a metódusokra. Használjuk a MenuStrip és ContextMenuStrip komponenseket. Ne felejtsük el a ListBox-nál a ContextMenuStrip tulajdonságot beállítani.

18.34. forráskód. Három szám mértani közepe

     
private bool JoSzamok() 
{   return ((int.TryParse(textBoxSz1.Text, out sz1)) && 
         (int.TryParse(textBoxSz2.Text, out sz2)) && 
         (int.TryParse(textBoxSz3.Text, out sz3)));} 
 
private void mértaniKözépToolStripMenuItem_Click(object sender, 
                                    EventArgs e) 
{   if (JoSzamok()) 
   { ListBoxEredmeny.Items.Add("Mértani közép: " + 
               (Math.Pow(sz1 * sz2 * sz3, 1.0 / 3)).ToString()); } 
   else 
   { MessageBox.Show("3 egész számot kérek!!!", "Hiba...", 
         MessageBoxButtons.OK, MessageBoxIcon.Error); } }
    

18.24. feladat (Menük ikonokkalszint: 2). Egészítse ki az előző feladat megoldásául szolgáló programot úgy, hogy a menüpontok előtt kis ikonok is jelenjenek meg, melyek szimbolizálják a műveletet. Ugyanezek az ikonok jelenjenek meg egy eszköztáron is, ahonnan szintén elindítható legyen minden művelet.

18.24. ábra. Három szám átlagai ikonokkal.

18.25. feladat (Véletlen számokszint: 3). Töltsön fel egy listát 10 és 20 közé eső véletlen számokkal. Legyen 10 elemű a lista. Lehessen a listából kijelölt elemeket törölni, új elemet bevinni, amit egy megjelenő TextBoxba tudunk bevinni, és lehessen a meglévő elemek összegét és szorzatát kiszámítani. Ezeket a műveleteket menüből kell indítani. A státuszsoron jelenítsük meg folyamatosan, hogy hány elemű a lista, mekkora a legkisebb és legnagyobb eleme.

18.25. ábra. Listaelemek kezekése menüből

Magyarázat: A feladat megoldásához alkalmazni kell a minimum-maximum kiválasztás tételét, az összegzés tételét alapesetben, és szorzatokra is. Ebben az esetben figyeljünk oda a gyűjtőváltozó kezdőérték adására. Az új érték bevitelénél csak egész számot fogadjunk el.

18.35. forráskód. Listaelemek kezelése

     
private void Szelsoertek(out int max, out int min) 
{ 
   int i; 
   min = max = Convert.ToInt32(listBox1.Items[0]); 
   for (i = 1; i < listBox1.Items.Count; i++) 
   { 
      if (max < Convert.ToInt32(listBox1.Items[i])) 
         max = Convert.ToInt32(listBox1.Items[i]); 
      if (min > Convert.ToInt32(listBox1.Items[i])) 
         min = Convert.ToInt32(listBox1.Items[i]); 
   } 
} 
 
private void SetStatus() 
{ 
   StatusLabel1.Text = "Elemek száma: " + 
            listBox1.Items.Count.ToString(); 
   int max, min; 
   Szelsoertek(out max, out min); 
   StatusLabel2.Text = "Legnagyobb elem: " + max.ToString(); 
   StatusLabel3.Text = "Legkisebb elem: " + min.ToString(); 
} 
 
private void SetDef() 
{ 
   int i, szam; 
   listBox1.Items.Clear(); 
   for (i = 0; i < 10; i++) 
   { 
      szam = rnd.Next(10) + 10; 
      listBox1.Items.Add(szam.ToString()); 
   } 
   SetStatus(); 
} 
 
private void alaphelyzetToolStripMenuItem_Click(object sender, 
                                 EventArgs e) 
{ 
   SetDef(); 
} 
 
private void összegToolStripMenuItem_Click(object sender, 
                                 EventArgs e) 
{ 
   int i, s = 0; 
   for (i = 0; i < listBox1.Items.Count; i++) 
   { 
      s += Convert.ToInt32(listBox1.Items[i]); 
   } 
   labelOsszeg.Text = "Elemek összeg: " + s.ToString(); 
}
    

18.36. forráskód. Listaelemek kezelése

 
private void szorzatToolStripMenuItem_Click(object sender, 
                                 EventArgs e) 
{ 
   int i; 
   double s = 1; 
   for (i = 0; i < listBox1.Items.Count; i++) 
   { 
      s *= Convert.ToInt32(listBox1.Items[i]); 
   } 
   labelSzorzat.Text = "Elemek szorzata: " + 
                  s.ToString(); 
} 
 
private void kijelöltekTörléseToolStripMenuItem_Click(object sender, 
                                        EventArgs e) 
{ 
   while (listBox1.SelectedItems.Count > 0) 
   { 
      listBox1.Items.Remove(listBox1.SelectedItems[0]); 
   } 
 
   SetStatus(); 
} 
 
private void újBeviteleToolStripMenuItem_Click(object sender, 
                                   EventArgs e) 
{ 
   int sz; 
   if (int.TryParse(textBox1.Text, out sz)) 
            listBox1.Items.Add(textBox1.Text); 
 
   SetStatus(); 
}

18.26. feladat (Véletlen számok mátrixbanszint: 4). Töltsön fel egy 3x3 mátrixot 10 és 20 közé eső véletlen számokkal. Végezze el menüből és helyi menüből választhatóan a következő műveleteket: transzponált, a páratlan számok összege, a főátló számainak összege, a sorokban lévő értékek és az oszlopokban lévő értékek összege. Ezeket az eredményeket jelenítse is meg a formon.

18.26. ábra. Mátrix elemek kezelése menüből

Magyarázat: A feladat megoldásánál használjuk a DataGridView komponens adta lehetőségeket. Figyeljünk arra, hogy a mátrix bejárásánál a sorokat és oszlopokat megfelelően azonosítsuk. Használjuk az összegzés tételét megfelelően. A transzponált előállítását lásd a 18.43-ben.

18.37. forráskód. Mátrix elemek generálása

     
private void General() 
{ 
   Random rnd = new Random(); 
   int i, j, szam; 
   dataGridAlap.Rows.Clear(); 
   for (i = 0; i < 3; i++) 
   { 
      DataGridViewRow r = new DataGridViewRow(); 
      for (j = 0; j < 3; j++) 
      { 
         szam = rnd.Next(10) + 10; 
         DataGridViewCell dc = new DataGridViewTextBoxCell(); 
         dc.Value = szam; 
         r.Cells.Add(dc); 
      } 
      dataGridAlap.Rows.Add(r); 
   } 
}
    

18.38. forráskód. Mátrix elemek kezelése

     
private void páratlanÖsszegToolStripMenuItem_Click(object sender, 
                                       EventArgs e) 
{ 
   int i, j, szam, ptl = 0; 
   for (i = 0; i < 3; i++) 
   { 
      for (j = 0; j < 3; j++) 
      { 
         szam = (int)dataGridAlap.Rows[j].Cells[i].Value; 
         if (szam % 2 == 1) ptl += szam; 
      } 
   } 
   labelPtlOsszeg.Text = "Páratlan elemek összege: " + ptl.ToString(); 
} 
 
private void sorokÖsszegeToolStripMenuItem_Click(object sender, 
                                       EventArgs e) 
{ 
   int i, j, szam, s; 
   labelSorok.Text = "Sorok összege: \n"; 
   for (i = 0; i < 3; i++) 
   { 
      s = 0; 
      for (j = 0; j < 3; j++) 
      { 
         szam = (int)dataGridAlap.Rows[i].Cells[j].Value; 
         s += szam; 
      } 
      labelSorok.Text = labelSorok.Text + (i+1).ToString() + 
            ". sor: " + s.ToString() + "\n"; 
   } 
} 
 
private void főátlóÖsszegToolStripMenuItem_Click(object sender, 
                                    EventArgs e) 
{ 
   int i, szam, ossz = 0; 
   for (i = 0; i < 3; i++) 
   { 
      szam = (int)dataGridAlap.Rows[i].Cells[i].Value; 
      ossz += szam; 
   } 
   labelFoAtlOsszeg.Text = "Főátló elemeinek összege: " + 
                              ossz.ToString(); 
}
    

18.27. feladat (Műveletekszint: 2). Írj programot, amely egy számokkal töltött listában végez műveleteket. A műveleteket menüből érhessük el, és a következők legyenek:

  • minimum/maximum keresés (ezt almenü segítségével old meg)

  • átlagszámítás

  • összeg

  • páros számok összege

Ugyancsak menüből lehessen kiválasztani, hogy kézzel adjuk meg a számokat, vagy a program generálja őket. Menüből és gomb segítségével is lehessen kilépni a programból. A számok bekérésénél végezzünk ellenőrzést, hogy valóban egész számot adjon meg a felhasználó és a megadott határokon belül legyen: 1 és 20 között lehet a darabszám, és a számok 1 és 99 között legyenek a listában.

18.27. ábra. Működés közben

Magyarázat: Mivel gyakran kell egy bekért szám ellenőrzését elvégezni, írjunk rá külön metódust, mely egy textbox szövegét próbálja meg átalakítani és megadható neki két határ, amik közé kell essen a szám.

18.39. forráskód. Ellenőrzés és összegzés

     
private Boolean Ellenoriz(TextBox tb, Int32 ah, Int32 fh, out Int32 szam) 
{ 
   if (Int32.TryParse(tb.Text, out szam) && 
      (szam >= ah) && (szam <= fh)) 
   { 
      return true; 
   } 
   else 
   { 
      MessageBox.Show(String.Format("Számot kell megadni és {0}," 
                          +"{1} között kell lennie!", ah, fh)); 
      tb.Text = String.Empty; 
      tb.Focus(); 
      return false; 
   } 
} 
 
private void párosakÖsszegeToolStripMenuItem_Click(object sender, 
                                      EventArgs e) 
{ 
   Int32 sum = 0; 
   for (Int32 i = 0; i < listBox.Items.Count; i++) 
   { 
      if ((Int32)listBox.Items[i] % 2 == 0) 
      { 
         sum += (Int32)listBox.Items[i]; 
      } 
   } 
   if (sum > 0) 
     MessageBox.Show(String.Format("A páros számok összege: {0}" 
                           , sum)); 
   else 
     MessageBox.Show("Nincs páros szám!"); 
} 
 
private void számokátlagaToolStripMenuItem_Click(object sender, 
                        EventArgs e) 
{ 
   Int32 sum = 0; 
   for (Int32 i = 0; i < listBox.Items.Count; i++) 
   { 
     sum += (Int32)listBox.Items[i]; 
   } 
   MessageBox.Show(String.Format("A számok átlaga: {0}", sum / 
            ((double)listBox.Items.Count))); 
}
    

Több info egy formon

18.28. feladat (SplitContainer használataszint: 1). Írjon programot, mely tartalmaz 2 színes panelt egymás mellett, és lehetőség legyen a területük arányának változtatására. Adjuk meg a jobboldali panel szélességének arányát az egészhez képest.

18.28. ábra. Működés közben a SplitContainer.

Magyarázat: A panelek eltolására használja a SplitContainer komponenst, míg látványosan az arány megaddható a Trackbar segítségével.

18.40. forráskód. SplitContainer használata

     
namespace Tobbinfo_1 
{ 
   public partial class Form1 : Form 
   { 
      public Form1() 
      { 
         InitializeComponent(); 
      } 
 
      private void trackBar1_Scroll(object sender, EventArgs e) 
      { 
         splitContainer2.SplitterDistance = 
            splitContainer2.Width * trackBar1.Value / 100; 
         labelPos.Text = trackBar1.Value.ToString() + "%"; 
      } 
 
      private void Form1_Shown(object sender, EventArgs e) 
      { 
         splitContainer2.SplitterDistance = 
            splitContainer2.Width * 10 / 100; 
         labelPos.Text = trackBar1.Value.ToString() + "%"; 
      } 
   } 
}
    

18.29. feladat (TabControl használataszint: 1). Írjon programot, mely bekér két egész számot külön külön egy TabControl egyik lapján. Majd kiszámolja a két szám számtani közepét, amit kiír egy másik lapra, aminek a címkéje legyen: eredmények. A bekéréskor ügyeljen a kivételkezelésre! A programból való kilépéskor kérdezzen rá, hogy biztos ki akar-e lépni a felhasználó, és a válasznak megfelelően járjon el.

18.29. ábra. Adatbekérés TabControl használatával.

Magyarázat: Figyeljünk oda a hibakezelésre, és a váltásra a TabPage-ek között.

18.41. forráskód. TabControl használata

     
private void buttonSzamol_Click(object sender, EventArgs e) 
{ 
  int szam1, szam2; 
  if (textBox1.Text != String.Empty && 
     textBox2.Text != String.Empty) 
  { 
  try 
  { 
     szam1 = Convert.ToInt32(textBox1.Text); 
     szam2 = Convert.ToInt32(textBox2.Text); 
     labelEredmeny.Text = ((szam1 + szam2) / 2).ToString(); 
     tabControl1.SelectTab(1); 
  } 
  catch 
  { 
     MessageBox.Show("Adathiba!", "Hiba", 
         MessageBoxButtons.OK, MessageBoxIcon.Error); 
  } 
  } 
  else 
  { 
    MessageBox.Show("Mindkét számot írd be!", " Hiba", 
         MessageBoxButtons.OK, MessageBoxIcon.Error); 
  } 
}
    

18.30. feladat (Mátrixok adatai egy formonszint: 3). Írjon programot, mely generál egy 3x3 mátrixot olyan véletlen számokból, melyek 1 és 20 közé esnek. Határozza meg a mátrix transzponáltját, a skalárszorosát és a mátrix legkisebb és legnagyobb értékét is válassza ki. Az egyes mátrixokat és a szélsőértékeket külön lapokon jelenítse meg, de csak egy formot használjon.

Magyarázat: A kezdeti állapotban a program generáljon egy kiinduló mátrixot. Figyeljen oda, hogy a véletlen számok a megadott intervallumba essenek. Megjelenítéshez lehet használni a DataGridView egy megfelelően beállított példányát.

18.30. ábra. Kiinduló mátrix.

18.42. forráskód. Kiinduló mátrix generálása

     
private void buttonAlap_Click(object sender, EventArgs e) 
{ 
  Random rnd = new Random(); 
  int i, j, szam; 
  dataGridAlap.Rows.Clear(); 
  for (i = 0; i < 3; i++) 
  { 
     DataGridViewRow r = new DataGridViewRow(); 
     for (j = 0; j < 3; j++) 
     { 
       szam = (rnd.Next() % 20) + 1; 
       DataGridViewCell dc = new DataGridViewTextBoxCell(); 
       dc.Value = szam; 
       r.Cells.Add(dc); 
     } 
     dataGridAlap.Rows.Add(r); 
  } 
}
    

Magyarázat: A számolás indításakor határozza meg a feladatban előírt mátrixokat és számokat.

18.31. ábra. Kiinduló mátrix.

18.43. forráskód. Transzponált számítása

     
private void Transzponalt() 
{ 
 int i, j, szam; 
 dataGridTr.Rows.Clear(); 
 for (i = 0; i < 3; i++) 
 { 
   DataGridViewRow r = new DataGridViewRow(); 
   for (j = 0; j < 3; j++) 
   { 
      szam = (int)dataGridAlap.Rows[j].Cells[i].Value; 
      DataGridViewCell dc = new DataGridViewTextBoxCell(); 
      dc.Value = szam; 
      r.Cells.Add(dc); 
   } 
   dataGridTr.Rows.Add(r); 
         } 
      }
    

18.44. forráskód. Skalárral szorzás

 
private void SkalarSzorzas() 
{ 
 Random rnd = new Random(); 
 int i, j, szam, szorzo; 
 szorzo = (rnd.Next() % 7) + 3; 
 labelSkalar.Text = " A skalár a: "+szorzo.ToString(); 
 dataGridSzor.Rows.Clear(); 
 for (i = 0; i < 3; i++) 
 { 
   DataGridViewRow r = new DataGridViewRow(); 
   for (j = 0; j < 3; j++) 
   { 
     szam = (int)dataGridAlap.Rows[j].Cells[i].Value * szorzo; 
     DataGridViewCell dc = new DataGridViewTextBoxCell(); 
     dc.Value = szam; 
     r.Cells.Add(dc); 
   } 
   dataGridSzor.Rows.Add(r); 
  } 
}

18.45. forráskód. Szélsőértékek

 
private void SzelsoErtekek() 
     { 
         int szam, i,j, min = 21, max = -1; 
         for (i = 0; i < 3; i++) 
         { 
            for (j = 0; j < 3; j++) 
            { 
               szam = (int)dataGridAlap.Rows[i].Cells[j].Value; 
               if (min > szam) min = szam; 
               if (max < szam) max = szam; 
            } 
         } 
         labelMin.Text = min.ToString(); 
         labelMax.Text = max.ToString(); 
      }
                                                                                                                                     

                                                                                                                                     
    

Dialógusok

18.31. feladat (Színek állítása dialógusablak segítségével.szint: 1). Készítsen egy olyan programot, mely egy formon lévő label-nek a szín tulajdonságait állítja. A színbeállítást egy nyomógomb segítségével kezdeményezze. A színeket a szokásos windows beállító ablak segítségével lehessen kiválasztani. Egy további label-be jelenítsük meg a kiválaszott szín adatait is.

18.32. ábra. Működés közben.

Magyarázat: A ColorDialog példányosítása történhet a komponens használatával, vagy a kódból közvetlenül is! Figyeljen arra, hogy a ColorDialog is, mint minden dialógus ablak, a ShowDialog() metódussal hívható, melynek visszatérési értéke a DialogResult osztály egy példányában fogadható, és utána értékelhető ki.

18.46. forráskód. ColorDialog használata

     
      private void buttonColors_Click(object sender, EventArgs e) 
      { 
         ColorDialog cd = new ColorDialog(); 
         DialogResult dr; 
         dr = cd.ShowDialog(); 
         if (dr == DialogResult.OK) 
         { 
            labelMinta.BackColor = cd.Color; 
            labelVal.Text = cd.Color.ToString(); 
         } 
      }
    

18.32. feladat (Kép megnyitása dialógus ablak segítségével.szint: 1). Készítsen egy olyan programot, melyben a szokásos windows Megnyitás ablak segítségével kiválaszt egy képet, és azt megnyitja egy PictureBox-ban. A kép töltse ki a form felületét, méretezésre kövesse annak mozgását. A megnyitást egy gomb segítségével kezdeményezze.

18.33. ábra. Kép megnyitása.

Magyarázat: Figyeljen rá, hogy a PictureBox Dock tulajdonságát hogy állítja be!

18.47. forráskód. OpenFileDialog használata

                                                                                                                                     

                                                                                                                                     
     
private void buttonOpen_Click(object sender, EventArgs e) 
      { 
         OpenFileDialog of = new OpenFileDialog(); 
         DialogResult dr = of.ShowDialog(); 
         if (dr == DialogResult.OK) 
         { 
            pictureBoxDest.SizeMode = PictureBoxSizeMode.CenterImage; 
            pictureBoxDest.Image = new Bitmap(of.FileName); 
         } 
      }
    

18.33. feladat (Szöveges file megnyitása és mentéseszint: 2). Készítsen egy programot, mely a szokásos windows Megnyitás ablak segítségével meg tud nyitni egy szöveges file-t egy TextBox-ba. Illetve tudjuk elmenteni a tartalmát a szokásos Mentés ablak használatával.

18.34. ábra. Szöveges file mentése dialógus ablakkal.

Magyarázat: Figyeljen oda, hogy a TextBox Multiline tulajdonságát hogy állítja be. Ne feledjük, a file-ok használathához a System.IO névtérre szükség van.

18.48. forráskód. A SaveFileDialog használata

 
private void buttonOpen_Click(object sender, EventArgs e) 
{ OpenFileDialog of = new OpenFileDialog(); 
 if (of.ShowDialog() == DialogResult.OK) 
 { FileStream fs = new FileStream(of.FileName, 
                  FileMode.Open); 
   StreamReader rs = new StreamReader(fs); 
   string s = rs.ReadLine(); 
   while (s != null) 
   { textBoxDest.Text += s; 
    s = rs.ReadLine(); } 
   rs.Close(); fs.Close(); } } 
 
private void buttonSave_Click(object sender, EventArgs e) 
{ SaveFileDialog sf = new SaveFileDialog(); 
 if (sf.ShowDialog() == DialogResult.OK) 
 { FileStream fs = new FileStream(sf.FileName, 
            FileMode.Create); 
   StreamWriter wr = new StreamWriter(fs); 
   wr.Write(textBoxDest.Text); 
   wr.Close(); fs.Close(); } }
                                                                                                                                     

                                                                                                                                     
    

18.34. feladat (Dialógusok használataszint: 3). Készítsen programot mely egy RichText komponensbe megnyit egy kiválasztott rtf file-t. Tudjuk módosítani a háttér színét, a karakterek színét, a karakterek jellemzőit. Tudjunk menteni. Az egyes lehetőségeket helyi menüből érjük el.

18.35. ábra. Helyi menü használata a feladatban.

Magyarázat: A háttérszín beállításánál használjuk a ColorDialog komponenst. A karakterek jellemzőit a FontDialog komponens segítségével állíthatjuk be. Ennek a Font tulajdonsága tartalmazza az összes beállítást.

18.49. forráskód. Háttérszín és Font beállítása

 
private void háttérszínToolStripMenuItem_Click(object sender, 
                                    EventArgs e) 
{ ColorDialog cd = new ColorDialog(); 
  if (cd.ShowDialog() == DialogResult.OK) 
    richTextBox1.BackColor = cd.Color; } 
 
private void fontBeállításToolStripMenuItem_Click(object sender, 
                                    EventArgs e) 
{ FontDialog fd = new FontDialog(); 
   if (fd.ShowDialog() == DialogResult.OK) 
       richTextBox1.Font = fd.Font; }

Magyarázat: Mentésnél figyeljünk arra, hogy file művelet végzésekor erőforrást használunk. Szükség lehet a kivételkezelésre.

18.50. forráskód. Mentés és visszatöltés

                                                                                                                                     

                                                                                                                                     
     
private void betöltésToolStripMenuItem_Click(object sender, EventArgs e) 
{ OpenFileDialog of = new OpenFileDialog(); 
 if (of.ShowDialog() == DialogResult.OK) 
   richTextBox1.LoadFile(of.FileName); } 
 
private void mentésToolStripMenuItem_Click(object sender, EventArgs e) 
{ SaveFileDialog sf = new SaveFileDialog(); 
 if (sf.ShowDialog() == DialogResult.OK) 
    richTextBox1.SaveFile(sf.FileName); }
    

Modális és nem modális formok

18.35. feladat (Üzenetablak használataszint: 1). Írjon programot, mely véletlenszerűen kitalál egy egész számot 1 és 20 között. A felhasználó tippelje meg, hogy páros vagy páratlan lesz. A kiértékelést egy dialógus üzenettel végezze a program.

18.36. ábra. Kiértékelés üzenetablak segítségével.

Magyarázat: Ügyeljen a véletlenszámok használatára. Az üzenetablak a MessageBox Show metódusával hívható, melynek 4 paramétere van. A megjelenítendő szöveg, a form fejlécszövege, a megjelenő gombok, és az ikon. A gombok és az ikon a rendszer felsorolt típusa MessageBoxButtons és MessageBoxIcon. Ezek közül kell választani. A Páratlan tipp kiértékelése teljesen hasonlóan mehet.

18.51. forráskód. Deklarálás

     
private int aSzam = 0; 
private bool ParosE; 
private Random rnd = new Random(); 
 
private void buttonGen_Click(object sender, EventArgs e) 
{ aSzam = (rnd.Next() % 20) + 1; 
  ParosE = ((aSzam % 2) == 0); 
  labelSZAM.Text = "Generálás kész"; } 
 
private void buttonParos_Click(object sender, EventArgs e) 
{  if (ParosE && aSzam != 0) 
         MessageBox.Show("Jól tippeltél nagyon. ", "Eredmény", 
           MessageBoxButtons.OK, MessageBoxIcon.Information); 
   else 
      MessageBox.Show("Rossz tipp. ", "Eredmény", 
           MessageBoxButtons.OK, MessageBoxIcon.Warning); 
   labelSZAM.Text = aSzam.ToString(); }
    

18.36. feladat (Üzenetablak kiértékeléseszint: 1). Írjon programot, mely feltesz egy eldöntendő kérdést egy üzenet ablakban, és a válasznak megfelelően, ha IGEN, akkor zöldre, ha NEM akkor pirosra színezi a form hátterét.

18.37. ábra. Üzenetablak gombjai.

18.52. forráskód. Egy lehetséges megoldás.

                                                                                                                                     

                                                                                                                                     
     
private void buttonKerdes_Click(object sender, EventArgs e) 
{ 
  if (MessageBox.Show("Süt kint a nap ?", "Kérdés ablak...", 
     MessageBoxButtons.YesNo, 
      MessageBoxIcon.Question) == DialogResult.Yes) 
  { 
     this.BackColor = Color.Green; 
  } 
  else 
  { 
     this.BackColor = Color.Red; 
  } 
}
    

18.37. feladat (Adatbekérés modális form segítségével.szint: 3). Írjon programot, mely bekér két egész számot külön külön egy adatbekérő modális form segítségével. Majd kiszámolja a két szám számtani átlagát, amit kiír a főformra. A bekéréskor ügyeljen a kivételkezelésre! A programból való kilépéskor kérdezzen rá, hogy biztos ki akar-e lépni a felhasználó, és a válasznak megfelelően járjon el.

18.38. ábra. Modális form.

Magyarázat: Figyeljen oda, hogy az adatbekérés után publikus adatmezőbe kerüljön az adat, hogy át lehessen venni a másik formból. Ne felejtse el az adatbekérő formon a felrakott gombok DialogResult értékét beállítani. Alapértelmezése None. Az adatbekéréshez példányosítsuk a bekérő formot. A kilépésnél kezeljük a MessageBox Show metódusának a visszatérési értékét.

18.53. forráskód. Egy lehetséges megoldás.

     
private void buttonBe1_Click(object sender, EventArgs e) 
{ 
   FormBeker frm = new FormBeker(); 
   if (frm.ShowDialog() == DialogResult.OK) 
   {  SzamEgy = frm.BekertSzam; 
      labelElso.Text = frm.BekertSzam.ToString(); } 
} 
 
private void FormMain_FormClosing(object sender, FormClosingEventArgs e) 
{ 
   if (MessageBox.Show("Biztos ki akar lépni?", "Kérdés", 
      MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == 
      DialogResult.Cancel) 
   {  e.Cancel = true;  } }
    

18.38. feladat (Összetartozó adatok kezeléseszint: 5). Készítsen egy programot, melyben egy kiscserkész csapat tagjainak adatait tudjuk nyilvántartani. A tagokról az azonosítójukat, a nevüket, és a születési dátumukat kell letárolni. Az adatbevitel egy modális form segítségével történjen. Az adatokat táblázatos formában jelenítsük meg. Tudjunk adatot menteni és visszatölteni fileból, a szokásos windows dialógus ablakok használatával.

18.39. ábra. Kiscserkészek adatai

Magyarázat: A feladat során több mindenre kell figyeljünk. Amit át kell tekinteni, a ListView kezelése, bináris file írása és olvasása, modális form használata, és adatforgalom a formok között.

Tekintsük először az adatbeviteli formot. Itt csak arra ügyeljünk, hogy az adatmezőket publikus láthatóságra állítsuk, hogy a FormMain osztályból is el lehessen érni.

18.54. forráskód. Adatbeviteli form

     
// Az adatbeviteli form 
 
public partial class FormAdat : Form 
{ 
  public string Beazon = ""; 
  public string Benev = ""; 
  public DateTime Beszul; 
 
  public FormAdat() 
  { 
    InitializeComponent(); 
  } 
 
  private void buttonOK_Click(object sender, EventArgs e) 
  { 
    Beazon = textBoxAzon.Text; 
    Benev = textBoxNev.Text; 
    Beszul = dateTimePickerSzDatum.Value; 
  } 
}
    

Magyarázat: A FormMain osztály eseménykezelői kissé összetettebbek, mert itt végezzük el a feladatokat.

18.55. forráskód. A főform eseménykezelői, metódusai

                                                                                                                                     

                                                                                                                                     
     
// A főform 
 
public partial class FormMain : Form 
{ 
   private string azon = ""; 
   private string nev = ""; 
   private DateTime szul; 
 
   public FormMain() 
   { 
      InitializeComponent(); 
   } 
 
   private void buttonZar_Click(object sender, EventArgs e) 
   { 
      Close(); 
   } 
 
   private void FormMain_FormClosing(object sender, 
                  FormClosingEventArgs e) 
   { 
      if (MessageBox.Show(" Biztos kilép?", "Kérdés", 
         MessageBoxButtons.YesNo, MessageBoxIcon.Question) == 
                              DialogResult.No) 
      { 
         e.Cancel = true; 
      } 
   }
    

18.56. forráskód. A főform eseménykezelői, metódusai

 
   // Kiválasztott adat módosítása 
private void buttonMod_Click(object sender, EventArgs e) 
{ 
   FormAdat frm = new FormAdat(); 
   frm.textBoxAzon.Text = 
  listViewData.Items[listViewData.SelectedIndices[0]].Text; 
   frm.textBoxNev.Text = 
  listViewData.Items[listViewData.SelectedIndices[0]].SubItems[1].Text; 
   DateTime d = new DateTime(); 
   d = Convert.ToDateTime( 
  listViewData.Items[listViewData.SelectedIndices[0]].SubItems[2].Text); 
   frm.dateTimePickerSzDatum.Value = d; 
   if (frm.ShowDialog() == DialogResult.OK) 
   { 
  listViewData.Items[listViewData.SelectedIndices[0]].Text = 
       frm.Beazon; 
  listViewData.Items[listViewData.SelectedIndices[0]].SubItems[1].Text = 
       frm.Benev; 
  listViewData.Items[listViewData.SelectedIndices[0]].SubItems[2].Text = 
       frm.Beszul.ToShortDateString(); 
   } 
} 
 
   // Bináris file-ba mentés 
   private void buttonSave_Click(object sender, EventArgs e) 
   { 
      SaveFileDialog sf = new SaveFileDialog(); 
      if (sf.ShowDialog() == DialogResult.OK) 
      { 
         BinaryWriter br = new BinaryWriter(File.Open(sf.FileName, 
                                    FileMode.Create)); 
         try 
         { 
            int i; 
            for (i = 0; i < listViewData.Items.Count; i++) 
            { 
               br.Write(listViewData.Items[i].Text); 
               br.Write(listViewData.Items[i].SubItems[1].Text); 
               br.Write(listViewData.Items[i].SubItems[2].Text); 
            } 
            br.Flush(); 
         } 
         catch 
         { 
            MessageBox.Show("Hiba a mentésben."); 
         } 
         finally 
         { 
            br.Close(); 
         } 
      } 
   }

18.57. forráskód. A főform eseménykezelői, metódusai

 
   // Visszatöltés bináris file-ból 
   private void buttonOpen_Click(object sender, EventArgs e) 
   { 
      OpenFileDialog of = new OpenFileDialog(); 
      if (of.ShowDialog() == DialogResult.OK) 
      { 
         string sa; 
         listViewData.Items.Clear(); 
         BinaryReader br = new BinaryReader(File.Open(of.FileName, 
                                    FileMode.Open)); 
         try 
         { 
            if (File.Exists(of.FileName)) 
            { 
               long len1 = br.BaseStream.Length; 
               while (br.BaseStream.Position < len1) 
               { 
                  azon = br.ReadString(); 
                  nev = br.ReadString(); 
                  sa = br.ReadString(); 
                  ListViewItem li = new ListViewItem(azon, 0); 
                  li.SubItems.Add(nev); 
                  li.SubItems.Add(sa); 
                  listViewData.Items.Add(li); 
               } 
            } 
         } 
         catch { } 
         finally 
         { 
            br.Close(); 
         } 
      } 
   } 
 
   // Sor törlése 
   private void buttonDel_Click(object sender, EventArgs e) 
   { 
      listViewData.Items[listViewData.SelectedIndices[0]].Remove(); 
   }

18.39. feladat (Memóriaszint: 4). Írj memória játék programot. A következő beállításokat támogassa a program:

  • hány szám legyen (6 vagy 9)

  • mennyi ideig látszódjanak (5, 10, vagy 20 mp)

  • hány jegyűek legyenek (1 vagy 2)

Ha 6 db számot kell kitalálni, akkor 5/10 mp, ha 9 számot, akkor pedig 10/20 mp legyen a választható. A program a beállított paramétereknek megfelelően generáljon számokat és jelenítse meg azokat egy ideig, majd kérdezze vissza őket. A számok megjelenítéséhez és visszakérdezéséhez is modális ablakokat használjunk. A visszakérdezéskor csak annyi tippje lehessen a játékosnak, mint amennyi a kitalálandó számok darabszáma.

18.40. ábra. Kezdő ablak

18.41. ábra. További megjelenő formok

18.58. forráskód. Játék indítása és kiértékelése

     
private void BT_Indulhat_Click(object sender, EventArgs e) 
{ 
   int db = (RB_szam6.Checked) ? 6 : 9; 
   Frm_Szamok frm_Szamok = new Frm_Szamok( 
      db, 
      (CB_Egyjegyu.Checked) ? 1 : 2, 
      RB_mp5.Checked ? 5 : RB_mp10.Checked ? 10 : 20); 
   frm_Szamok.ShowDialog(); 
   Frm_Memoria frm_Memoria = new Frm_Memoria(db); 
   frm_Memoria.ShowDialog(); 
   int joValasz = 0; 
   foreach (int i in frm_Memoria.tippek) 
   { 
      if (frm_Szamok.szamok.Contains(i)) 
      { 
         joValasz++; 
      } 
   } 
   MessageBox.Show(String.Format("A jó válaszok száma: {0}", joValasz)); 
}
    

18.59. forráskód. Számok megjelenítése

 
private void LabelekKirak(int db, int szamjegy) 
{  Random veletlen = new Random(); 
   int meretSzelesseg = (panel1.Width - 40) / 3; 
   int meretMagassag = 200 / (db / 3); 
   szamok = new List<int>(db); 
   int min, max; 
   if (szamjegy == 1) 
   {  min = 1; max = 9; } 
   else 
   {  min = 10; max = 99; } 
   for (int i = 0; i < db; i++) 
   { 
      Label ujLabel = new Label(); 
      int x = i % 3, y = i / 3; 
      ujLabel.Location = new Point(x * (meretSzelesseg + 10) + 10, 
                              y * (meretMagassag + 10) + 10); 
      ujLabel.Size = new Size(meretSzelesseg, meretMagassag); 
      ujLabel.Font = new Font(Font.FontFamily, 16); 
      ujLabel.TextAlign = ContentAlignment.MiddleCenter; 
      ujLabel.BackColor = Color.Red; 
      int ujSzam; 
      do 
      {  ujSzam = veletlen.Next(max - min + 1) + min; 
      } while (szamok.Contains(ujSzam)); 
      szamok.Add(ujSzam); 
      ujLabel.Text = ujSzam.ToString(); 
      panel1.Controls.Add(ujLabel); 
   } 
}

Magyarázat: A labeleket dinamikusan rakja fel a formra, mivel nem tudni előre, hogy hány számot kell megjeleníteni.

18.60. forráskód. Tipp hozzáadása

     
private void BT_Hozzaad_Click(object sender, EventArgs e) 
{ 
   if (!listBox1.Items.Contains(TB_Szam.Text)) 
   { 
      int temp; 
      if (int.TryParse(TB_Szam.Text, out temp)) 
      { 
         listBox1.Items.Add(TB_Szam.Text); 
         tippek.Add(temp); 
      } 
   } 
   TB_Szam.Text = String.Empty; 
   TB_Szam.Focus(); 
   if (maxDb == listBox1.Items.Count) 
   { 
      TB_Szam.Enabled = BT_Hozzaad.Enabled = false; 
   } 
}
    

Magyarázat: Maximálisan annyi számot lehessen beírni, amennyit eredetileg kiválasztottunk megtekintésre.

Időzítés és üzenetek

18.40. feladat (Időzítés használataszint: 2). Írj programot, mely a form közepén mutatja a futó időt másodperc pontosan.

18.42. ábra. Időzítés használata

Magyarázat: Az időzítés legegyszerűbben a Timer komponens segítségével oldhatjuk meg. Használjuk a Tick eseményt. Figyeljünk rá, hogy az időzítőt engedélyezni kell. Az alapértelmezett értéke false.

18.61. forráskód. Időzítés használata

     
namespace timer_1 
{ 
   public partial class Form1 : Form 
   { 
 
      public Form1() 
      { 
         InitializeComponent(); 
         timer1.Enabled = true; 
      } 
 
      private void timer1_Tick(object sender, EventArgs e) 
      { 
         labelIdo.Text = DateTime.Now.ToLongTimeString(); 
      } 
   } 
}
    

18.41. feladat (Form színe időzítveszint: 1). Írj programot, mely 1 másodpercenként megváltoztatja a form háttérszínét.

Magyarázat: Egy lehetséges megoldás a színek ciklikus változtatására a maradékos osztás használata.

18.62. forráskód. Időzítés használata

 
namespace idozit_2 
{ 
   public partial class Form1 : Form 
   { 
      int ind = 0; 
      Color[] szinek = new Color[5] 
         { Color.White, Color.Blue, Color.Beige, 
            Color.Black, Color.DarkSeaGreen }; 
 
      public Form1() 
      { 
         InitializeComponent(); 
      } 
 
      private void Form1_Load(object sender, EventArgs e) 
      { 
         timer1.Interval = 1000; 
         timer1.Enabled = true; 
      } 
 
      private void timer1_Tick(object sender, EventArgs e) 
      { 
         this.BackColor = szinek[ind % 5]; 
         ind++; 
      } 
   } 
}

18.42. feladat (Új formok születése és halálaszint: 2). Írj programot, 2 másodpercenként megjelenít egy 20 másodpercig látható formot. Ezt 1 percig csinálja. Minden új form más más feliratot tartalmazzon.

18.43. ábra. Új formok születése és halála

Magyarázat: Több timerre is szükségünk lesz mind a főformon, ami méri a 2 másodperceket, mind a létrejövő formokon, ami a 20 másodpercekért felel. A főformon az 1 percet is figyelni kell.

18.63. forráskód. A vezérlés a főformon

     
DateTime kezdido = new DateTime(); int x, y; TimeSpan eltelt; 
private void button1_Click(object sender, EventArgs e) 
{  timer1.Enabled = true; 
   timer1.Interval = 2000; 
   kezdido = DateTime.Now; } 
private void timer1_Tick(object sender, EventArgs e) 
{  eltelt = DateTime.Now - kezdido; 
   if (eltelt.Seconds > 60) this.Close(); 
   Form2 frm = new Form2(); 
   frm.label1.Text = DateTime.Now.ToLongTimeString(); 
   frm.x = x % 800; 
   frm.y = y % 600; 
   frm.Show(); 
   x += 100; 
   y += 100; } }
    

18.64. forráskód. A megjelenő formok

 
private void Form2_Load(object sender, EventArgs e) 
{ timer1.Enabled = true; } 
private void timer1_Tick(object sender, EventArgs e) 
{ this.Close(); } 
private void Form2_Shown(object sender, EventArgs e) 
{ this.Top = y; 
  this.Left = x; }

18.43. feladat (Keringő formszint: 2). Írjon programot, mely egy formot mozgat a képernyőn körbe, 1 másodperces időközzel lépkedve. A mozgás 2 percig menjen az indítástól. Használj felsorolás típust a mozgás irányának tárolásához.

18.44. ábra. Körbe fut a képernyőn

18.65. forráskód. Felsorolás típus létrehozása

     
namespace Korbefut 
{  enum Iranyok 
   {  Jobbra, 
      Le, 
      Balra, 
      Fel 
   } 
}
    

Magyarázat: Az éppen aktuális irány tárolásához hozzunk létre egy felsorolás típust (Jobbra,Le,Balra,Fel).

18.66. forráskód. Feladat megoldása

 
private void timer_Tick(object sender, EventArgs e) 
{  label.Text = String.Format("{0} mp", stopper.Elapsed.TotalSeconds); 
   if (stopper.Elapsed.TotalSeconds >= 120) 
   { 
      timer.Enabled = false; 
      stopper.Stop(); 
      Left = (Screen.PrimaryScreen.Bounds.Width - Width) / 2; 
      Top = (Screen.PrimaryScreen.Bounds.Height - Height) / 2; 
      return; 
   } 
   switch (irany) 
   {  case Iranyok.Jobbra: 
         if (Left + lepes < Screen.PrimaryScreen.Bounds.Width - Width) 
            Left += lepes; 
         else 
         {  Left = Screen.PrimaryScreen.Bounds.Width - Width; 
            irany = Iranyok.Le; 
         }  break; 
      case Iranyok.Le: 
         if (Top + lepes <Screen.PrimaryScreen.Bounds.Height - Height) 
            Top += lepes; 
         else 
         {  Top = Screen.PrimaryScreen.Bounds.Height - Height; 
            irany = Iranyok.Balra; 
         }  break; 
      case Iranyok.Balra: 
         if (Left - lepes > 0) 
            Left -= lepes; 
         else 
         {  Left = 0; 
            irany = Iranyok.Fel; 
         }  break; 
      case Iranyok.Fel: 
         if (Top - lepes > 0) 
            Top -= lepes; 
         else 
         {  Top = 0; 
            irany = Iranyok.Jobbra; 
         }  break; 
   } 
}

Magyarázat: Az aktuális állapot alapján mindig tudhatjuk, hogy merre kell mozgatni a form-ot, és melyik lesz a következő irány, ha elértük a képernyő megfelelő szélét. Figyeljünk arra, hogy mivel fix nagyságú lépéseket teszünk, nem biztos, hogy pontosan a képernyő széléhez ér az ablak majd a mozgás végén, ezért igazítsuk be (ne lógjon ki és ne is maradjon rés).

18.44. feladat (TiliToli játékszint: 3). Írjon pogramot, mely megvalósítja a TiliToli játékot. Közben valósítsa meg az időmérést is.

18.45. ábra. TiliToli játék

Magyarázat: A játék lemezkéit egy-egy dinamikusan létrehozott label komponens valósítsa meg. Az újonnan létrehozott labeleket tároljuk el egy kétdimenziós tömbben, és mindegyikéhez ugyanazt az eseménykezelőt rendeljük. A közös metódus a sender objektumban utazó label pozíciójából „találja ki”, hogy ő melyik a rácsban. Ha a lyuk melletti lemezre kattintunk, akkor az cseréljen helyet a lyukkal. Készítsünk függvényt, ami a labelek feliratából és helyes sorrendjéből meghatározza, hogy jó-e az elrendezés.

18.67. forráskód. A kérdéses metódusok

     
void ujLabel_Click(object sender, EventArgs e) 
{ 
   if (!timer.Enabled) 
   { 
      timer.Enabled = true; 
   } 
   Label kep = (sender as Label); 
   int i = kep.Left / meret; 
   int j = kep.Top / meret; 
   if (i > 0 && labelek[i - 1, j] == null) 
   { 
      Csere(i, j, i - 1, j); 
   } 
   else 
      if (i < N - 1 && labelek[i + 1, j] == null) 
      { 
         Csere(i, j, i + 1, j); 
      } 
      else 
         if (j > 0 && labelek[i, j - 1] == null) 
         { 
            Csere(i, j, i, j - 1); 
         } 
         else 
            if (j < N - 1 && labelek[i, j + 1] == null) 
            { 
               Csere(i, j, i, j + 1); 
            } 
   if (MindegyikJoHelyen()) 
   { 
      timer.Enabled = false; 
      MessageBox.Show("Gratulálok, kész! {0}",Lb_Ido.Text ); 
   } 
} 
 
private bool MindegyikJoHelyen() 
{ 
   bool jo = true; 
   for (int db = 0; (db < N * N) && jo; db++) 
   { 
      int i = db % N; 
      int j = db / N; 
      if (labelek[i, j] != null) 
      { 
         jo = Convert.ToInt32(labelek[i, j].Text) == (db + 1); 
      } 
   } 
   return jo; 
}