wxPython - události
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
Reklama

wxPython - událostiwxPython - události

 

wxPython - události

Google       Google       8. 11. 2008       25 595×

Události jsou nedílnou součástí každé GUI aplikace. Všechny GUI aplikace jsou jimi vlastně řízeny. Události jsou většinou vygenerované uživatelem. Jakmile zavoláme metodu MainLoop(), bude naše aplikace v nekonečné smyčce odchytávat události a zpracovávat je. Tato smyčka skončí společně s koncem programu.

Reklama
Reklama

První příklad

Než začneme se samotným příkladem, měli bychom si vysvětlit několik pojmů. Jak už bylo řečeno, program ve smyčce MainLoop() zachytává všechny události a předává je do rozvodny. Tam se zkontroluje, zda je pro danou událost registrován nějaký ovladač. Pokud je, zavolá se funkce/metoda svázaná s ovladačem.

V následujícím příkladě si popíšeme velmi jednoduchou věc - ukážeme si, jaká událost se vygeneruje, pohneme-li oknem.

Vždy když pohneme oknem, vygeneruje se událost typu wx.MoveEvent. Ovladač pro ni je wx.EVT_MOVE.

import wx

class MoveEvent(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(250, 180))

        wx.StaticText(self, -1, 'x:', (10,10))
        wx.StaticText(self, -1, 'y:', (10,30))
        self.st1 = wx.StaticText(self, -1, '', (30, 10))
        self.st2 = wx.StaticText(self, -1, '', (30, 30))

        self.Bind(wx.EVT_MOVE, self.OnMove)

        self.Centre()
        self.Show(True)

    def OnMove(self, event):
        x, y = event.GetPosition()
        self.st1.SetLabel(str(x))
        self.st2.SetLabel(str(y))


app = wx.App()
MoveEvent(None, -1, 'move event')
app.MainLoop()

V tomto příkladu vypisujeme do wx.StaticText aktuální pozici okna (ta se automaticky přepíše, pokud oknem pohneme).

self.Bind(wx.EVT_MOVE, self.OnMove)

Pomocí předcházejícího kusu kódu jsme svázali ovladač wx.EVT_MOVE s metodou self.OnMove.

def OnMove(self, event):
    x, y = event.GetPosition()

Jistě jste si všimli, že metoda OnMove() přijímá kromě parametru self ještě parametr event. V tomto případě je to instance třídy wx.MoveEvent. Pomocí této třídy můžete získat nějaké informace o události. Například aktuální pozici okna. Tu zjistíme zavoláním metody GetPosition().

Registrování událostí

Registrování událostí je ve wxPythonu poměrně jednoduchá záležitost. Skládá se ze dvou kroků:

  • Vytvořit metodu, která se zavolá, pokud se vygeneruje daná událost.
  • Registrovat ovladač (wx.EVT_SIZE, wx.EVT_BUTTOM, wx.EVT_CLOSE apod.) a svázat ho s metodou vytvořenou v předešlém kroku.
button = Button(self, label = 'I am button', id = -1)
button.Bind(wx.EVT_BUTTON, self.OnClick)

Vetování událostí

Občas potřebujeme provádění události zastavit (vetovat). K tomu slouží metoda Veto().

import wx

class Veto(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(250, 200))


        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self.Centre()
        self.Show(True)

    def OnClose(self, event):

        dial = wx.MessageDialog(None, 'Are you sure to quit?', 'Question',
            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        ret = dial.ShowModal()
        if ret == wx.ID_YES:
            self.Destroy()
        else:
            event.Veto()


app = wx.App()
Veto(None, -1, 'Veto')
app.MainLoop()

V tomto příkladě odchytáváme událost wx.CloseEvent. Tato událost je zavolána, když se pokoušíme zavřít okno. V mnoha aplikacích chceme zabránit uživateli, aby okno jen tak zavřel, protože například nestihl uložit rozdělanou práci. Musíme tedy registrovat ovladač wx.EVT_CLOSE.

dial = wx.MessageDialog(None, 'Are you sure to quit?', 'Question',
    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
ret = dial.ShowModal()

V průběhu metody wx.OnClose vytvoříme dialog, kde se ptáme, zda uživatel chce aplikaci opravdu vypnout.

if ret == wx.ID_YES:

    self.Destroy()
else:
    event.Veto()

V závislosti na proměnné ret buď zničíme okno, nebo zastavíme událost. Všimněte si, že okno ničíme pomocí Destroy(). Kdybychom použili metodu Close(), skončili bychom v nekonečné smyčce.

Šíření událostí

Existují dva druhy událostí: šiřitelné a nešiřitelné. Ty šiřitelné putují od dceřiných komponent až k hlavnímu rodičovskému oknu. Nešiřitelné putovat přestanou, jakmile jsou jednou zachyceny. Pokud chceme, aby se událost šířila dál, musíme zavolat metodu Skip().

import wx


class MyPanel(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)

        self.Bind(wx.EVT_BUTTON, self.OnClicked)

    def OnClicked(self, event):
        print 'event reached panel class'
        event.Skip()


class MyButton(wx.Button):
    def __init__(self, parent, id, label, pos):
        wx.Button.__init__(self, parent, id, label, pos)

        self.Bind(wx.EVT_BUTTON, self.OnClicked)

    def OnClicked(self, event):
        print 'event reached button class'
        event.Skip()


class Propagate(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(250, 150))

        panel = MyPanel(self, -1)

        MyButton(panel, -1, 'Ok', (15, 15))

        self.Bind(wx.EVT_BUTTON, self.OnClicked)

        self.Centre()
        self.Show(True)

    def OnClicked(self, event):
        print 'event reached frame class'
        event.Skip()


app = wx.App()
Propagate(None, -1, 'Propagate')
app.MainLoop()

V tomto příkladě máme jedno tlačítko v panelu, který je umístěn v okně wx.Frame. Vytvořili jsme ovladače pro všechny tři komponenty.

event reached button class
event reached panel class
event reached frame class

Tento výstup dostaneme, pokud klikneme na tlačítko. Událost putuje od tlačítka přes panel až k hlavnímu oknu.

Zkuste vynechat metodu Skip() a uvidíte, co se stane.

Identifikátory komponent

Identifikátory komponent jsou unikátní čísla (nelze použít nějaké číslo dvakrát), pomocí nichž poznáme, jaké komponentě máme předat danou událost. Existují tři způsoby, jak vytvořit identifikátor:

  • Nechat Python jej vytvořit.
  • Použít některý z předdefinovaných identifikátorů.
  • Přiřadit komponentě identifikátor dle vlastního výběru.
wx.Button(parent, -1)
wx.Button(parent, wx.ID_ANY)

Pokud jako identifikátor poskytneme -1 nebo wx.ID_ANY, necháváme jeho výběr na wxPythonu. Takto automaticky vytvořený identifikátor je vždy záporný, zatímco námi určené identifikátory musí být vždy kladné. Automatické indentifikátory používáme hlavně tehdy, když víme, že s danou komponentou již nebudeme pracovat (například wx.StaticText, který se po celou dobu aplikace nezmění). Pokud ale budeme chtít, můžeme získat hodnotu automatického identifikátoru pomocí metody GetId().

import wx

class AuIds(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(170, 100))

        panel = wx.Panel(self, -1)
        exit = wx.Button(panel, -1, 'Exit', (10, 10))

        self.Bind(wx.EVT_BUTTON,  self.OnExit, id=exit.GetId())

        self.Centre()
        self.Show(True)

    def OnExit(self, event):
        self.Close()


app = wx.App()
AuIds(None, -1, '')
app.MainLoop()

V předchozím příkladě jsme neurčili hodnotu identifikátoru → wxPython ji vybral za nás.

self.Bind(wx.EVT_BUTTON,  self.OnExit, id=exit.GetId())

Hodnotu automaticky vytvořeného identifikátoru získáme metodou GetId().

Je doporučeno používat předdefinované indentifikátory co nejvíce. Na některých platformách to totiž zlepší vzhled aplikace.

import wx

class Identifiers(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(200, 150))

        panel = wx.Panel(self, -1)
        grid = wx.GridSizer(3, 2)

        grid.AddMany([(wx.Button(panel, wx.ID_CANCEL), 0, wx.TOP | wx.LEFT, 9),
            (wx.Button(panel, wx.ID_DELETE), 0, wx.TOP, 9),
            (wx.Button(panel, wx.ID_SAVE), 0, wx.LEFT, 9),
            (wx.Button(panel, wx.ID_EXIT)),
            (wx.Button(panel, wx.ID_STOP), 0, wx.LEFT, 9),
            (wx.Button(panel, wx.ID_NEW))])


        self.Bind(wx.EVT_BUTTON, self.OnQuit, id=wx.ID_EXIT)

        panel.SetSizer(grid)
        self.Centre()
        self.Show(True)

    def OnQuit(self, event):
        self.Close()

app = wx.App()
Identifiers(None, -1, '')
app.MainLoop()

V předchozí ukázce jsme použili předdefinované identifikátory na tlačítka. Na linuxu budou mít tato tlačítka automaticky malé ikony.

wx.Focus event

Pomocí focusu dává aplikace vědět uživateli, která komponenta je zrovna vybraná. Stisky kláves a další události jsou odeslány komponentě, která má focus. K jeho manipulaci existují dva ovladače: wx.EVT_SET_FOCUS je zavolán, když daná komponenta získá focus. Druhý ovladač je wx.EVT_KILL_FOCUS. Ten je zavolán vždy, když komponenta ztratí focus. Focus se mění kliknutím myši na jinou komponentu nebo pomocí klávesové zkratky (obvykle Tab/Shift+Tab).

import wx


class MyWindow(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)

        self.color = '#b3b3b3'

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

    def OnPaint(self, event):
        dc = wx.PaintDC(self)

        dc.SetPen(wx.Pen(self.color))
        x, y = self.GetSize()
        dc.DrawRectangle(0, 0, x, y)

    def OnSize(self, event):
        self.Refresh()

    def OnSetFocus(self, event):
        self.color = '#0099f7'
        self.Refresh()

    def OnKillFocus(self, event):
        self.color = '#b3b3b3'
        self.Refresh()

class FocusEvent(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(350, 250))

        grid = wx.GridSizer(2, 2, 10, 10)
        grid.AddMany([(MyWindow(self), 1, wx.EXPAND|wx.TOP|wx.LEFT,9),
            (MyWindow(self), 1, wx.EXPAND|wx.TOP|wx.RIGHT, 9), 
            (MyWindow(self), 1, wx.EXPAND|wx.BOTTOM|wx.LEFT, 9), 
            (MyWindow(self), 1, wx.EXPAND|wx.BOTTOM|wx.RIGHT, 9)])


        self.SetSizer(grid)
        self.Centre()
        self.Show(True)

app = wx.App()
FocusEvent(None, -1, 'focus event')
app.MainLoop()

V předchozím příkladě jsme měli čtyři panely. Panel s focusem byl zvýrazněn.

wx.SizeEvent

Událost wx.SizeEvent je vygenerována vždy, když se změní velikost okna. V následujícím příkladu zobrazujeme aktuální velikost okna v titlebaru.

import wx

class SizeEvent(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Centre()
        self.Show(True)

    def OnSize(self, event):
        self.SetTitle(str(event.GetSize()))


app = wx.App()
SizeEvent(None, 1, 'sizeevent.py')
app.MainLoop()

Nastavení titulku okna provádíme metodou SetTitle().

self.SetTitle(str(event.GetSize()))

Aktuální velikost okna získáme zavoláním metody GetSize().

wx.PaintEvent

Kdykoliv se okno překresluje, je vyvolána událost wx.PaintEvent. Okno se překresluje celkem často. Například když změníte jeho velikost, nebo ho maximalizujete.

import wx

class PaintEvent(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        self.count = 0
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Centre()
        self.Show(True)

    def OnPaint(self, event):
        self.count = self.count + 1
        print self.count
        event.Skip()

app = wx.App()
PaintEvent(None, -1, 'paintevent.py')
app.MainLoop()

wx.KeyEvent

Pokud uživatel zmáčkne nějakou klávesu, vyvolá se událost wx.KeyEvent. Tato událost je poslána komponentě, která má v té době focus. Pro zpracování wx.KeyEvent existují tři různé ovladače:

  • wx.EVT_KEY_DOWN
  • wx.EVT_KEY_UP
  • wx.EVT_CHAR

Je celkem obvyklé, že pokud uživatel zmáčkne klávesu Escape, aplikace se zavře. A to se také pokusíme naprogramovat v následujícím kódu:

import wx

class KeyEvent(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        panel = wx.Panel(self, -1)
        panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        panel.SetFocus()

        self.Centre()
        self.Show(True)


    def OnKeyDown(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_ESCAPE:
            ret  = wx.MessageBox('Are you sure to quit?', 'Question', 
		wx.YES_NO | wx.NO_DEFAULT, self)
            if ret == wx.YES:
                self.Close()
        event.Skip()


app = wx.App()
KeyEvent(None, -1, 'keyevent.py')
app.MainLoop()

Analýza kódu:

keycode = event.GetKeyCode()

Získali jsme kód stisknuté klávesy.

if keycode == wx.WXK_ESCAPE:

Zde kontrolujeme, jaká klávesa byla zmáčknuta. Kód klávesy Escape je wx.WXK_ESCAPE.

Zdroj: http://zetcode.com/wxpython/events/

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

Hlasování bylo ukončeno    
0 hlasů
Google
Autor studuje na FIT ČVUT a je šéfredaktorem portálu Matematika pro každého.
Web    

Nové články

Reklama
Reklama
Obrázek ke článku Nový IT hráč na českém trhu

Nový IT hráč na českém trhu

V roce 2015 otevřela v Praze na Pankráci v budově City Tower své kanceláře společnost EPAM Systems (NYSE:EPAM), jejíž centrála se nachází v USA. Společnost byla založená v roce 1993 a od té doby prošla velkým vývojem a stále roste.

Obrázek ke článku České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace (CRA) pořádají druhý ročník CRA IoT Hackathonů. Zájemci z řad vývojářů a fanoušků moderních technologií mohou změřit své síly a během jediného dne sestrojit co nejzajímavější funkční prototyp zařízení, které bude komunikovat prostřednictvím sítě LoRa. CRA IoT Hackathony se letos uskuteční ve dvou fázích, na jaře a na podzim, v různých městech České republiky. Jarní běh se odstartuje 31. března v Brně a 7. dubna v Praze.

Obrázek ke článku Cloud computing je využíván stále intenzivněji

Cloud computing je využíván stále intenzivněji

Využívání cloud computingu nabývá na intenzitě. Jen v letošním roce vzroste podle analytiků trh se službami veřejného cloudu o 18 %, přičemž o téměř 37 % vzrostou služby typu IaaS. Růst o více než pětinu pak čeká služby poskytování softwaru formou služby, tedy SaaS. Aktuálním trendům v oblasti využívání cloudu se bude věnovat konference Cloud computing v praxi, která se koná 23. března. 2017 v pražském Kongresovém centru Vavruška na Karlově náměstí 5.

loadingtransparent (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })();
Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032017 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý