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 339×

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

Obrázek ke článku NEWTON Media prohledá 200  milionů mediálních zpráv během sekund díky Cisco UCS

NEWTON Media prohledá 200 milionů mediálních zpráv během sekund díky Cisco UCS

Česká společnost NEWTON Media provozuje největší archiv mediálních zpráv ve střední a východní Evropě. Mezi její zákazníky patří například ministerstva, evropské instituce nebo komerční firmy z nejrůznějších oborů. NEWTON Media rozesílá svým zákazníkům každý den monitoring médií podle nastavených klíčových slov a nabízí online službu, kde lze vyhledat mediální výstupy v plném znění od roku 1996.

Reklama
Reklama
Obrázek ke článku Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Touto roční dobou, kdy je zem pokrytá barevným listím a prsty křehnou v mrazivých ránech, se obvykle těšíme na zbrusu novou verzi RAD Studia. Letos si však ale budeme muset počkat na Godzillu a Linux až do jara. Vezměme tedy za vděk alespoň updatem 2 a jelikož dle vyjádření pánů z Embarcadero se budou nové věci objevovat průběžně, pojďme se na to tedy podívat.

Obrázek ke článku Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Stále rostoucí zájem o cloudové služby i maximální důraz na pružnost, spolehlivost a bezpečnost IT vedou k výrazným inovacím v datových centrech. V infrastruktuře datových center hraje stále významnější roli software a stále častěji se lze setkat s hybridními přístupy k jejich budování i provozu.

Obrázek ke článku Konference: Mobilní technologie mají velký potenciál pro byznys

Konference: Mobilní technologie mají velký potenciál pro byznys

Firmy by se podle analytiků společnosti Gartner měly  rychle přizpůsobit skutečnosti, že mobilní technologie už zdaleka nejsou horkou novinkou, ale standardní součástí byznysu. I přesto - nebo možná právě proto - tu nabízejí velký potenciál. Kde tedy jsou ty největší příležitosti? I tomu se bude věnovat již čtvrtý ročník úspěšné konference Mobilní řešení pro business.

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 © 20032016 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý