© 2013 All rights reserved.
0

C++ & WxWidgets – zpracování událostí

Zpracování událostí jsou velmi důležité operace, které jsou využívané téměř u všech programů. Ve wxWidgets máte dvě základní možnosti, které si vysvětlíme.

Článek se věnuje zpracování událostí v knihovně wxWidgets verze 2.x, ve starší verzi 1.x je zpracování událostí řešeno odlišně(pomocí callback funkcí nebo virtuálních funkcí).

Událost

wxwidgets code

Událost je libovolná operace, která musí být obsloužena. Tato operace vyvolává událost.
V knihovně wxWidgets budeme hovořit především o událostech vyvolaných uživateli v uživatelském rozhraní programu.

Události (a zprávy) jsou vlastně základním stavebním kamenem, pomocí nichž komunikuje uživatelské rozhraní programu s operačním systémem nebo naopak.

Událost si tedy můžete představit jako obslužnou rutinu, která je vyvolána například při kliknutí na tlačítko, které musí být programem obslouženo.

Dalo by se říct, že veškeré operace vašeho programu jsou důsledkem vyvolání libovolných událostí a zpracováním jejich obslužných rutin.

Události ve wxWidgets

Ve wxWidgets máte dvě možnosti jak mapovat události a to buď staticky pomocí Event Tables nebo dynamicky pomocí funkce wxEvtHandler::Connect, výběr záleží pouze na vás.

Každý z těchto dvou způsobů má určité výhody i nevýhody.

Mapované události, ať pomocí Connect nebo tabulky událostí, přebírají automaticky jeden jediný parametr – objekt wxEvent, který je jim automaticky předán a návratová hodnota je void.

V předané proměnné typu wxEvent jsou potom informace o vyvolané události, ke kterým můžeme přistupovat, např:

Pokud chcete událost přeskočit a její obslužnou rutinu provést jinde, můžete handler opustit metodou wxEvent::Skip:

Event Table

První zmíněnou možností je mapování událostí staticky. K tomuto postupu nabízí wxWidgets deklaraci tabulky událostí odvozenou od wxEvtHandler.

Tabulka událostí se skládá ze dvou částí – deklarace a implementace.

Deklaraci tabulky provedete v deklaraci třídy a to velmi jednoduše zavoláním makra DECLARE_EVENT_TABLE:

Pokud je tabulka deklarována, můžeme ji do naší třídy implementovat. Implementace začíná a končí makry BEGIN_EVENT_TABLE() a END_EVENT_TABLE()

Makro pro začátek tabulky obsahuje dva vstupní parametry a to třída, ve které je tabulka deklarovaná a jméno rodiče, od kterého je odvozena (wxFrame, wxDialog, …).

Prázdná tabulka může vypadat například takto:

Do tabulky můžeme nyní přidávat makra událostí dle naší potřeby. Maker pro mapování existuje celá spousta:

Makra pro mapování formulářových prvků (parametrem je vždy identifikátor a název obslužné funkce):

  • EVT_BUTTON(id, func)
  • EVT_CHECKBOX(id, func)
  • EVT_CHOICE(id, func)
  • EVT_COMBOBOX(id, func)
  • Apod.

Makra pro mapování událostí myši (vstupní parametr je pouze název obslužné funkce):

  • EVT_LEFT_DOWN(func)
  • EVT_LEFT_UP(func)
  • EVT_LEFT_DCLICK(func)
  • Apod.

Podrobný seznam a popis všech dostupných maker pro mapování událostí je v dokumentaci knihovny.

Pro názornou ukázku si můžeme vytvořit tabulku událostí, která bude mapovat události pro dvě tlačítka (wxButton), které budou volat stejnou obslužnou funkci.

Události jsou mapovány dle identifikátorů prvků.

Pokud máme více stejných elementů, které chceme obsloužit stejnou funkcí a máme přehled nad hodnotami identifikátorů, které můžeme například sami definovat:

Pak nemusíme mapovat každou událost samostatně, ale můžeme mapovat události pro určitý rozsah (RANGE) například pomocí EVT_COMMAND_RANGE (u menu existuje ekvivalent EVT_MENU_RANGE apod.):

První dva parametry určují pouze rozsah identifikátorů, které chceme mapovat a mohou být zadány jako Integer hodnota. Třetí parametr určuje událost a poslední parametr obslužnou funkci.

Ještě jednou zmíním, že maker pro mapování událostí existuje celá spousta. Jejich seznam je uveden v dokumentaci.

wxEvtHandler::Connect

Použití tabulky událostí je vcelku jednoduché, ovšem nese sebou omezení statického mapování, to znamená že mapované události není tímto způsobem možné při běhu programu měnit nebo teprve při běhu programu mapovat.

Na rozdíl od tabulky událostí můžeme použít funkci wxEvtHandler::Connect() pro dynamické mapování událostí.

Pokud se podíváte do dokumentace, pak vidíte, že funkce Connect má spoustu parametrů a máme několik možností pro volání funkce.

 

V prvním případě zadáváme dva identifikátory, které symbolizují počáteční a koncovou hodnotu pro určitý rozsah elementů podobně jako bylo uvedeno u EVT_COMMAND_RANGE v tabulce událostí:

Ukázka kódu:

Ve druhém případě mapujeme událost pouze na jeden identifikátor, který bude událost vyvolávat:

Ukázka kódu:

Ve třetím případě mapujeme událost přímo k objektu elementu a identifikátor nezadáváme:

Ukázka kódu:

Další důležité parametry, které funkce Connect obsahuje jsou:

eventType (wxEventType) – typ události, která vyvolá obslužnou rutinu. V tabulce událostí byly symbolizovány přímo makrem, které se volalo.

function (wxObjectEventFunction) – název obslužné funkce, který se při vyvolání správného eventType provede.

wxEvtHandler::Disconnect

Aby byl tento způsob mapování pomocí Connect opravdu dynamický, musí samozřejmě existovat i možnost událost odebrat. Pro tuto volbu existuje v wxEvtHandler funkce Disconnect.

Funkce má stejné parametry jako Connect, jenom s tím rozdílem, že namísto identifikátoru elementu je možnost zadat hodnotu wxID_ANY.

Použití je ale stejné jako v případě Connect:

Ukázkový příklad

wxwidgets example

Ve vytvořeném ukázkovém příkladě je vytvořené jednoduché rozhraní, obsahující 3 tlačítka a jedno textové pole.

Horní dvě tlačítka mají mapovány události pomocí Event Table staticky (soubor WxWidgetsEventsMain.cpp), které volají dvě metody:

  • OnConnect – funkce dynamicky mapuje událost na třetí tlačítko
  • OnDisconnect – funkce dynamicky odmapuje událost na třetí tlačítko

Pokud je událost na třetí tlačítko přimapována, bude po kliknutí psát do textového pole text „Click!“.

Příklad můžete stahovat zde: wxWidgetsEvents.zip

Závěrem

Jak je vidět, možností jak zpracovat události v knihovně wxWidgets jsou dostačující. V podstatě je rozhodnutí na programátorovi, zda bude chtít využívat statické nebo dynamické mapování.

Comments are closed for this page

About
Hi, i am programmer from the Czech Republic. I love web development (Ruby, Ruby on Rails, PHP, Nette) and iOS development (Objective-C, Cocoa).
To cooperate, here is my phone:
+420 608 836