Myš a klávesnice
Nejzajímavější jsou události MouseDown a KeyDown. Z objektu e, který je parametrem obslužné metody MouseDown a KeyDown, lze zjistit, které tlačítko myši bylo stisknuto a pozice myši, a jaká klávesa na klávesnici byla stisknuta.
MouseDown e.button výčet Mouse.Buttons, určuje, které tlačítko stisknuto e.x, e.y int, souřadnice myši v okamžiku stisku, vztahují se k souřadnému systému objektu, co událost vyvolal (oknoprogramu) KeyDown e.control, e.alt, e.shift bool, určuje, zda stisknut Ctrl, Alt, Shift e.keycode výčet Keys, určuje stisknutou klávesu
Př. program, který počítá stisky levého a pravého tlačítka, musí fungovat nad ovládacími prvky i mimo.
private void všechnyprvky_mousedown(object sender, MouseEventArgs e) // Zvětši počitadlo levého tlačítka if (e.button == MouseButtons.Left) int kolikrát = Convert.ToInt32(poleLevéTlačítko.Text); kolikrát++; polelevétlačítko.text = kolikrát.tostring(); // Zvětši počitadlo pravého tlačítka if (e.button == MouseButtons.Right) int kolikrát = Convert.ToInt32(polePravéTlačítko.Text); kolikrát++; polepravétlačítko.text = kolikrát.tostring();
Př. Test myši a klávesnice dole label jménem info private void oknoprogramu_mousedown(object sender, MouseEventArgs e) // Zjištění tlačítka, které bylo stisknuto string jaké; switch (e.button) case MouseButtons.Left: jaké = "Levé"; break; case MouseButtons.Middle: jaké = "Prostřední"; break; case MouseButtons.Right: jaké = "Pravé"; break; default: // Pokud nic z předchozího nenastane jaké = "Neznámé"; break; // Zjištění souřadnic int myšx = e.x; int myšy = e.y; // Zobrazení zprávy info.text = jaké + " tlačítko stisknuto na souřadnicích [" + myšx.tostring() + ";" + myšy.tostring() + "]"; private void oknoprogramu_keydown(object sender, KeyEventArgs e) // Test modifikačních kláves string modif = null; if (e.control) modif += "Ctrl+"; if (e.alt) modif += "Alt+"; if (e.shift) modif += "Shift+"; // Modifikační klávesy podruhé do zprávy nepřidávat string klávesa; if (e.keycode == Keys.ControlKey e.keycode == Keys.Menu e.keycode == Keys.ShiftKey) klávesa = null; else klávesa = e.keycode.tostring(); // Zobrazení zprávy info.text = "Stisknuta klávesa " + modif + klávesa;
Př. program, který náhodně kreslí na sekundu modré kuličky a píše, kolik kuliček bylo zobrazeno a kolik zasaženo myší. Paint vykreslí kuličku v barvě uložené v příslušné členské proměnné. Tick vygeneruje nové souřadnice, nastaví se modrá barva kuličky, překreslí se panel a zvedne počitadlo kuliček MouseDown vyhodnotí se, zda stisknuta myš na kuličce nebo mimo, pokud zásah, tak obarvení kuličky, zvětší počitadlo zásahů
Detekce zásahu vzdálenost od středu kuličky k místu klepnutí musí být menší nebo rovna poloměru kuličky. Vzdálenost klepnutí od středu kuličky vypočítáme pomocí 2 2 Pythágorovy věty. ( x) ( y) K x d SK y S x y
using System; using System.Drawing; using System.Windows.Forms; namespace Trefuj_kuličky public partial class oknoprogramu : Form Random náhoda = new Random(); // Souřadnice, poloměr a aktuální barva kuličky: int x, y; int poloměr = 5; Color barva = Color.Transparent; // na začátku průhledná // Možné barvy kuličky Color barvanezasažené = Color.CornflowerBlue; Color barvazasažené = Color.Tomato; public oknoprogramu() InitializeComponent(); private void časovač_tick(object sender, EventArgs e) // Stanovím meze, ve kterých se může nacházet střed // kuličky tak, aby kulička byla celá uvnitř int minx = poloměr; int maxx = panel.width - poloměr - 1; int miny = poloměr; int maxy = panel.height - poloměr - 1; // Připravím novou kuličku x = náhoda.next(minx, maxx + 1); y = náhoda.next(miny, maxy + 1); barva = barvanezasažené; panel.refresh(); Brush štětec = new SolidBrush(barva); kp.fillellipse(štětec, xlh, ylh, šířka, výška); private void panel_mousedown(object sender, MouseEventArgs e) // Pokud byla poslední kulička již zasažena, ignoruji myš if (barva!= barvanezasažené) return; // Vyhodnotím, zda došlo k zásahu int rozdílx = e.x - x; int rozdíly = e.y - y; double vzdálenostodstředu = Math.Sqrt(rozdílX*rozdílX + rozdíly*rozdíly); bool zásah = vzdálenostodstředu <= poloměr; if (zásah) // Pokud ano,... // přebarvím kuličku... barva = barvazasažené; panel.refresh(); // a aktualizuji počitadlo zásahů (zvětším o 1) int početzásahů = Convert.ToInt32(poleZásahů.Text); početzásahů++; polezásahů.text = početzásahů.tostring(); // Aktualizuji počitadlo kuliček (zvětším o 1) int početkuliček = Convert.ToInt32(poleKuliček.Text); početkuliček++; polekuliček.text = početkuliček.tostring(); private void panel_paint(object sender, PaintEventArgs e) Graphics kp = e.graphics; // Nakreslím kuličku se středem v bodě [x, y] a barvou barva int xlh = x - poloměr; int ylh = y - poloměr; int šířka = 2 * poloměr; int výška = šířka; Brush štětec = new SolidBrush(barva);
Konzumace kláves Při vyhodnocování stisknutých kláves je problém, že některé ovládací prvky převezmou klávesy a zpracují je samy a na okno programu už nedojde řada. Např. textová pole, zaškrtávátka apod. Př. program, který vypisuje stisknuté klávesy a navíc nastavuje zaškrtávátko, je-li stisknuto F1 až F12. private void oknoprogramu_keydown(object sender, KeyEventArgs e) Keys klávesa = e.keycode; info.text = "Stisknuta klávesa " + klávesa.tostring(); políčkofunkčníklávesa.checked = klávesa >= Keys.F1 && klávesa <= Keys.F12; Program moc nefunguje, protože zaškrtávátko všechno konzumuje.
Opravit lze nastavením vlastnosti KeyPreview okna na true, čímž docílíme, že okno dostane stisknuté klávesy dříve než prvek. Vyzkoušíme Ovšem stále nefungují klávesy jako šipky, Tab, mezerník apod.
Šipky a tabulátor mají v programu navigační funkci, takže jsou zpracovány jinak, než předáním ovládacímu prvku. Mezerník program pozná, ale zároveň ho zpracovává i zaškrtávací políčko, takže to mylně pak vypadá, že jde o funkční klávesu. Zaškrtávátko (příp. všechny prvky, je-li jich v programu víc) prohlásí, že chtějí všechny klávesy brát jako vstupní a nikoliv jako navigační. Mezerník se zpracuje v události PreviewKeyDown a označí se jako zpracovaný, takže dále se jím již nikdo nezabývá. Jak se toto řeší, ukazuje následující výpis.
private void oknoprogramu_keydown(object sender, KeyEventArgs e) Keys klávesa = e.keycode; info.text = "Stisknuta klávesa " + klávesa.tostring(); políčkofunkčníklávesa.checked = klávesa >= Keys.F1 && klávesa <= Keys.F12; ; // Událost se označí jako zpracovaná. Stisk se tak // již nepošle zaškrtávacímu políčku. e.handled = true; private void políčkofunkčníklávesa_previewkeydown(object sender, PreviewKeyDownEventArgs e) // Políčko (nepodmíněně) prohlásí všechny klávesy // jako své vstupní klávesy, čímž se zamezí jejich // použití jako kláves navigačních. e.isinputkey = true;
Parametr Sender předává odkaz na prvek, který událost vyvolal využívá se hlavně tehdy, když jedna metoda obsluhuje události více objektů Př. starý známý barevný prstenec private void tlačítka_click(object sender, EventArgs e) Button stisknutétlačítko = (Button)sender; barva = stisknutétlačítko.backcolor; panel.refresh();
Př. program s devíti tlačítky, která se po stisknutí ztrácejí, poslední zároveň ukončí program, všechna tlačítka musí obsluhovat jediná společná metoda
Př. vyrobte program, který umožní tahat čtverec myší Tip: obsluhujte MouseDown, MouseUp a MouseMove, pracujte s e.x a e.y
using System; using System.Drawing; using System.Windows.Forms; namespace Tažení_myší public partial class oknoprogramu : Form // Parametry čtverce int xleváčtverce, yhorníčtverce; int velikostčtverce = 50; // Pozice myši vůči levému hornímu rohu čtverce int xposunmyši, yposunmyši; // Jestli probíhá tažení bool tažení = false; public oknoprogramu() InitializeComponent(); private void oknoprogramu_load(object sender, EventArgs e) xleváčtverce = (ClientSize.Width - velikostčtverce) / 2; yhorníčtverce = (ClientSize.Height - velikostčtverce) / 2; private void oknoprogramu_paint(object sender, PaintEventArgs e) Graphics kp = e.graphics; kp.fillrectangle(brushes.lightcoral, xleváčtverce, yhorníčtverce, velikostčtverce, velikostčtverce); private void oknoprogramu_mousedown(object sender, MouseEventArgs e) // Pozice myši vůči oknu int xmyši = e.x; int ymyši = e.y; // Je myš stisknuta nad čtvercem? if (xmyši >= xleváčtverce && xmyši <= xpraváčtverce && ymyši >= yhorníčtverce && ymyši <= ydolníčtverce) tažení = true; // Zaznamenej, jak je myš daleko od rohu čtverce xposunmyši = xmyši - xleváčtverce; yposunmyši = ymyši - yhorníčtverce; private void oknoprogramu_mouseup(object sender, MouseEventArgs e) tažení = false; private void oknoprogramu_mousemove(object sender, MouseEventArgs e) if (tažení) // Posuň čtverec za myší xleváčtverce = e.x - xposunmyši; yhorníčtverce = e.y - yposunmyši; Refresh(); // int xpraváčtverce = xleváčtverce + velikostčtverce - 1; int ydolníčtverce = yhorníčtverce + velikostčtverce - 1;
Př. program, který pomocí šipek nahoru a dolů emuluje funkci číselníku Př. program Půlkalkulačka, který do textového pole sestaví zadané číslo pomocí kláves. Všechny klávesy musí obsluhovat jedna metoda.