Grafikus C# – Windows Forms tanfolyam › 1.5 lecke

Windows Forms · 1.5 lecke · önálló gyakorlás

CheckedListBox és ListBox – több elem kiválasztása

Egy névlistából több nevet is ki lehet választani, majd a kijelölteket egy másik listába lehet másolni. Ebben a leckében megismered a két lista vezérlő működését, és megtanulod megkülönböztetni a kijelölt és a bepipált elemet.

  • kb. 60 perc
  • kezdő szint
  • listák
Diáklány C# programot készít laptopon

A lecke végére

  • listákat töltesz fel elemekkel az Items.Add() metódussal;
  • megkülönbözteted a kijelölt (Selected) és a bepipált (Checked) elemet;
  • a foreach ciklussal végigmész a bepipált elemeken;
  • törölsz egy elemet vagy az egész listát (RemoveAt, Clear);
  • kiolvasod az elemek számát (Items.Count);
  • beállítod a CheckOnClick tulajdonságot, hogy egy kattintás elég legyen a pipához.

Mielőtt elkezded

Ehhez a leckéhez kell az 1.4 lecke és a Form1_Load eseményt bemutató 0.8 lecke. A foreach ciklust a lecke közben magyarázzuk el.

1.4 CheckBox és RadioButton →

0.8 A Form élete →

A felület

Tegyél az ablakra két listát, két gombot és egy feliratot:

clbNevekEgy CheckedListBox: minden sora mellett jelölőnégyzet van. Az előtag clb.
lstValasztottEgy ListBox: a kiválasztott nevek listája. Az előtag lst.
btnAtmasol, btnTorol, btnKijeloltTorolHárom gomb: Kijelöltek másolása, Lista ürítése és Kijelölt törlése (ez utóbbit az 5. szakaszban használjuk).
lblDarabEgy Label, amely a kiválasztott nevek számát mutatja.

Állítsd a clbNevek CheckOnClick tulajdonságát True-ra (lásd a 3. szakaszt).

📷 Képernyőkép helye

Mit tegyél ide: a tervezőnézet két egymás melletti listával (balra a CheckedListBox néhány névvel, jobbra az üres ListBox), alattuk a két gomb és a számláló felirat.Javasolt fájlnév: winforms-1-5-felulet.webp · Alt szöveg: Az ablak CheckedListBoxszal, ListBoxszal és két gombbal a tervezőben

A lista feltöltése

A lista elemeit az Items gyűjtemény tartalmazza. Az Add() metódussal egyenként adhatsz hozzá elemet. A betöltéskor futó Form1_Load eseményben töltsük fel a nevekkel:

Form1.csC#
private void Form1_Load(object sender, EventArgs e)
{
clbNevek.Items.Add("István");
clbNevek.Items.Add("Judit");
clbNevek.Items.Add("Béla");
clbNevek.Items.Add("Lilla");
}
Items.Add("István")Hozzáad egy elemet a lista végéhez.
Form1_LoadAz ablak betöltésekor egyszer fut le (0.8 lecke), ezért ide jó az induló adatok betöltése.
Rövidebben: AddRangeTöbb elemet egyszerre is hozzáadhatsz: clbNevek.Items.AddRange(new object[] { "István", "Judit" });. A new object[] { ... } egy elemlistát készít, amelyet a tömbökről szóló leckében részletesen tanulunk.
Properties ablakbólAz Items tulajdonságnál a (Collection) gombbal a tervezőben is beírhatod az elemeket, ahogy a ComboBoxnál (1.6, 2.5).

Jósolj!

Megnyitod a programot, de a Form1_Load metódust kézzel gépelted be, nem dupla kattintással hoztad létre. Mi lesz a listában?

Jóslat ellenőrzése

Üres lesz, mert a metódus nincs összekötve a Load eseménnyel, ezért sosem fut le. A tervezőben az ablak üres részére duplán kattintva jön létre a megfelelően összekötött Form1_Load.

Kijelölt vagy bepipált?

A CheckedListBoxban két külön dolog van, és könnyű összekeverni:

FogalomMit jelent?Tulajdonság
Kijelölt (Selected)A sor, amelyre rákattintottál, kiemelve látszik. Egyszerre egy sor lehet kijelölt.SelectedItem, SelectedIndex
Bepipált (Checked)A sor melletti jelölőnégyzet be van pipálva. Egyszerre több is lehet.CheckedItems

A CheckOnClick tulajdonság

Alapból az első kattintás csak kijelöli a sort, és a második kattintás pipálja be. Ez zavaró. A CheckOnClick tulajdonság True értékével már az első kattintás bepipálja a sort.

Jósolj!

A CheckOnClick értéke False. Egyszer rákattintasz a „Judit” sorra. Be van pipálva?

Jóslat ellenőrzése

Nincs. Az első kattintás kijelöli a sort, és csak a második kattintás pipálja be. A CheckOnClick = True esetén az első kattintás is bepipálja.

Új fogalom: a foreach ciklus

A bepipált elemek számát nem tudjuk előre, ezért ciklussal megyünk végig rajtuk. A foreach (magyarul: „minden egyes”) ciklus a gyűjtemény minden elemére egyszer lefuttatja a kapcsos zárójelek közötti kódot:

Form1.csC#
private void btnAtmasol_Click(object sender, EventArgs e)
{
lstValasztott.Items.Clear();

foreach (object nev in clbNevek.CheckedItems)
{
lstValasztott.Items.Add(nev);
}

lblDarab.Text = $"Kiválasztva: {lstValasztott.Items.Count}";
}
foreach (object nev in clbNevek.CheckedItems)Minden bepipált elemre egyszer lefut a blokk. A nev az éppen soron lévő elem.
lstValasztott.Items.Clear()Kiüríti a jobb oldali listát, hogy a másolás ne ismétlődjön.
Items.Add(nev)A bepipált elemet hozzáadja a jobb oldali listához.
Items.CountA lista elemeinek száma.

Jósolj!

Bepipálod az István és a Lilla nevet, és megnyomod a gombot. Hány elem lesz a jobb oldali listában, és mi áll a feliraton?

Jóslat ellenőrzése

Két elem: István és Lilla. A felirat: Kiválasztva: 2. A foreach kétszer fut le, mert két bepipált elem van.

📷 Képernyőkép helye

Mit tegyél ide: a futó program: a bal listában az István és a Lilla be van pipálva, a jobb listában ugyanez a két név látszik, alatta a „Kiválasztva: 2” felirat.Javasolt fájlnév: winforms-1-5-atmasolas.webp · Alt szöveg: A bepipált nevek átmásolva a jobb oldali listába

Törlés és darabszám

Két törlési mód van: az egész lista ürítése (Clear()) és egy kijelölt elem törlése (RemoveAt()). Utóbbinál a SelectedIndex mondja meg, melyik elem a kijelölt (ha nincs kijelölt elem, az értéke -1).

Form1.csC#
private void btnTorol_Click(object sender, EventArgs e)
{
lstValasztott.Items.Clear();
lblDarab.Text = "Kiválasztva: 0";
}

private void btnKijeloltTorol_Click(object sender, EventArgs e)
{
if (lstValasztott.SelectedIndex >= 0)
{
lstValasztott.Items.RemoveAt(lstValasztott.SelectedIndex);
}
else
{
MessageBox.Show("Előbb jelölj ki egy elemet!");
}

lblDarab.Text = $"Kiválasztva: {lstValasztott.Items.Count}";
}
SelectedIndex >= 0Akkor igaz, ha van kijelölt elem (ha nincs, az érték -1).
RemoveAt(index)Törli a megadott sorszámú elemet. A számozás 0-tól indul.

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. A kijelölteket másolja a bepipáltak helyett

foreach (object nev in clbNevek.SelectedItems)
{
lstValasztott.Items.Add(nev);
}
Hiba és javítás

Rossz működés: a SelectedItems a kijelölt (kiemelt) sorokat adja, nem a bepipáltakat. A CheckedListBox jelölőnégyzeteihez a CheckedItems kell.

2. Összeomlik törléskor

lstValasztott.Items.RemoveAt(lstValasztott.SelectedIndex);
Hiba és javítás

Futás közbeni hiba (ArgumentOutOfRangeException), ha nincs kijelölt elem, mert a SelectedIndex ilyenkor -1. Előbb ellenőrizd: if (lstValasztott.SelectedIndex >= 0).

3. Duplikált nevek

A másolás gombot kétszer nyomod meg, és a jobb listában kétszer szerepelnek a nevek.

Ok és javítás

A másolás előtt nem ürítetted a jobb oldali listát. Tedd az eseménykezelő elejére az lstValasztott.Items.Clear(); sort.

4. Üres a lista induláskor

Az ablak megnyitása után egyetlen név sincs a listában.

Ok és javítás

A Form1_Load nincs összekötve a Load eseménnyel (kézzel gépelted be), vagy üres a metódus belseje. Kattints duplán az ablak üres részére a tervezőben, és ott add meg a feltöltést.

5. Kétszer kell kattintani a pipához

A CheckedListBoxban egy kattintás csak kijelöl, nem pipál.

Ok és javítás

A CheckOnClick tulajdonság értéke False. Állítsd True-ra a Properties ablakban.

Mini projekt: meghívottak listája

Állítsd össze a teljes programot:

  1. A két lista, a gombok és a felirat a megadott nevekkel. A CheckOnClick legyen True.
  2. A Form1_Load töltse fel a nevekkel a CheckedListBoxot (legalább hat név).
  3. A Kijelöltek másolása gomb másolja át a bepipált neveket, és a felirat mutassa a darabszámot.
  4. A Lista ürítése gomb ürítse a jobb oldali listát.
  5. Próbáld ki: pipálj be két nevet, másold át, majd pipálj be még egyet, és másolj újra.
📷 Képernyőkép helye

Mit tegyél ide: a kész program néhány bepipált névvel és a másolt névsorral a jobb oldali listában.Javasolt fájlnév: winforms-1-5-meghivottak.webp · Alt szöveg: A kész meghívottak listája program

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Új név hozzáadása

Tegyél az ablakra egy txtUj beviteli mezőt és egy btnHozzaad gombot, amely az új nevet a CheckedListBox végére teszi (üres név ne kerüljön be).

Egy lehetséges megoldás
string nev = txtUj.Text.Trim();

if (nev.Length > 0)
{
clbNevek.Items.Add(nev);
txtUj.Clear();
}

2. Kijelölt elem törlése

Készíts egy btnKijeloltTorol gombot, amely a jobb oldali listából a kijelölt elemet törli.

Egy lehetséges megoldás

Használd a leckében látott btnKijeloltTorol_Click eseménykezelőt, SelectedIndex >= 0 ellenőrzéssel és RemoveAt hívással.

3. Mennyi van bepipálva?

Írd ki egy lblBepipalt feliratra, hogy hány elem van bepipálva a bal oldali listában. A CheckedItems gyűjteménynek is van Count tulajdonsága.

Egy lehetséges megoldás
lblBepipalt.Text = $"Bepipálva: {clbNevek.CheckedItems.Count}";

Tedd a másolás gombba, vagy a lista ItemCheck eseményéhez (az 5. fejezetben tanulunk róla).

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Használd a txtElem beviteli mezőt, a lstElemek ListBoxot és a leírt gombokat. Csak a saját próbálkozásod után nyisd le a megoldást.

Alap szint

1. Elem hozzáadása

A btnHozzaad gomb vegye fel a mezőbe írt szöveget a listába, majd ürítse a mezőt. Üres szöveget ne vegyen fel.

Megoldás megnyitása

A Items.Add adja hozzá az elemet. A Trim() a szóközöket levágja a szöveg széléről.

Form1.csC#
private void btnHozzaad_Click(object sender, EventArgs e)
{
string elem = txtElem.Text.Trim();

if (elem.Length == 0)
{
MessageBox.Show("Írj be valamit!");
return;
}

lstElemek.Items.Add(elem);
txtElem.Clear();
txtElem.Focus();
}

2. A kijelölt elem törlése

A btnTorol gomb törölje a kijelölt elemet. Ha nincs kijelölt elem, a program ne omoljon össze, hanem szóljon.

Megoldás megnyitása

A SelectedIndex értéke -1, ha nincs kijelölt elem. A RemoveAt(-1) hibát okozna, ezért előbb ellenőrzünk.

Form1.csC#
private void btnTorol_Click(object sender, EventArgs e)
{
if (lstElemek.SelectedIndex >= 0)
{
lstElemek.Items.RemoveAt(lstElemek.SelectedIndex);
}
else
{
MessageBox.Show("Előbb jelölj ki egy elemet!");
}
}

Közepes szint

3. Duplikáció elkerülése

Ugyanaz az elem ne kerülhessen be kétszer a listába.

Megoldás megnyitása

Az Items.Contains igaz, ha az elem már szerepel. Az összehasonlítás kis- és nagybetűre is érzékeny (az alma és az Alma két külön elem).

Form1.csC#
private void btnHozzaad_Click(object sender, EventArgs e)
{
string elem = txtElem.Text.Trim();

if (elem.Length == 0)
{
MessageBox.Show("Írj be valamit!");
}
else if (lstElemek.Items.Contains(elem))
{
MessageBox.Show("Ez az elem már szerepel a listában.");
}
else
{
lstElemek.Items.Add(elem);
txtElem.Clear();
}
}

4. A bepipált elemek listázása

Egy CheckedListBox (clbTantargyak) tantárgyakat tartalmaz. A btnListaz gomb írja a lblEredmeny feliratra a bepipált elemeket vesszővel elválasztva.

Megoldás megnyitása

A CheckedItems csak a bepipált elemeket tartalmazza (nem azonos a kijelölt elemmel). A foreach végigmegy rajtuk, a TrimEnd a felesleges záró vesszőt és szóközt levágja.

Form1.csC#
private void btnListaz_Click(object sender, EventArgs e)
{
string lista = "";

foreach (object elem in clbTantargyak.CheckedItems)
{
lista = lista + elem.ToString() + ", ";
}

if (lista.Length == 0)
{
lblEredmeny.Text = "Nincs bepipált elem.";
}
else
{
lblEredmeny.Text = lista.TrimEnd(',', ' ');
}
}

Kihívás szint

5. Másolás másik listába

A btnMasol gomb másolja át a bepipált elemeket a lstValasztott ListBoxba (előbb ürítse), majd kapcsolja ki az összes pipát.

Megoldás megnyitása

A pipák kikapcsolása során a SetItemChecked(index, false) metódus kell, mert az elemeket indexükkel érjük el. A for ciklus a Items.Count értékéig megy.

Form1.csC#
private void btnMasol_Click(object sender, EventArgs e)
{
lstValasztott.Items.Clear();

foreach (object elem in clbTantargyak.CheckedItems)
{
lstValasztott.Items.Add(elem);
}

for (int i = 0; i < clbTantargyak.Items.Count; i++)
{
clbTantargyak.SetItemChecked(i, false);
}
}

6. Bevásárlólista darabszámmal

A lista legyen ábécébe rendezett, és a lblDarab felirat mutassa: 3 tétel. Hozzáadás és törlés után is frissüljön.

Megoldás megnyitása

A ListBox Sorted tulajdonságát állítsd True értékre a Properties ablakban: ekkor automatikusan rendezett marad. A darabszámot a Items.Count adja, amelyet külön metódusban frissítünk, és minden változtatás után meghívunk.

Form1.csC#
private void DarabFrissit()
{
lblDarab.Text = $"{lstElemek.Items.Count} tétel";
}

private void btnHozzaad_Click(object sender, EventArgs e)
{
string elem = txtElem.Text.Trim();

if (elem.Length > 0)
{
lstElemek.Items.Add(elem);
txtElem.Clear();
DarabFrissit();
}
}

private void btnTorol_Click(object sender, EventArgs e)
{
if (lstElemek.SelectedIndex >= 0)
{
lstElemek.Items.RemoveAt(lstElemek.SelectedIndex);
DarabFrissit();
}
}

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Melyik gyűjtemény tartalmazza a bepipált elemeket?

A CheckedItems.

2. Mi a különbség a kijelölt és a bepipált elem között?

A kijelölt sor kiemelt (egyszerre egy lehet), a bepipált sor jelölőnégyzete be van jelölve (egyszerre több is lehet).

3. Mit csinál az Items.Clear()?

Kiüríti a lista összes elemét.

4. Mit csinál a foreach?

A gyűjtemény minden elemére egyszer lefuttatja a ciklus belsejét.

5. Mi a SelectedIndex értéke, ha nincs kijelölt elem?

-1.

6. Mikor fut a Form1_Load?

Az ablak betöltésekor, még a megjelenése előtt, egyszer.

Mit tudsz már?

  • Feltöltöd a listákat elemekkel.
  • Megkülönbözteted a kijelölt és a bepipált elemet.
  • A foreach ciklussal végigmész a bepipált elemeken.
  • Törölsz egy elemet vagy az egész listát.
  • Beállítod a CheckOnClick tulajdonságot.

Következő lecke: ComboBox, TrackBar és DateTimePicker

Eddig listából több elemet választottunk. A következő leckében legördülő listát, csúszkát és dátumválasztót használunk.