Hlavní navigace

Cirkus s okny: dialog pro komunikaci s uživatelem

Zdeněk Král 7. 1. 2003

Chcete mít zajímavou firemní prezentaci, nebo pěkný obrázek s nápisem hned v úvodním okně Vaší aplikace? Pokud ano, tak se podívejte na dnešní pokračování o grafické knihovně wxPython, kde najdete návod, jak na to. Dále si vytvoříme dialog pro komunikaci s uživatelem naší aplikace. Naučíme se psát text do námi definované oblasti a vysvětlíme si, jak naše aplikace pozná, na které platformě operačního systému je spuštěna.

V úvodu dnešního pokračování musím přiznat několik chyb, které se vloudily do skriptu naší aplikace v minulém díle. Proto zde uvádím opravený zdrojový kód. A nyní se podíváme na to, jak by mohlo vypadat úvodní okno naší aplikace

Teď si vysvětlíme, jak zajistit odezvu na podnět ze strany uživatele. V mnoha případech budeme používat dialogové okno z třídy wxMessageDialog , které nám umožní pohodlně reagovat na řadu událostí jak ze strany uživatele, tak ze strany samotné aplikace. V knihovně wxPython máme v podstatě dva typy dialogů. První jsou již předdefinované a jsou součástí vlastní grafické knihovny, jako již zmíněný dialog pro jednoduché zprávy nebo dialog pro otevření a uložení souboru – wxFileDialog, dialog pro adresáře – wxDirDialog, dialog palety barev atd. Druhou skupinu tvoří dialogy z třídy wxDialog , pomocí kterých budeme tvořit vlastní aplikaci a budou mít vzhled a vlastnosti, které jim sami nadefinujeme. Nyní se vraťme k našemu prvnímu dialogu.

Třída wxMessageDialog:

Uvedeme i předky této třídy, z kterých dědí důležité vlastnosti:

wxWindow, wxEvtHandler, wxObject, wxDialog

Defaultní konstruktor této třídy má následující formát :

wxMessageDialog­.__init__( parent, message, caption, style, pos )

Parametry třídy wxMessageDialog:

První čtyři parametry jsou povinné, pátý volitelný,

  • parent má defaultně hodnotu self jako ukazatel na objekt, který jej volá.
  • message typu wxString obsahuje zprávu pro uživatele.
  • caption má defaultně hodnotu „MessageBox“ nebo námi zadaný titulek tohoto okna.
  • style nabývá následujících hodnot :
    • wxOK
    • wxCANCEL
    • wxYES_NO
    • wxYES_DEFAULT
    • wxNO_DEFAULT
    • wxCENTRE pouze pro Unix a Linux
    • wxICON_EXCLAMATION
    • wxICON_HAND
    • wxICON_QUESTION
    • wxICON_INFORMATION
    • pos určuje pozici okna na obrazovce pomocí třídy wxPoint(int, int). Defaultně má hodnotu wxDefaultPosition a dialog se zobrazí nad středem volajícího objektu.

Metody třídy wxMessageDialog:

Tato třída obsahuje pouze jedinou metodu, která má návratovou hodnotu typu integer.

  • wxMessageDialog­.ShowModal() nám vrátí hodnotu int jako wxID_OK, wxID_CANCEL, wxID_YES nebo wxID_NO.

Členění projektu do modulů

Náš kód se pomalu začíná rozrůstat, a pokud budeme chtít mít přehled i ve skriptech s několika stovkami řádků a docílit toho, aby se náš projekt nechal dobře udržovat, musíme začít s členěním do modulů. Je věcí každého, jak k této problematice přistoupí, a každý prográmator si časem vytvoří vlastní styl, který mu nejvíce vyhovuje. Takže další navržené postupy berte pouze jako východisko k vlastní tvořivosti.

V našem pracovním adresáři si vytvořte ve Vašem oblíbeném textovém editoru nový soubor /home/projekt/Pro­jektFunkce.py nebo C:\Python22\pro­jekt\ProjektFun­kce.py. V tomto souboru si vytvoříme stejnojmennou třídu, pro kterou budeme definovat metody základního okna naší aplikace. Sem také zkopírujeme nám již známou metodu Notify.

Návrh souboru ProjektFunkce.py

01. #!/usr/bin/env python
02.
03. from wxPython.wx import *
04. import time
05.
06. class ProjektFunkce:
07.
08.     def __init__(self):
09.
10.         self.parent = self
11.
12.     #----------------------------------------------
13.     def OnCloseWindow(self, event):
14.
15.         dlg = wxMessageDialog(self,'Zálohovat ?',\
16.              'POZOR', wxYES_NO|wxICON_EXCLAMATION)
17.
18.         msg = wxMessageDialog(self, 'Uloženo !',\
19.              'ZÁLOHOVÁNÍ', wxOK|wxICON_INFORMATION)
20.
21.
22.         if dlg.ShowModal() == wxID_YES:
23.
24.            #  zde provedeme zálohování
25.
26.            if msg.ShowModal() == wxID_OK:
27.               msg.Destroy()
28.               dlg.Destroy()
29.               self.Destroy()
30.            else:
31                dlg.Destroy()
32.               self.Destroy()
33.
34.     #----------------------------------------------
35.     def Notify(self):
36.
37.         t = time.localtime(time.time())
38.         st= time.strftime("%d-%b-%Y  %I:%M:%S", t)
39.         self.SetStatusText(st, 1)
40.
41.     #----------------------------------------------
42.     def OnMoveWindow(self, event):
43.
44.         self.CenterOnScreen()

Podotkněme, že řádek 10. nám zajišťuje syntaxi jazyka pro požadované odsazení. Další význam tomuto zápisu nepřikládejme.

Nyní si náš skript rozšíříme o možnost nápisu do prostoru hlavního okna naší aplikace. V dnešním dílu nebudu blíže rozebírat použité třídy wxSaticText a wxFont , protože jim bude věnován samostatný díl, až si budeme tvořit vlastní třídy pro zjednodušení zápisu některých grafických prvků do kódu. Podotknu, že je pouze nutné použít pomocnou třídu wxPanel, která nám vytvoří pozadí na virtuální ploše základního frameworku. Tak můžeme prakticky ovládat vzhled základního okna a můžeme na tuto plochu umisťovat další grafické prvky. Všimněte si, že jako rodič třídy wxStaticText je uveden „panel“ jako instance třídy wxPanel. Pouze je nutné zdůraznit, že zde nemusí plně fungovat diakritika, a proto volíme raději názvy bez národních znaků. Spíše bude zajímavé, že zde můžeme umístit třeba firemní logo ve formě bitmapy atd. To nám umožní na řádku18. třída wxBitmap a následně zobrazíme na řádku 20. zvolenou bitmapu pomocí třídy wxStaticBitmap. Vzhledem k tomu, že pracujeme s formátem JPG, je nutné v metodě OnInit na řádku 72. zadat handle na tento formát dat pomocí třídy wxImage_AddHandler. Obrázek ve formátu JPG umístíme do stejného adresáře, jako je umístěna vlastní aplikace, jinak budete muset definovat absolutní cestu k tomuto souboru.

V projektu přidáme na řádku 64. a 65. volání námi definovaných metod základního okna self.OnCloseWindow a self.OnMove, a to prostřednictvím maker EVT_CLOSE aEVT_MOVE z třídy wxCommandEvent. Na řádku 05. importujeme všechny metody definované v třídě ProjektFunkce a na řádku 07. zajistíme jejich dědění pro třídu MyFrame hlavního okna naší aplikace. Tím se stávají součástí této třídy a můžeme je podle potřeby zavolat.

01. #!/usr/bin/env python
02.
03. from wxPython.wx import *
04.
05. from ProjektFunkce import *
06.
07. class MyFrame(wxFrame, ProjektFunkce):
08.
09.     def __init__(self, parent, id, title):
10.
11.         wxFrame.__init__(self, parent, id, title,\
12.                 wxPoint(150,150),wxSize(650, 400))
13.
14.         panel = wxPanel(self, -1)

15.
16.         string = "Projekt"
17.
18.         bmp = wxBitmap('CSO_III_pozadi.jpg', \
19.                        wxBITMAP_TYPE_JPEG)
20.         wxStaticBitmap(panel, -1, bmp, (0, 0))
21.
22.         text = wxStaticText(panel, -1, string, \
23.                             wxPoint(60, 120))
24.         font = wxFont(40, wxROMAN,wxNORMAL,wxBOLD,\
25.                       false, '')
26.         w, h, d, e = self.GetFullTextExtent(string,\
27.                       font)
28.         text.SetFont(font)
29.         text.SetSize(wxSize(w, h))
30.         text.SetForegroundColour(wxColour(255,196,88))
31.         text.SetBackgroundColour(wxColour(0, 16, 32))
32.
33.         year = "2002"
34.         text = wxStaticText(panel, -1, year, \
35.                             wxPoint(170, 185))
36.         font = wxFont(15, wxROMAN,wxNORMAL,wxBOLD, \
37.                       false, '')
38.         w, h, d, e = self.GetFullTextExtent(year, \
39.                       font)
40.         text.SetFont(font)
41.         text.SetSize(wxSize(w, h))
42.         text.SetForegroundColour(wxColour(255,196,88))
43.         text.SetBackgroundColour(wxColour(0, 16, 32))
44.
45.         if wxPlatform == '__WXMSW__':
46.            self.icon = wxIcon('project.ico', \
47.                                wxBITMAP_TYPE_ICO)
48.            self.SetIcon(self.icon)
49.         else:
50.            self.icon = wxIcon("project.xpm", \
51.                                wxBITMAP_TYPE_XPM)
52.            self.SetIcon(self.icon)
53.
54.
55.         self.CenterOnScreen()
56.
57.         sb = self.CreateStatusBar(2)
58.         sb.SetStatusWidths([-1, 130])
59.
60.         self.timer = wxPyTimer(self.Notify)
61.         self.timer.Start(1000)
62.         self.Notify()
63.
64.         EVT_CLOSE(self, self.OnCloseWindow)
65.         EVT_MOVE(self, self.OnMoveWindow)

66.
67.
68. class MyApp(wxApp):
69.
70.     def OnInit(self):
71.
72.         wxImage_AddHandler(wxJPEGHandler())
73.         frame = MyFrame(NULL, -1, Title)
74.         frame.Show(true)
75.         self.SetTopWindow(frame)
76.         return(true)
77.
78. app = MyApp(0)
79. app.MainLoop()

Nyní bych se rád zmínil o některých direktivách preprocesoru, které umožní aplikaci zjistit, na jakém operačním systému je spuštěna. V našem případě tak docílíme toho, že bude jak na systému Windows, tak i na Linuxu zavedena správná systémová ikona a my se v rámci demonstrace přenositelnosti kódu mezi operačními systémy nemusíme starat o její grafický formát. Obě ikony musí být umístěny ve stejném adresáři jako vlastní aplikace!

Direktivy preprocesoru:

  • __WXMOTIF__ pro knihovnu Motif
  • __WXGTK__ pro knihovnu GTK
  • __WXGTK12__ pro knihovnu GTK verze 1.2 a vyšší
  • __WXMSW__ pro systém Windows
  • __WXWINE__ při použití Wine pro Windows na Unixu
  • __WXMAC__ pro MacOS

Právě použití direktivy __WXMSW__ si demonstrujeme na řádku 45. za pomoci třídy wxPlatform, která ji definuje jako svou návratovou hodnotu a umožní nám určit typ operačního systému.

Po zkompilování a spuštění bychom měli při uzavření hlavního okna aplikace vyvolat následující dva dialogy, které nám již dobře demonstrují implementaci třídy wxMessageDialog.

V příštím pokračování se již dostaneme k slíbenému vytváření nabídek typu wxMenu a rozčleníme si náš kód do dalších modulů pro jednoduchou správu celého systému. Dále nás bude čekat implementace třídy wxDialog a vytvoření prvního dialogu dle našich požadavků.

Pro demonstraci kódu z dnešního dílu si můžete stáhnout příslušné grafické soubory:
project.ico
project.xpm
pozadi.jpg

Našli jste v článku chybu?

16. 1. 2003 23:07

Zdeněk Král (neregistrovaný)

Musim priznat, ze se jedna o velmi podnetny prispevek, protoze jde o chybu zanesenou do vlastni instalace Python 2.2 v adresari "Tools/idle". Uvedenou upravu jsem odzkousel na vsech Windows 9x az po 2k a XP, je plne funkcni. Myslim, ze by stalo za to, upozornit autory "IDLE" pro dalsi distribuce Pythonu pod Windows. Proste "Windows jsou Windows", co dodat??

16. 1. 2003 10:29

Bohous (neregistrovaný)

Pokud by nekoho zajimala uvedena uprava IDLE tady je:
V dokumentaci je uvedeno ,ze python pri behu prohledava adresare podle seznamu 'sys.path' a pokud je prvni prvek seznamu prazdny tak prohledava aktualni adresar. Ale pri vypisu toho seznamu v IDLE tam ten prazdny prvek chybel a krome toho po spusteni skryptu ,ktery vypise aktualni adresar se ukazalo, ze i ten aktualni adresar jiny nez umisteni daneho skryptu.

Takze v modulu 'PyShell.py' jsem za upravu promenne sys.path
' for i in range…



Podnikatel.cz: EET zvládneme, budou horší zákony

EET zvládneme, budou horší zákony

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: ČRo rozšiřuje DAB do Berouna

ČRo rozšiřuje DAB do Berouna

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Měšec.cz: Finančním poradcům hrozí vracení provizí

Finančním poradcům hrozí vracení provizí

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře