Grafikus C# – Windows Forms tanfolyam › 5.4 lecke Windows Forms · 5.4 lecke · billentyűzet A billentyűzet a második legfontosabb beviteli eszköz: gépelés, nyilak, funkcióbillentyűk, gyorsbillentyűk (KeyDown, KeyPress, KeyUp és 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.
A lecke végére
- megkülönbözteted a
KeyDown,KeyPressésKeyUpeseményt, és tudod a sorrendjüket; - tudod, mely billentyűk nem váltanak ki
KeyPresseseményt; - a
KeyPreviewés aProcessCmdKeysegí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.
A három billentyűesemény
| Esemény | Mikor fut? | Mit mond? | Mire való? |
|---|---|---|---|
KeyDown | Egy 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. |
KeyPress | Egy karaktert adó billentyűt lenyomnak. | Melyik karakter (e.KeyChar). | Beírt szöveg szűrése és módosítása. |
KeyUp | A billentyűt felengedik. | Melyik fizikai billentyű. | A „felengedés” érzékelése (játék, hosszú nyomás vége). |
KeyDown → KeyPress → KeyUp. Ha a billentyűt nyomva tartod, a KeyDown (és KeyPress) ismétlődik, a KeyUp csak egyszer, a végén.F1–F12), a Ctrl, Shift, Alt billentyűkre és a legtöbb Ctrl-kombinációra nem fut le.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).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:
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:
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
}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.Keys értékben. A kombinációt a | (bitenkénti vagy) operátor építi fel: Keys.Control | Keys.S a Ctrl+S.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:
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.& 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.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.// 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öz | Mikor 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. |
ProcessCmdKey | Globális billentyűk menü nélkül (F5, Esc, nyilak). | Kódot kell írni, és ügyelni kell a return base sorra. |
KeyPreview + KeyDown | Egyszerű, ablak szintű billentyű-feldolgozás. | A nyilak, Tab, Enter nem mindig érkeznek meg. |
AcceptButton / CancelButton | Az 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:
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
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:
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.
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 A Windows a nyilakat, a KeyDown kezelője reagál a betűkre, de a nyilakra nem, ha gomb van fókuszban.Ok és javítás
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 A billentyűeseményt a fókuszban lévő vezérlő kapja meg, nem az ablak. Állítsd a Form Form1_KeyDown kezelő megvan, de gépeléskor sosem hívódik meg.Ok és javítás
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ő A beillesztés nem a 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
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:
- Az ablakon: egy többsoros
txtJegyzet, egytxtNevés egytxtKormező,lblUzenet,lblSzamlalo,lblCaps(a Caps Lock jelzése), és egyMenuStripFájl → Mentés menüponttal (miMentes). Ctrl+Sgyorsbillentyű amiMentesmenüponthoz (ShortcutKeys, a szövegben mnemonikus&Mentés). A mentés egyelőre csak üzenetet ír (Mentve: 21:05:30).F5: a kurzor helyére beszúrja az aktuális dátumot és időt (ProcessCmdKey).Ctrl+Shift+U: a kijelölt szöveget nagybetűssé alakítja.Esc: megszünteti a kijelölést.- A
txtKormező csak számjegyet fogad (KeyPress), legfeljebb 3 karaktert, és aValidatingeseményben ellenőrzi, hogy 1 és 120 közötti szám-e. - A
txtNevéstxtKormezőben azEntera következő mezőre lép (SelectNextControl). - A
lblCapsmutassa (Caps Lock be van kapcsolva), ha a Caps Lock aktív (KeyUpésActivated). - A
lblSzamlaloa jegyzet karaktereit mutassa (TextChanged). - 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).
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;
}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 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
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.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 A számjegy beírása után a 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
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.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 Az aktuálisan lenyomott billentyűt egy mezőben (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
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.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 A 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
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).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 A Form 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
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 A címke szövegében a Alt-betűs elérést. Mire kell vigyázni?Megoldás megnyitása
& 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 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
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.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? A várt sorozatot egy Megoldás megnyitása
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.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 A lenyomás idejét a KeyUp eseménynél. Hogyan szűröd ki az ismétlődő KeyDown eseményeket?Megoldás megnyitása
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.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. A A nyilakra, az A Form tulajdonsága: ha igaz, az ablak előbb megkapja a billentyűeseményeket, mint a rajta lévő vezérlők. Ha globális gyorsbillentyűt ( A A beillesztett szöveg nem a 1. Mi a különbség a KeyDown és a KeyPress között?
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?
F-billentyűkre, a Ctrl, Shift, Alt billentyűkre és a legtöbb Ctrl-kombinációra.3. Mi a KeyPreview?
4. Mikor kell a ProcessCmdKey?
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?
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?
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.



