Grafikus C# – Windows Forms tanfolyam › 5.4 lecke

Windows Forms · 5.4 lecke · billentyűzet

KeyDown, KeyPress, KeyUp és gyorsbillentyűk

A billentyűzet a második legfontosabb beviteli eszköz: gépelés, nyilak, funkcióbillentyűk, gyorsbillentyűk (Ctrl+S, F5). A Windows Forms három billentyűesemény ad (KeyDown, KeyPress, KeyUp), és mindháromnak más a szerepe. Ebben a leckében megtanulod, melyiket mikor használd, hogyan kezeld az ablak szintjén a billentyűket (KeyPreview, ProcessCmdKey), hogyan adhatsz menüpontoknak gyorsbillentyűt (ShortcutKeys, & jel), és hogyan kerüld el a leggyakoribb csapdákat, például azt, hogy a nyilak nem érkeznek meg az eseménykezelőbe.

  • kb. 110 perc
  • közepes szint
  • billentyűesemények
Anime stílusú fiú és lány egy C# programozási feladatot beszél meg

A lecke végére

  • megkülönbözteted a KeyDown, KeyPress és KeyUp eseményt, és tudod a sorrendjüket;
  • tudod, mely billentyűk nem váltanak ki KeyPress eseményt;
  • a KeyPreview és a ProcessCmdKey segítségével az ablak szintjén kezeled a billentyűket;
  • menüpontoknak gyorsbillentyűt adsz (ShortcutKeys), és mnemonikus billentyűket (&) használsz;
  • megvalósítod az Enter-navigációt és a Caps Lock jelzést;
  • felismered a gyakori hibákat (nem érkező nyilak, kettős működés, elfelejtett return base).

Mielőtt elkezded

Ehhez a leckéhez az 5.2 lecke (KeyEventArgs, KeyPressEventArgs, Handled) és az 1.7 lecke (MenuStrip) szükséges. Új projektben próbáld ki a példákat.

5.3 Egérműveletek →

A három billentyűesemény

EseményMikor fut?Mit mond?Mire való?
KeyDownEgy billentyűt lenyomnak (nyomva tartva ismétlődik).Melyik fizikai billentyű (e.KeyCode), módosítók.Vezérlőbillentyűk (nyilak, Enter, Esc, F5), kombinációk.
KeyPressEgy karaktert adó billentyűt lenyomnak.Melyik karakter (e.KeyChar).Beírt szöveg szűrése és módosítása.
KeyUpA billentyűt felengedik.Melyik fizikai billentyű.A „felengedés” érzékelése (játék, hosszú nyomás vége).
A sorrendEgy karakteres billentyűnél: KeyDown → KeyPress → KeyUp. Ha a billentyűt nyomva tartod, a KeyDown (és KeyPress) ismétlődik, a KeyUp csak egyszer, a végén.
A KeyPress szűkCsak karaktert adó billentyűkre fut. A nyilakra, a funkcióbillentyűkre (F1–F12), a Ctrl, Shift, Alt billentyűkre és a legtöbb Ctrl-kombinációra nem fut le.
KeyCode vagy KeyCharA KeyDown a billentyű helyét adja (az A és a ugyanaz), a KeyPress a karaktert (az A és a különbözik, és a billentyűzetkiosztás is számít).
SzabálySzövegszűréshez KeyPress, minden máshoz (gyorsbillentyű, nyíl, funkcióbillentyű) KeyDown.

Kísérlet: a három esemény egymás után

Tegyél az ablakra egy txtProba TextBoxot és egy lstNaplo ListBoxot:

Form1.csC#
private void txtProba_KeyDown(object sender, KeyEventArgs e)
{
Naplo("KeyDown: " + e.KeyCode);
}

private void txtProba_KeyPress(object sender, KeyPressEventArgs e)
{
Naplo("KeyPress: " + e.KeyChar);
}

private void txtProba_KeyUp(object sender, KeyEventArgs e)
{
Naplo("KeyUp: " + e.KeyCode);
}

private void Naplo(string szoveg)
{
lstNaplo.Items.Add(szoveg);
lstNaplo.TopIndex = lstNaplo.Items.Count - 1;
}

Jósolj!

A txtProba mezőben megnyomod a Shift + A billentyűt (nagy A), majd felengeded. Hány KeyDown, KeyPress és KeyUp sor kerül a naplóba, és mi lesz az értékük? Mi történik az F5 billentyűvel?

Jóslat ellenőrzése

A Shift lenyomása már egy KeyDown (ShiftKey), majd az A lenyomásakor KeyDown: A, KeyPress: A (nagybetű, mert Shift van lenyomva), és a felengedéskor két KeyUp (A és ShiftKey). A Shift önmagában nem ad KeyPress eseményt. Az F5 csak KeyDown és KeyUp eseményt ad, KeyPress nem fut, mert nem karakter. A pontos sorrendet a saját gépeden érdemes megnézni.

Ablak szintű kezelés: KeyPreview és ProcessCmdKey

Alapból a billentyűeseményt az a vezérlő kapja, amelyiknél a fókusz van (a kijelölt, aktív vezérlő). Ha az ablak egészére szeretnél gyorsbillentyűt (például Esc, F1), akkor két eszközöd van:

1. KeyPreview

Ha a Form KeyPreview tulajdonsága True, az ablak előbb megkapja a billentyűeseményt, mint a vezérlő, és a Form1_KeyDown (és KeyPress, KeyUp) lefut. Egyszerű, de a nyilakat, a Tab és az Enter billentyűt nem mindig kapja meg (ezeket a Windows navigációra használja, lásd a hibavadászatban).

2. ProcessCmdKey

A ProcessCmdKey az ablak egy felülírható metódusa, amely a parancsbillentyűket (nyilak, Tab, Enter, Esc, kombinációk, F-billentyűk) még azelőtt kapja meg, hogy a vezérlők feldolgoznák őket. Ez a megbízhatóbb mód a globális gyorsbillentyűkre:

Form1.csC#
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F5)
{
txtJegyzet.SelectedText = DateTime.Now.ToString("yyyy. MM. dd. HH:mm");
return true; // kezeltük: a billentyű nem megy tovább
}

if (keyData == (Keys.Control | Keys.Shift | Keys.U))
{
txtJegyzet.SelectedText = txtJegyzet.SelectedText.ToUpper();
return true;
}

if (keyData == Keys.Escape)
{
txtJegyzet.SelectionLength = 0; // a kijelölés megszüntetése
return true;
}

return base.ProcessCmdKey(ref msg, keyData); // minden más billentyű a megszokott módon megy tovább
}
overrideAz ablak (Form) ősosztályának metódusát felülírjuk a sajátunkkal. A protected override szerkezet fix, a paraméterek (ref Message msg, Keys keyData) is.
keyDataA megnyomott billentyű a módosítókkal együtt egyetlen Keys értékben. A kombinációt a | (bitenkénti vagy) operátor építi fel: Keys.Control | Keys.S a Ctrl+S.
return trueAzt jelenti: „ezt a billentyűt kezeltem, ne dolgozza fel más”. A visszatérési érték itt lényeges.
return base.ProcessCmdKey(...)Az összes többi billentyűt tovább kell adni az ősosztálynak. Ha ez a sor kimarad, az ablak elnyeli a billentyűket (például a Tab és a nyilak nem működnek).

Jósolj!

A ProcessCmdKey felülírásából kitörlöd a legalsó return base.ProcessCmdKey(...) sort, és helyette return false; áll. Működik-e még a Tab billentyű és a gépelés a szövegmezőkben?

Jóslat ellenőrzése

A gépelés működik (a karakterek nem parancsbillentyűk, ezért a ProcessCmdKey alapból nem kezeli őket), de a navigációs billentyűk (Tab, a nyilak a gombok közt, a menü gyorsbillentyűi, Alt-kombinációk) nem fognak működni, mert az ősosztály sosem kapja meg őket. A hibát nehéz észrevenni: a program „fura”, de nem omlik össze. Ezért a metódus végén mindig return base.ProcessCmdKey(ref msg, keyData); áll.

Gyorsbillentyűk menüpontokhoz és gombokhoz

A leggyakoribb gyorsbillentyűkhöz (Ctrl+S, Ctrl+O) nem kell kódot írnod a billentyűk figyeléséhez. A menüpontoknak beállítható a ShortcutKeys tulajdonság, amely a billentyűt is figyeli, és a menüben is megjeleníti:

ShortcutKeysA ToolStripMenuItem tulajdonsága a Properties ablakban: kiválasztod a módosítót (Ctrl, Shift, Alt) és a billentyűt. A menüpont Click eseménye fut le, és a menü mellett megjelenik a felirat (Ctrl+S). Kódot nem kell írnod.
ShowShortcutKeysIgaz értéknél a menüben látszik a gyorsbillentyű szövege.
Mnemonikus billentyű (&)A szövegben a & jel utáni betű aláhúzódik, és az Alt + az a betű aktiválja a vezérlőt: &Fájl → Fájl (Alt+F), &Mentés gomb → Alt+M.
Címke és mezőEgy Label szövegében a & jel azt a vezérlőt aktiválja, amely a tabulátorsorrendben utána következik (jellemzően a mellette lévő szövegmező): &Név: + txtNev.
Tervezőben és Form1.csC#
// A tervezőben: miMentes.ShortcutKeys = Ctrl+S; miMentes.Text = "&Mentés";
// A kezelő csak egyszer, a menüpont Click eseményén:
private void miMentes_Click(object sender, EventArgs e)
{
lblUzenet.Text = "Mentve: " + DateTime.Now.ToString("HH:mm:ss");
}

// A gomb mnemonikus billentyűje: btnTorol.Text = "&Törlés"; (Alt+T)
// Ha a feliratban magát az & jelet szeretnéd: "Ár && Mennyiség"
EszközMikor használd?Hátránya
ShortcutKeys (menüpont)Parancsokhoz, amelyek a menüben is szerepelnek (Ctrl+S, Ctrl+O).Csak menüponthoz kapcsolható; a menünek léteznie kell.
& mnemonikus billentyűGombok, menük és mezők Alt-betűs elérése.Csak Alt-kombináció, a felhasználónak ismernie kell.
ProcessCmdKeyGlobális billentyűk menü nélkül (F5, Esc, nyilak).Kódot kell írni, és ügyelni kell a return base sorra.
KeyPreview + KeyDownEgyszerű, ablak szintű billentyű-feldolgozás.A nyilak, Tab, Enter nem mindig érkeznek meg.
AcceptButton / CancelButtonAz Enter és az Esc egy gombot nyom meg (6.7 lecke).Csak két billentyű, egy-egy gombbal.

Jósolj!

A menüpontnak beállítod a Ctrl+S gyorsbillentyűt, és ugyanerre a kombinációra a Form1_KeyDown eseményben is írsz kódot (KeyPreview igaz). Hányszor fut le a „mentés” egy Ctrl+S lenyomására?

Jóslat ellenőrzése

Előfordulhat, hogy kétszer (a menüpont és a KeyDown kezelő is lefut), de a viselkedés a billentyűtől és a feldolgozás sorrendjétől függ. A tanulság: egy gyorsbillentyűt egy helyen kezelj. Ha menüpontod van hozzá, használd a ShortcutKeys tulajdonságot, és ne írj mellé külön billentyűkezelőt.

Gyakorlati minták

Enter-navigáció: Enterrel a következő mezőre

Űrlapokon kényelmes, ha az Enter a következő mezőre lép (mint a Tab). A KeyDown eseményben a SelectNextControl metódus a tabulátorsorrend szerinti következő vezérlőre teszi a fókuszt:

Form1.cs (a txtNev, txtEmail, txtTelefon mezők közös KeyDown kezelője)C#
private void Mezo_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.SuppressKeyPress = true; // a csengő hang és a sortörés elmarad

// SelectNextControl(honnan, előre, csak tabstop, beágyazva, körbe)
this.SelectNextControl((Control)sender, true, true, true, true);
}
}

Caps Lock jelzés

Form1.csC#
private void CapsJelzes()
{
lblCaps.Visible = Control.IsKeyLocked(Keys.CapsLock);
}

private void txtJelszo_KeyUp(object sender, KeyEventArgs e)
{
CapsJelzes();
}

private void Form1_Activated(object sender, EventArgs e)
{
CapsJelzes(); // az ablakra visszatérve is friss legyen
}

Nyilak a lenyomott billentyűvel (ismétlés)

Ha egy vezérlőt nyilakkal mozgatsz (játék, rajzolás), a nyomva tartott billentyű KeyDown eseménye ismétlődik. Ha ezt nem szeretnéd (például egy váltókapcsolónál, amely csak az első lenyomásra váltson), jegyezd meg, hogy a billentyű le van-e nyomva:

Form1.csC#
private bool szokozLenyomva = false;

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space && !szokozLenyomva)
{
szokozLenyomva = true;
lampa.Visible = !lampa.Visible; // csak a lenyomás pillanatában vált
}
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
szokozLenyomva = false;
}
}

Jósolj!

A váltókapcsoló kódjából törlöd a KeyUp kezelőt, de a szokozLenyomva jelző megmarad. Hányszor tudsz váltani a szóköz megnyomásával?

Jóslat ellenőrzése

Csak egyszer: az első lenyomás igazra állítja a jelzőt, és mivel a KeyUp nem állítja vissza hamisra, a további szóközök nem váltanak. A jelző mindig két oldalról kezelendő: a KeyDown bekapcsolja, a KeyUp kikapcsolja.

📷 Képernyőkép helye

Mit tegyél ide: a billentyűnapló: a txtProba mezőben beírt „Aa” után a lista KeyDown, KeyPress és KeyUp soraival.Javasolt fájlnév: winforms-5-4-naplo.webp · Alt szöveg: A KeyDown, KeyPress és KeyUp események naplója

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 nyilak nem érkeznek meg a KeyDown eseménybe

Az ablak KeyDown kezelője reagál a betűkre, de a nyilakra nem, ha gomb van fókuszban.

Ok és javítás

A Windows a nyilakat, a Tab és az Enter billentyűt navigációs billentyűnek tekinti: a gomb (vagy a panel) nem adja át a KeyDown eseménynek, hanem a fókuszt mozgatja. Megoldás: felülírt ProcessCmdKey (ahol a nyilak is megérkeznek), vagy egy vezérlő, amely a nyilakat bemenetként fogadja.

2. A KeyPress nem fut a gyorsbillentyűre

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 's') { } // a Ctrl+S nem ide érkezik
}
Hiba és javítás

A KeyPress a beírt karaktert adja, a Ctrl+S pedig vezérlőkarakter (nem a betű). A kombinációkhoz KeyDown, ProcessCmdKey vagy menüpont ShortcutKeys való.

3. Az Enter megnyomásakor csengő hang szól

if (e.KeyCode == Keys.Enter)
{
this.SelectNextControl((Control)sender, true, true, true, true);
}
Hiba és javítás

Az egysoros szövegmező az Enter billentyűre hangjelzést ad, ha az esemény nincs elnyelve. Add hozzá: e.SuppressKeyPress = true; (és e.Handled = true; is használható). Így nincs hang, és az Enter nem kerül a szövegmezőbe.

4. A Form KeyDown eseménye nem fut le

A Form1_KeyDown kezelő megvan, de gépeléskor sosem hívódik meg.

Ok és javítás

A billentyűeseményt a fókuszban lévő vezérlő kapja meg, nem az ablak. Állítsd a Form KeyPreview tulajdonságát True értékre, hogy az ablak előbb láthassa. A navigációs billentyűkhöz a ProcessCmdKey kell.

5. Elromlik a Tab és a menü gyorsbillentyűje

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F5) { /* ... */ return true; }
return false; // hiba!
}
Hiba és javítás

A többi billentyűt tovább kell adni: return base.ProcessCmdKey(ref msg, keyData);. A return false megtartja a gépelést, de a navigációs és menü-billentyűk nem jutnak el az ősosztályhoz, így a Tab és a gyorsbillentyűk nem működnek.

6. A beillesztett szöveg megkerüli a szűrőt

A számmező KeyPress szűrője nem engedi a betűket, de Ctrl+V beillesztésnél a betűs szöveg mégis bekerül.

Ok és javítás

A beillesztés nem a KeyPress eseményen megy át (nem karakterenként érkezik). A végső ellenőrzést a Validating eseményben (int.TryParse) vagy a TextChanged eseményben is el kell végezni: a billentyűszűrő csak kényelmi segítség, nem védelem.

Mini projekt: gyorsbillentyűs jegyzet

Készíts kis jegyzetprogramot, amelyet nagyrészt billentyűzettel lehet kezelni:

  1. Az ablakon: egy többsoros txtJegyzet, egy txtNev és egy txtKor mező, lblUzenet, lblSzamlalo, lblCaps (a Caps Lock jelzése), és egy MenuStrip Fájl → Mentés menüponttal (miMentes).
  2. Ctrl+S gyorsbillentyű a miMentes menüponthoz (ShortcutKeys, a szövegben mnemonikus &Mentés). A mentés egyelőre csak üzenetet ír (Mentve: 21:05:30).
  3. F5: a kurzor helyére beszúrja az aktuális dátumot és időt (ProcessCmdKey).
  4. Ctrl+Shift+U: a kijelölt szöveget nagybetűssé alakítja. Esc: megszünteti a kijelölést.
  5. A txtKor mező csak számjegyet fogad (KeyPress), legfeljebb 3 karaktert, és a Validating eseményben ellenőrzi, hogy 1 és 120 közötti szám-e.
  6. A txtNev és txtKor mezőben az Enter a következő mezőre lép (SelectNextControl).
  7. A lblCaps mutassa (Caps Lock be van kapcsolva), ha a Caps Lock aktív (KeyUp és Activated).
  8. A lblSzamlalo a jegyzet karaktereit mutassa (TextChanged).
  9. Teszteld: az összes kombinációt, a Tab működését, a Ctrl+V beillesztést a számmezőbe, a Caps Lock ki- és bekapcsolását.
Megoldás megnyitása (próbáld ki előbb önállóan!)

A gyorsbillentyűk egy helyen vannak kezelve: a Ctrl+S a menüponté (ShortcutKeys), a többi a ProcessCmdKey-é. A számmező két védelmet kap: a billentyűszűrőt (KeyPress) és a végső ellenőrzést (Validating).

Form1.csC#
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F5)
{
txtJegyzet.SelectedText = DateTime.Now.ToString("yyyy. MM. dd. HH:mm");
return true;
}

if (keyData == (Keys.Control | Keys.Shift | Keys.U))
{
txtJegyzet.SelectedText = txtJegyzet.SelectedText.ToUpper();
return true;
}

if (keyData == Keys.Escape && txtJegyzet.Focused)
{
txtJegyzet.SelectionLength = 0;
return true;
}

return base.ProcessCmdKey(ref msg, keyData);
}

private void miMentes_Click(object sender, EventArgs e)
{
lblUzenet.Text = "Mentve: " + DateTime.Now.ToString("HH:mm:ss");
}

private void txtKor_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

private void txtKor_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
int kor;

if (txtKor.Text.Length > 0 && (!int.TryParse(txtKor.Text, out kor) || kor < 1 || kor > 120))
{
lblUzenet.Text = "A kor 1 és 120 közötti szám legyen.";
e.Cancel = true;
}
}

private void Mezo_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
e.SuppressKeyPress = true;
this.SelectNextControl((Control)sender, true, true, true, true);
}
}

private void CapsJelzes()
{
lblCaps.Visible = Control.IsKeyLocked(Keys.CapsLock);
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
CapsJelzes();
}

private void Form1_Activated(object sender, EventArgs e)
{
CapsJelzes();
}

private void txtJegyzet_TextChanged(object sender, EventArgs e)
{
lblSzamlalo.Text = "Karakterek: " + txtJegyzet.TextLength;
}
📷 Képernyőkép helye

Mit tegyél ide: a kész program: a jegyzet, a név és a kor mező, a Caps Lock jelzés, az üzenet („Mentve: ...”) és a menü a Ctrl+S felirattal.Javasolt fájlnév: winforms-5-4-kesz.webp · Alt szöveg: A gyorsbillentyűs jegyzet 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. Csak betű a névmezőbe

A txtNev mező csak betűt (ékezeteseket is), szóközt, kötőjelet és vezérlőkaraktert engedjen be. Miért nem elég az a–z tartomány ellenőrzése?

Egy lehetséges megoldás

A char.IsLetter a magyar ékezetes betűket is felismeri (á, é, ő, ű), míg az a–z tartomány kizárná őket. A beillesztett szöveget a Validating eseményben érdemes ellenőrizni.

Form1.csC#
private void txtNev_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetter(e.KeyChar) || char.IsControl(e.KeyChar) || e.KeyChar == ' ' || e.KeyChar == '-')
{
return;
}

e.Handled = true;
}

2. Négyjegyű PIN-kód ugrással

Négy kis TextBox (txtP1–txtP4, MaxLength: 1) alkossa a PIN-kódot: számjegy beírása után a kurzor a következő mezőbe ugrik, a Backspace üres mezőben az előzőbe lép vissza.

Egy lehetséges megoldás

A számjegy beírása után a TextChanged eseményben lépünk a következőre (SelectNextControl). A Backspace üres mezőben a KeyDown eseményben az előző mezőre visz (SelectNextControl hátra, az előre paraméter false). A számjegyszűrés a KeyPress eseményben történik.

Form1.cs (a négy mező közös kezelői)C#
private void Pin_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true;
}
}

private void Pin_TextChanged(object sender, EventArgs e)
{
TextBox mezo = (TextBox)sender;

if (mezo.Text.Length == 1)
{
this.SelectNextControl(mezo, true, true, true, false);
}
}

private void Pin_KeyDown(object sender, KeyEventArgs e)
{
TextBox mezo = (TextBox)sender;

if (e.KeyCode == Keys.Back && mezo.Text.Length == 0)
{
this.SelectNextControl(mezo, false, true, true, false); // előző mező
}
}

3. Billentyűnapló ismétlés nélkül

Egy lstNaplo a lenyomott billentyűket naplózza, de a nyomva tartott billentyű ismétlődő eseményeit csak egyszer jegyezze fel. A felengedéskor írja ki: A felengedett billentyű: X.

Egy lehetséges megoldás

Az aktuálisan lenyomott billentyűt egy mezőben (Keys típus) tartjuk nyilván. A KeyDown csak akkor ír naplót, ha a billentyű más, mint a már lenyomott. A KeyUp törli a nyilvántartást.

Form1.csC#
private Keys lenyomott = Keys.None;

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == lenyomott)
{
return; // ismétlődő esemény: kihagyjuk
}

lenyomott = e.KeyCode;
lstNaplo.Items.Insert(0, "Lenyomva: " + e.KeyCode);
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
lenyomott = Keys.None;
lstNaplo.Items.Insert(0, "A felengedett billentyű: " + e.KeyCode);
}

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. Leütések számlálása

Egy txtSzoveg mezőnél a lblDb mutassa, hány karaktert ütöttek le összesen (a törlést is beleértve nem, csak a karaktereket). Melyik eseményt használod, és miért?

Megoldás megnyitása

A KeyPress eseményt: az csak karaktert adó billentyűre fut, a Backspace és a nyilak nem karakterek (a Backspace vezérlőkarakter, ezért ki kell szűrni a char.IsControl segítségével).

Form1.csC#
private int leutesek = 0;

private void txtSzoveg_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar))
{
leutesek = leutesek + 1;
lblDb.Text = "Leütések: " + leutesek;
}
}

2. Esc és Enter egy ablakban

Egy bejelentkező ablakban az Enter a Belépés, az Esc a Mégse gombot nyomja meg. Mit állítasz be a tervezőben kódírás nélkül?

Megoldás megnyitása

A Form AcceptButton tulajdonsága a Belépés gomb, a CancelButton tulajdonsága a Mégse gomb. Az Enter és az Esc ekkor a megfelelő gomb Click eseményét hívja. (Részletesen a 6.7 leckében.)

Közepes szint

3. Mnemonikus billentyűk az űrlapon

Egy űrlapon a Név és az E-mail mező címkéjéhez, valamint a Mentés és Törlés gombhoz adj Alt-betűs elérést. Mire kell vigyázni?

Megoldás megnyitása

A címke szövegében a & jel a betű elé kerül (&Név:), és a címke utáni tabulátorsorrendben következő vezérlő kapja a fókuszt, ezért a címke TabIndex értéke közvetlenül a mezőé előtt legyen. Az Alt-betűk ne ütközzenek egymással (két gombnak ne legyen ugyanaz): ilyenkor a második betűt válaszd (&Törlés és Mente&s). A UseMnemonic tulajdonságnak True kell lennie (ez az alapértelmezés).

4. Keresőmező Ctrl+F-fel

A Ctrl+F a txtKereso mezőre helyezi a fókuszt, és kijelöli a tartalmát. Hol kezeled, és miért nem elég a Form1_KeyDown?

Megoldás megnyitása

A ProcessCmdKey megbízhatóbb, mert akkor is lefut, ha egy olyan vezérlő van fókuszban, amely a billentyűt maga kezelné (például a RichTextBox a Ctrl-kombinációkat feldolgozhatja). Az Esc bónuszként a fókuszt a szövegmezőre adja vissza.

Form1.csC#
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.F))
{
txtKereso.Focus();
txtKereso.SelectAll();
return true;
}

if (keyData == Keys.Escape && txtKereso.Focused)
{
txtSzoveg.Focus();
return true;
}

return base.ProcessCmdKey(ref msg, keyData);
}

Kihívás szint

5. Billentyűsorozat felismerése

Ha a felhasználó a Fel, Fel, Le, Le, B, A billentyűsorozatot üti le (a híres játékos csalókód mintájára), jelenjen meg egy üzenet. Rossz billentyűnél a sorozat kezdődik elölről. Hogyan oldod meg?

Megoldás megnyitása

A várt sorozatot egy Keys tömb tárolja, egy mező megjegyzi, hányadiknál tartunk. Helyes billentyűnél lépünk előre, rossznál nullázunk (de ha a rossz billentyű a sorozat első eleme, onnan indulunk újra). A KeyPreview legyen igaz.

Form1.csC#
private readonly Keys[] sorozat = { Keys.Up, Keys.Up, Keys.Down, Keys.Down, Keys.B, Keys.A };
private int hely = 0;

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == sorozat[hely])
{
hely = hely + 1;

if (hely == sorozat.Length)
{
MessageBox.Show("Titkos mód bekapcsolva!");
hely = 0;
}
}
else
{
hely = keyData == sorozat[0] ? 1 : 0;
}

return base.ProcessCmdKey(ref msg, keyData);
}

6. Hosszan nyomott billentyű mérése

Mérd meg, mennyi ideig tartottad lenyomva a szóközt, és írd ki ezredmásodpercben a KeyUp eseménynél. Hogyan szűröd ki az ismétlődő KeyDown eseményeket?

Megoldás megnyitása

A lenyomás idejét a Stopwatch méri (System.Diagnostics). Az ismétlődést jelzővel szűrjük: csak az első KeyDown indítja a mérést, a KeyUp leállítja és kiírja az eredményt.

Form1.csC#
private System.Diagnostics.Stopwatch ora = new System.Diagnostics.Stopwatch();

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space && !ora.IsRunning)
{
ora.Restart();
}
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space && ora.IsRunning)
{
ora.Stop();
lblIdo.Text = "Lenyomva tartva: " + ora.ElapsedMilliseconds + " ms";
}
}

Gyors önellenőrzés

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

1. Mi a különbség a KeyDown és a KeyPress között?

A KeyDown a fizikai billentyűt adja (KeyCode), és minden billentyűre lefut. A KeyPress a beírt karaktert (KeyChar), és csak karaktert adó billentyűre fut.

2. Mire nem fut le a KeyPress?

A nyilakra, az F-billentyűkre, a Ctrl, Shift, Alt billentyűkre és a legtöbb Ctrl-kombinációra.

3. Mi a KeyPreview?

A Form tulajdonsága: ha igaz, az ablak előbb megkapja a billentyűeseményeket, mint a rajta lévő vezérlők.

4. Mikor kell a ProcessCmdKey?

Ha globális gyorsbillentyűt (F5, Esc, Ctrl-kombináció) vagy navigációs billentyűt (nyilak) kell kezelni a fókusztól függetlenül.

5. Mit kell a ProcessCmdKey végén visszaadni?

return base.ProcessCmdKey(ref msg, keyData);, hogy a kezeletlen billentyűk a megszokott módon mehessenek tovább. A kezelt billentyűnél return true.

6. Hogyan adsz menüpontnak gyorsbillentyűt?

A ShortcutKeys tulajdonsággal, kód nélkül. A & jel a szövegben Alt-betűs elérést ad.

7. Mi a baj a KeyPress szűrővel a beillesztésnél?

A beillesztett szöveg nem a KeyPress eseményen megy át, ezért a szűrést a Validating vagy TextChanged eseményben is el kell végezni.

Mit tudsz már?

  • Megkülönbözteted a három billentyűeseményt, és tudod a sorrendjüket.
  • Az ablak szintjén kezeled a billentyűket (KeyPreview, ProcessCmdKey).
  • Gyorsbillentyűket és mnemonikus billentyűket használsz (ShortcutKeys, &).
  • Megvalósítod az Enter-navigációt, a Caps Lock jelzést és az ismétlés szűrését.
  • Felismered a gyakori billentyűkezelési hibákat.

Következő lecke: TextChanged, ValueChanged és SelectedIndexChanged

A billentyűk után a vezérlők változás-eseményei következnek: mikor fut a TextChanged, és hogyan kerüld el a visszacsatolási hurkokat.