Grafikus C# – Windows Forms tanfolyam › 2.8 lecke Windows Forms · 2.8 lecke Egy szövegszerkesztőben a Ctrl+F keresés nélkülözhetetlen. Ebben a leckében a MiniWord megtanul keresni: először az első találatot kijelöli, majd az összes előfordulást sárgára színezi. Közben megismerjük az Szövegkeresés és az összes találat kiemelése
IndexOf metódust, a while ciklust és a kiemelés trükkjét.
A lecke végére
- az
IndexOfmetódussal megkeresed egy szöveg helyét egy másik szövegben; - a
Select()metódussal kijelölöd a találatot a szövegdobozban; whileciklussal végigmész az összes találaton;- a
SelectionBackColorsegítségével sárgára színezed az összes előfordulást; - érted, miért kiemelés az „összes találat kijelölése”;
- kezeled az üres keresőszöveget és a kis- és nagybetű kérdését.
Mielőtt elkezded
Ehhez a leckéhez kell a MiniWord a 2.7 lecke után, ismerned kell a Select() és a SelectionLength fogalmát (2.4), valamint az if–else szerkezetet. A while ciklust itt a lecke közben magyarázzuk el.
A keresősáv
Tegyél a MiniWord ablakára három új vezérlőt:
TextBox: ide írja be a felhasználó a keresett szót.Keresés felirattal: az első találatot jelöli ki.Összes kiemelése felirattal: az összes találatot sárgára színezi.HideSelection tulajdonságát állítsd False-ra (2.4 lecke), hogy a kijelölés a gombnyomás után is látszódjon.Mit tegyél ide: a MiniWord keresősávja a txtKeres beviteli mezővel és a két gombbal (Keresés, Összes kiemelése), alatta a szövegdobozzal.Javasolt fájlnév: winforms-2-8-keresosav.webp · Alt szöveg: A MiniWord keresősávja beviteli mezővel és két gombbal
Az IndexOf: hol van a keresett szöveg?
A string típusnak van egy IndexOf metódusa (ismerős lehet a C# alapokból). Megmondja, hogy a keresett szöveg hányadik karakternél kezdődik. A számozás 0-tól indul. Ha nincs találat, az eredmény -1.
string szoveg = "Szia Peti, szia Anna!";
int hely = szoveg.IndexOf("szia", StringComparison.OrdinalIgnoreCase);
// hely értéke: 0 (a nagybetűs Szia a legelején van)StringComparison.Ordinal megkülönbözteti őket.Jósolj!
A szöveg: Szia Peti, szia Anna!. Mi az IndexOf("Anna", ...) eredménye? És mi a IndexOf("Bence", ...) eredménye?
Jóslat ellenőrzése
Az „Anna” a 16. karakternél kezdődik (a számolás 0-tól indul: a „Szia Peti, szia ” 16 karakter). A „Bence” nem szerepel a szövegben, ezért az eredmény -1.
Miért Ordinal?
A magyar nyelvben vannak betűkapcsolatok (például cs, sz, zs), amelyekre a nyelvfüggő összehasonlítás másképp viselkedhet, és a visszaadott pozíció nem mindig egyezik a szövegdobozban lévő pozícióval. Az Ordinal és az OrdinalIgnoreCase mindig karakterről karakterre hasonlít, ezért biztonságos a keresésnél.
Az első találat kijelölése
private void btnKeres_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
if (keresett.Length == 0)
{
MessageBox.Show("Írd be, mit keressek!");
}
else
{
int hely = rtbDokumentum.Text.IndexOf(keresett, StringComparison.OrdinalIgnoreCase);
if (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.Focus();
}
else
{
MessageBox.Show("Nincs találat.");
}
}
}Mit tegyél ide: a MiniWord egy dokumentummal, amelyben a keresett szó első előfordulása kijelölve (kék háttér) látszik, mellette a txtKeres mezőben a keresett szó.Javasolt fájlnév: winforms-2-8-elso-talalat.webp · Alt szöveg: A MiniWord az első találatot kijelöli a szövegben
Új fogalom: a while ciklus
Az összes találat megkereséséhez ismételnünk kell a keresést, amíg van találat. Erre való a while (magyarul: „amíg”) ciklus: addig ismétli a kapcsos zárójelek közötti kódot, amíg a feltétel igaz.
int szam = 1;
while (szam <= 3)
{
MessageBox.Show("Szám: " + szam);
szam = szam + 1;
}Jósolj!
Hányszor jelenik meg az üzenetablak a fenti példában? Mik a számok?
Jóslat ellenőrzése
Háromszor: 1, 2 és 3. A negyedik körben a szam értéke 4, a szam <= 3 feltétel hamis, ezért a ciklus véget ér.
Az összes találat kiemelése
A RichTextBoxnak egyszerre csak egyetlen kijelölése lehet, ezért az „összes találat kijelölése” valójában kiemelés: minden találatot sárga háttérrel színezünk. A SelectionBackColor tulajdonság a kijelölt szöveg háttérszínét állítja.
private void btnOsszes_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
if (keresett.Length == 0)
{
MessageBox.Show("Írd be, mit keressek!");
}
else
{
TorolKiemeleseket();
string szoveg = rtbDokumentum.Text;
int darab = 0;
int hely = szoveg.IndexOf(keresett, 0, StringComparison.OrdinalIgnoreCase);
while (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.SelectionBackColor = Color.Yellow;
darab = darab + 1;
hely = szoveg.IndexOf(keresett, hely + keresett.Length, StringComparison.OrdinalIgnoreCase);
}
rtbDokumentum.Select(0, 0);
MessageBox.Show($"Találatok száma: {darab}");
}
}
private void TorolKiemeleseket()
{
rtbDokumentum.SelectAll();
rtbDokumentum.SelectionBackColor = rtbDokumentum.BackColor;
rtbDokumentum.Select(0, 0);
}A kiemelés a dokumentum része
A háttérszín formázás, ezért az RTF fájlba is belekerül. Ha mentés előtt nem törlöd a kiemeléseket, a mentett dokumentumban is sárga szavak lesznek. Ha a Color alá hullámvonal kerül, add a fájl elejéhez a using System.Drawing; sort.
Mit tegyél ide: a MiniWord egy dokumentummal, amelyben a keresett szó minden előfordulása sárgával kiemelt. Mellette az üzenetablak a „Találatok száma: 4” szöveggel.Javasolt fájlnév: winforms-2-8-osszes-talalat.webp · Alt szöveg: A MiniWord a keresett szó összes előfordulását sárgával kiemeli
Jósolj, aztán futtasd!
Minden feladatnál először írd le, mit vársz, és csak utána próbáld ki.
1. Kis- és nagybetű
A dokumentumban ez áll: 3, mert az Alma alma ALMA. Az „alma” szóra keresel az Összes kiemelése gombbal. Hány találat lesz?Jóslat ellenőrzése
OrdinalIgnoreCase nem tesz különbséget a kis- és nagybetű között.
2. Átfedő találatok
A dokumentum: 1: a program az első találat vége után folytatja a keresést, ezért az átfedő második „aa” nem számít.aaa. Az „aa” szóra keresel. Hány találat lesz?Jóslat ellenőrzése
3. Nincs találat
Olyan szót keresel, amely nincs a dokumentumban. Mit kapsz az Összes kiemelése gombra? A ciklus egyszer sem fut le, a Jóslat ellenőrzése
darab értéke 0 marad, és az üzenet: Találatok száma: 0.
4. Két keresés egymás után
Először az „alma” szóra, utána a „körte” szóra keresel az Összes kiemelése gombbal. Mi látszik a második keresés után? Csak a „körte” találatai sárgák, mert a keresés elején a Jóslat ellenőrzése
TorolKiemeleseket() eltünteti az előző kiemeléseket.
Hibakeresés: te vagy a hibadetektív
Hibavadászat
Jósold meg, hogy fordítási hiba, futás közbeni hiba vagy rossz működés lesz-e. Csak utána nyisd le a megoldást.
1. A program lefagy
Az Összes kiemelése gomb megnyomása után a MiniWord nem válaszol semmire, amikor a keresőmező üres. Végtelen ciklus. Üres keresőszövegnél az Ok és javítás
IndexOf mindig az aktuális pozíciót adja vissza, a hely + 0 pedig sosem lép előre, ezért a while sosem ér véget. Az üres szöveg ellenőrzése ezért kötelező. Ha a program lefagyott, a Visual Studióban a Shift+F5 (Stop) paranccsal állíthatod le.
2. A ciklus nem lép tovább
while (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.SelectionBackColor = Color.Yellow;
darab = darab + 1;
}Ok és javítás
Végtelen ciklus: a hely értéke a ciklusban sosem változik, ezért a feltétel mindig igaz marad. A következő találat helyét minden körben ki kell számolni: hely = szoveg.IndexOf(keresett, hely + keresett.Length, ...);
3. Nem kapok találatot
if (hely > 0)
{
rtbDokumentum.Select(hely, keresett.Length);
}Ok és javítás
Rossz működés: a > 0 feltétel a dokumentum legelején lévő találatot (ahol a hely értéke 0) kihagyja. Javítás: hely >= 0, mert a -1 jelenti a találat hiányát.
4. Nem látszik a kijelölés
A Keresés gombra kattintasz, de a találat nincs kijelölve a szövegben. A gomb átvette a fókuszt, és a RichTextBox elrejti a kijelölést. Állítsd a Ok és javítás
HideSelection tulajdonságot False-ra, és hívd meg a rtbDokumentum.Focus() metódust a kijelölés után.
5. Maradnak a régi sárga szavak
Új szót keresel, de a régi találatok továbbra is sárgák. A kiemelések a dokumentum formázásának részei, nem tűnnek el maguktól. A keresés elején hívd meg a Ok és javítás
TorolKiemeleseket() metódust.
Mini projekt: a MiniWord keres
Építsd be a keresősávot a MiniWordbe, a leckében látott három metódussal (btnKeres_Click, btnOsszes_Click, TorolKiemeleseket). Tesztelj:
- Írj be egy többsoros szöveget, amelyben egy szó többször szerepel.
- Keress rá a Keresés gombbal: az első találat kijelölődik.
- Nyomd meg az Összes kiemelése gombot: minden előfordulás sárga lesz, és az üzenet megmutatja a számukat.
- Próbáld ki üres kereséssel és olyan szóval, amely nincs a szövegben.
- Mentés előtt töröld a kiemeléseket, hogy a mentett dokumentumban ne maradjon sárga háttér.
Mit tegyél ide: a kész MiniWord kereséssel: a keresőmezőben egy szó, a dokumentumban a szó összes előfordulása sárgával kiemelve.Javasolt fájlnév: winforms-2-8-miniword-keres.webp · Alt szöveg: A kész MiniWord keresősávja és a kiemelt találatok
Önálló gyakorlófeladatok
Először készíts saját megoldást. A lenyitható rész csak ellenőrzéshez van.
1. Kis- és nagybetű megkülönböztetése
Tegyél az ablakra egy A chkNagybetu nevű CheckBoxot Kis- és nagybetű megkülönböztetése felirattal. Ha be van jelölve, a keresés tegyen különbséget a kis- és a nagybetű között.Egy lehetséges megoldás
StringComparison mod = StringComparison.OrdinalIgnoreCase;
if (chkNagybetu.Checked)
{
mod = StringComparison.Ordinal;
}
int hely = szoveg.IndexOf(keresett, 0, mod);mod változó tárolja az összehasonlítás módját, és ezt adjuk át az IndexOf-nak.
2. Következő találat
Készíts egy Az üres keresőszöveg ellenőrzését ide is tedd be, ahogy a leckében láttad.btnKovetkezo gombot, amely a kijelölés után következő találatra ugrik. Ha nincs több, kezdje elölről.Egy lehetséges megoldás
string keresett = txtKeres.Text;
int kezdet = rtbDokumentum.SelectionStart + rtbDokumentum.SelectionLength;
int hely = rtbDokumentum.Text.IndexOf(keresett, kezdet, StringComparison.OrdinalIgnoreCase);
if (hely < 0)
{
hely = rtbDokumentum.Text.IndexOf(keresett, 0, StringComparison.OrdinalIgnoreCase);
}
if (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.Focus();
}
3. Enterre keressen
Szeretnéd, ha az Enter lenyomására is elindulna a keresés. Hogyan oldanád meg a legegyszerűbben? Jelöld ki az ablakot (a Form üres részét), és a Properties ablakban állítsd az Egy lehetséges megoldás
AcceptButton tulajdonságát btnKeres-re. Ekkor az Enter billentyű úgy működik, mintha a Keresés gombra kattintottál volna. A billentyűesemények részletes kezelését később, az 5. fejezetben tanuljuk.
Gyakorlótár: 6 további feladat
Három szinten gyakorolhatsz: alap, közepes és kihívás. A feladatokhoz egy rtbDokumentum RichTextBox (a HideSelection tulajdonsága False, hogy a kijelölés a fókusz elvesztése után is látsszon), egy txtKeres beviteli mező és egy gomb kell. Csak a próbálkozás után nyisd le a megoldást.
Alap szint
1. Az első találat kijelölése
A Az btnKeres gomb keresse meg a beírt szöveg első előfordulását, és jelölje ki a dokumentumban.Megoldás megnyitása
IndexOf a keresett szöveg első helyét adja (-1, ha nincs). A Select(hely, hossz) kijelöli a szövegrészt.private void btnKeres_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
int hely = rtbDokumentum.Text.IndexOf(keresett);
if (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.Focus();
}
}
2. Nincs találat
Ha a szöveg nem szerepel a dokumentumban, vagy a keresőmező üres, a program írjon ki érthető üzenetet. Az üres keresőszöveget előre ellenőrizzük: az Megoldás megnyitása
IndexOf("") mindig 0-t adna. A -1 érték azt jelzi, hogy a szöveg nincs meg.private void btnKeres_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
if (keresett.Length == 0)
{
MessageBox.Show("Írd be, mit keressek!");
return;
}
int hely = rtbDokumentum.Text.IndexOf(keresett);
if (hely < 0)
{
MessageBox.Show("A szöveg nem található.");
return;
}
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.Focus();
}
Közepes szint
3. Kis- és nagybetű figyelmen kívül hagyása
A keresés ne tegyen különbséget a kis- és nagybetű között (alma megtalálja az Alma szót is). Az Megoldás megnyitása
IndexOf második paramétere a keresés módja: a StringComparison.OrdinalIgnoreCase a kis- és nagybetűt nem különbözteti meg.int hely = rtbDokumentum.Text.IndexOf(keresett, StringComparison.OrdinalIgnoreCase);
4. Az összes találat kiemelése
A gomb emelje ki sárga háttérrel a keresett szöveg összes előfordulását, és a A lblTalalat mutassa a számukat.Megoldás megnyitása
while ciklus addig fut, amíg van találat. Minden körben a keresést az előző találat vége utáni helytől folytatjuk, különben ugyanazt találná újra. Az üres keresőszöveg végtelen ciklust okozna, ezért előbb ellenőrizzük.private void btnOsszes_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
if (keresett.Length == 0)
{
return;
}
string szoveg = rtbDokumentum.Text;
int darab = 0;
int hely = szoveg.IndexOf(keresett, 0, StringComparison.OrdinalIgnoreCase);
while (hely >= 0)
{
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.SelectionBackColor = Color.Yellow;
darab = darab + 1;
hely = szoveg.IndexOf(keresett, hely + keresett.Length, StringComparison.OrdinalIgnoreCase);
}
rtbDokumentum.Select(0, 0);
lblTalalat.Text = $"Találatok száma: {darab}";
}
Kihívás szint
5. Következő találat
A Az utolsó találat helyét mezőben tároljuk, hogy a gombnyomások között is megmaradjon. A keresés mindig az utolsó találat vége után folytatódik. Ha nincs több, a mezőt visszaállítjuk, és elölről kezdjük.btnKovetkezo gomb minden megnyomásra a következő előfordulást jelölje ki. Ha elfogytak, a program jelezze, és kezdje elölről.Megoldás megnyitása
private int kovetkezoHely = 0;
private void btnKovetkezo_Click(object sender, EventArgs e)
{
string keresett = txtKeres.Text;
if (keresett.Length == 0)
{
return;
}
int hely = rtbDokumentum.Text.IndexOf(keresett, kovetkezoHely, StringComparison.OrdinalIgnoreCase);
if (hely < 0)
{
MessageBox.Show("Nincs több találat, a keresés elölről indul.");
kovetkezoHely = 0;
return;
}
rtbDokumentum.Select(hely, keresett.Length);
rtbDokumentum.Focus();
kovetkezoHely = hely + keresett.Length;
}
6. Kiemelések törlése
A A háttérszín a dokumentum formázása, ezért az egész szöveget kijelölve vissza kell állítani a szövegdoboz alapszínére. A kiemelés mentéskor a fájlba is bekerülne, ezért érdemes a mentés előtt is meghívni.btnTorolKiemel gomb szüntesse meg az összes sárga kiemelést, és a találatok számát jelző felirat is ürüljön.Megoldás megnyitása
private void TorolKiemeleseket()
{
rtbDokumentum.SelectAll();
rtbDokumentum.SelectionBackColor = rtbDokumentum.BackColor;
rtbDokumentum.Select(0, 0);
}
private void btnTorolKiemel_Click(object sender, EventArgs e)
{
TorolKiemeleseket();
lblTalalat.Text = "";
}
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Mert a RichTextBoxnak egyszerre csak egy kijelölése lehet. A többi találatot a háttérszínük megváltoztatásával tesszük láthatóvá. Ismétli a kódot, amíg a feltétel igaz. Mert üres szövegnél a Hogy a következő keresés a találat vége után induljon, és ne ugyanazt találja újra meg. Mert a háttérszín a dokumentum formázásának része, így az RTF fájlba is belekerül.1. Mit ad vissza az IndexOf, ha nincs találat?
-1-et.2. Miért kiemelés az „összes találat kijelölése”?
3. Mire való a while ciklus?
4. Miért kell ellenőrizni az üres keresőszöveget?
hely sosem lép előre, ezért a ciklus végtelen lenne, és a program lefagyna.5. Miért haladunk a hely + keresett.Length pozícióra?
6. Miért kell törölni a kiemeléseket mentés előtt?
Mit tudsz már?
- Az IndexOf segítségével megtalálod a szöveg helyét.
- A Select() metódussal kijelölöd a találatot.
- A while ciklussal végigmész az összes találaton.
- A SelectionBackColor tulajdonsággal kiemeled az összes előfordulást.
- Kezeled az üres keresőszöveget és a kiemelések törlését.
Következő lecke: névmező, felugró ablak és About
A keresés kész. A következő leckében a MiniWord egy névmezőt és egy About ablakot kap.




