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

wxPython - událostiwxPython - události

 

wxPython - události

Google       Google       8. 11. 2008       29 932×

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.

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

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý