Dialogy a formuláře ve wxPythonu

20. 7. 2006
Doba čtení: 5 minut

Sdílet

Dnes budeme pokračovat v programování GUI aplikace ve wxPythonu. Cílem dnešního dílu seriálu je vytvoření dialogu pro vkládání nebo editaci dat a základní zobrazení formulářů aplikace. Budeme přímo navazovat na předchozí díl seriálu, a proto si jej nezapomeňte zopakovat.

Trochu předběhnu (budeme se tomu věnovat v příštím díle) a ukážeme si, jak zhruba bude vypadat struktura tabulky v databázi sqlite (pomůže nám to k pochopení dnešního dílu).

Struktura tabulky addressbook
Název položky Typ
id INTEGER PRIMARY KEY
name VARCHAR(200)
address TEXT
phone VARCHAR(100)
email VARCHAR(200)

Návrh dialogu pro vkládání / editaci dat

Dialog určený pro vkládání / editaci dat by měl vypadat zhruba takhle:

boa05-01

Spusťme Boa Constructor, otevřeme aplikaci „/AddressBook/Ap­p1.py“ a přidáme nový „wx.Dialog“ (v horním „Toolbaru“ v paletě „New“ tlačítko (wx.Dialog) Spustíme „Designer panel“ (Designer panel) a jako první v „Inspectoru“ změníme položku „Name: dlgAddressBook“ a „Title: Address book“. V záložce „Props“ zvolíme „Icon:“, otevřeme soubor „myImgRes.py“a zvolíme „ico01“. Pomocí tažení, popř. numericky v Inspectoru, upravíme dialog na nějakou rozumnou velikost (doporučuji wx.Size(320, 211) a uložíme.

Opětovně spustíme „Designer panel“ (Designer panel) a vložíme jednotlivé komponenty:

Komponenty dialogu
Class: Name: Label: Style:
wx.StaticText stName Name:
wx.TextCtrl txName
wx.StaticText stAddress Address:
wx.TextCtrl txAddress wx.TE_MULTILINE
wx.StaticText stPhone Phone:
wx.TextCtrl txPhone
wx.StaticText stEmail Email:
wx.TextCtrl txEmail
wx.Button btConfirm C&onfirm
wx.Button btCancel C&ancel

Pohrajeme si se sizery (já jsem použil 3× „wx.FlexGridSi­zer“), nemělo by větší význam toto rozepisovat (zachází se s nimi podobně, jako v předchozích dílech), pro případné zájemce doporučuji prostudovat můj vzorový zdrojový kód.

Jako poslední zkontrolujeme / upravíme „Tab Order…“ (slouží k tomu, aby bylo možné přeskakovat mezi jednotlivými položkami pomocí klávesy „Tab“). Klikněme na „dlgAddressbook“ (zvolíme tento dialog) a pak klikneme pravým tlačítkem myši. Otevře se nám nabídka a v její spodní časti zvolíme položku „Creation/Tab order…“. V otevřeném dialogu upravíme položky následovně:

boa05-03

Dále pak vytvoříme události pro jednotlivá tlačítka:

Jména a události tlačítek
Name: wx.EVT_BUTTON
btConfirm myConfirm
btCancel myCancel

Ukončíme „Designer panel“ (Post the session) a v „Editoru“ upravíme funkci myCancel

    def myCancel(self, event):
        event.Skip()
        self.Close() 

Provedeme lokalizaci (viz díl Resource soubory a i18n ve wxPythonu) a celé naše snažení uložíme. Nyní můžeme v klidu ukončit Boa Constructor.

Začínáme programovat

I když to v tomto případě není nutné, je dobré si zvyknout, že většinu kódu není vhodné psát přímo do vygenerovaného kódu s UI, ale využít k tomu potomků daných tříd, např. z důvodu, že chcete vytvořený formulář použít více než jednou s jiným kódem, apod. K tomu v tomto příkladu slouží podadresář „lib/“. V něm vytvoříme (prozatím) 4 soubory („__init__.py“, „MyFunction.py“, „MyFrame.py“ a „dlgAddressBo­ok.py“)

Jako první upravíme v nějakém editoru soubor „lib/MyFunction.py“ (bude nám sloužit pro přístup k členským funkcím, které budeme využívat v různých místech našeho programu). V něm vytvoříme třídu „MyFunction“ a prozatím jednu členskou funkci „OpenMyDialog“. Tato funkce nám bude sloužit k otevírání dialogových oken. Výpis souboru lib/MyFunction.py

import wx

class MyFunction:
    enc = 'utf-8'

    def OpenMyDialog(self, mywin, param=""):
        self.dlg = mywin
        self.dlg.CenterOnScreen()        # vycentruje dialog
        self.val = self.dlg.ShowModal()  # nastaví dialog jako modální
        self.dlg.Destroy() 

Dále upravíme soubor „lib/MyFrame.py“ v němž vytvoříme třídu „MyFrame“ který je potomkem dvou tříd („ui.MyFrame.My­Frame“ a „lib.MyFuncti­on.MyFunction“). Upravíme konstruktor (členská funkce „__init__“) tak, aby přejímal i parametr „size“. Dále pak vytvoříme členskou funkci „MyGrid“, která přejímá parametry počet sloupců („cols“) a šířku sloupců („size“). Bude nám sloužit k nastavení sloupců v tabulce „grData“ se všemi potřebnými parametry.

Další členskou funkcí bude „InsertRecord“, která nám prozatím bude sloužit k zobrazení dialogu „dlgAddressBook“.

Obsah souboru lib/MyFrame.py

import wx
from wx import GetTranslation as _
import ui.MyFrame, lib.MyFunction

import os

class MyFrame( ui.MyFrame.MyFrame, lib.MyFunction.MyFunction ):
    conn = ''
    numrec = 0
    myId = 0

    def __init__( self, parent, size ):
        self._init_ctrls(parent)   # inicializujeme ui.MyFrame

        # nastavime jmena a sirku sloupcu v tabulce grData
        colName = [ _("Name"),_("E-mail"), _("Phone") ]
        colSize = [ size-560, 250, 250 ]
        self.MyGrid( colName, colSize )


    def MyGrid(self, cols, size):
        nr = len(cols)   # počet sloupců
        self.grData.CreateGrid(0, nr)
        self.grData.SetRowLabelSize(30)  # nastaví výšku labelu

        for i in range(len(cols)):
            self.grData.SetColLabelValue(i,cols[i])
            self.grData.SetColSize(i,size[i])

        self.grData.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE)
        return


    def InsertRecord(self, event):
        # Slouží k vkládání záznamů
        event.Skip()
        tmp = {}
        tmp['Id'] = 0
        tmp['conn'] = self.conn
        tmp['typ'] = 'insert'
        import lib.dlgAddressBook
        dlg = self.OpenMyDialog( lib.dlgAddressBook.dlgAddressBook( None, tmp ) ) 

Nyní vytvoříme potomka třidy „dlgAddressBook“ (soubor „lib/dlgAddres­sBook.py“). Vytvoříme konstruktor (členská funkce „__init__“) tak, aby přejímal i parametry „param“ a prozatím jen měnil podle těchto parametrů titulek okna.

Obsah souboru lib/dlgAddres­sBook.py

bitcoin_skoleni

import wx
from wx import GetTranslation as _
import ui.dlgAddressBook, lib.MyFunction

class dlgAddressBook( ui.dlgAddressBook.dlgAddressBook, lib.MyFunction.MyFunction ):
    conn = ''
    actId = 0
    typ = 'insert'

    def __init__(self, parent, param):
        self.conn = param['conn']
        self.typ = param['typ']
        self._init_ctrls(parent)

        if self.typ == 'edit':
            self.SetTitle( _('Address Book - Edit record') )
            self.actId = param['Id']
        else:
            self.SetTitle( _('Address Book - Insert record') ) 

Vzhledem k tomu, že u většiny aplikací budeme požadovat, aby šířka hlavního okna byla pokud možno přes celou obrazovku, upravíme jako poslední soubor „AddressBook/Ap­p1.py“ následujícím způsobem (nezapomeňte změnit „import ui.MyFrame“ na „import lib.MyFrame“ a „self.main = ui.MyFrame.cre­ate(None)“ na „self.main = lib.MyFrame.My­Frame( None, x-2 )“):

import lib.MyFrame

modules ={u'MyFrame': [0, '', u'ui/MyFrame.py'],
 u'dlgAddressBook': [0, '', u'ui/dlgAddressBook.py'],
 u'myImgRes': [0, '', u'ui/myImgRes.py']}

class BoaApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        x, y = wx.GetDisplaySize()           # získá šířku a výsku obrazovky
        self.main = lib.MyFrame.MyFrame( None, x-2 )
        self.main.SetSize( [ x-2, y-30 ] )   # nastaví šířku okna
        self.main.CenterOnScreen()           # nastaví pozici okna na obrazovce
        self.main.Show()
        self.SetTopWindow( self.main )
        return True

def main():
    application = BoaApp(0)
    application.MainLoop() 

Timto pro dnešek končíme, v příštím díle se budeme věnovat propojení aplikace s databází „sqlite“. Jakož v předchozích dílech, tak i dneska jsem připravil zdrojové kódy.

Autor článku