A wxPython egy több platformos GUI programozói könyvtár készlet, amelyet Python nyelven programozhatunk. A wxPython segítségével valódi natív alkalmazások hozhatok létre, amelyek kis változtatás, vagy változtatás nélkül használhatók Windows, macOS és Linux rendszeren.
Ennek a dokumentumnak az írásánál a wxPython stabil kiadása, 4.1.0.
A wxPython modulok a C++ nyelven írt, wxWidgets keresztplatformos, nyílt forráskódú programozói könyvtárból származnak. A wxPython a wxWidgets-hez hasonlóan nyílt forráskódú, ami azt jelenti hogy bárki számára szabadon használható, módosítható.
Mivel a programozási nyelv Python, a wxPython programok könnyen írhatók és könnyen érthetőek.
A Phoenix, a wxPython az alapoktól kezdve újraírt változata, azzal a szándékkal, hogy jobb és gyorsabb legyen mint korábban. A Phoenix-ből eltávolítása kerültek felesleges részek, karbantarthatóbb, bővíthetőbb lett. A Phoenix még fejlesztés alatt áll, aki használja, úgynevezett pillanatképet használ a megvalósításból.
Néhány átszervezés, tisztítás és egyszerűsítés miatt a wxPython és a Phoenix nem teljesen kompatibilis egymással, szándékosan. A különbségek azonban, általában csekélyek, egyes alkalmazások, akár módosítás nélkül is futhatnak. Néhány helyen az osztályból elérés módját változtatták meg a Phoenix rendszerben.
import wx program = wx.App(False) ablak = wx.Frame(None, title='Helló Világ') ablak.Show(True) program.MainLoop()
A szabványos kimenet és a szabványos hibakimenet (sys.stdout és sys.stderr) nem lesz átirányítva. Ha wx.App(True, filename='uzenet.txt') formában használjuk, akkor egy print() utasítás kimenete az uzenet.txt állomány végéhez fűzödik.
import wx app = wx.App() frame = wx.Frame(None, title='Helló Világ') button = wx.Button(frame, label="Mehet") frame.Show(True) app.MainLoop()
import wx app = wx.App() frame = wx.Frame(None, title='Helló Világ') button = wx.Button(frame, label="Mehet") def OnClickButton(event): frame.SetTitle('működik') button.Bind(wx.EVT_BUTTON, OnClickButton) frame.Show(True) app.MainLoop()
Az ablak címsorának megváltoztatása:
frame.SetTitle('működik')
import wx def main(): app = wx.App() frame = wx.Frame(None) frame.SetSize(wx.Size(800,600)) frame.Center() frame.SetTitle("Első program") frame.Show() app.MainLoop() main()
A következő programban osztályt használunk az ablak létrehozására.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) class SimpleApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = SimpleApp() app.MainLoop()
A SimplaApp osztályban létrehoztunk egy OnInit() függvényt. Ez automatikusan végrehajtódik futtatáskor.
A nyomógomb gyakori eszköz a felhasználói események figyelésére. A Button osztállyal egy gombot teszünk az ablakba. A gombnak csak a felirata lesz beállítva, ezét kitölti az egész ablakot.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) button = wx.Button(self, label="Mehet") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Nézzük az új sort: button = wx.Button(self, label=„Mehet”).
A nyomógombok a kattintásra való reagálás nélkül nem sokat érnek. Nézzük, hogyan rendelhetünk egy végrehajtandó függvényt a gombhoz.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.button = wx.Button(self, label="Mehet") self.button.Bind(wx.EVT_BUTTON, self.OnClickButton) def OnClickButton(self, event): self.SetTitle('Működik') class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Nézzük az új sort: self.button.Bind(wx.EVT_BUTTON, self.OnClickButton).
Ha két eszközt teszünk fel, azok alapértelmezettként egymáson jelennek meg. Meghatározhatjuk a pozíciójukat a SetPosition() függvénnyel. A gomb mellett egy beviteli mezőt jelenítünk meg a TextCtrl osztállyal.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text = wx.TextCtrl(self) self.text.SetPosition((10, 10)) self.button = wx.Button(self, label="Mehet") self.button.SetPosition((10, 60)) self.button.Bind(wx.EVT_BUTTON, self.OnClickButton) def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
A SetPosition() függvénynek egyetlen paramétere van, egy wx.Point típus. Ez két módon adható meg:
A példában mi az első formát használtuk.
A widgetsek elhelyezése a SetPositon() függvénnyel fix elrendezést eredményez. A méretezők lehetővé tesznek rugalmas, automatikus elrendezést, méretezést. A programok widgets elemeit célszerű ezekkel meghatározni.
Itt a BoxSizer méretezőt fogjuk használni. Segítségével, két lehetőséget állíthatunk be. Vagy függőlegesen egymás alá rendezzük a widgets elemeket, vagy vízszintesen, egymás mellé.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text = wx.TextCtrl(self) self.button = wx.Button(self, label="Mehet") self.button.Bind(wx.EVT_BUTTON, self.OnClickButton) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(self.text) vbox.Add(self.button) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Most változtassuk meg az elrendezést vízszintesre.
Keressük meg a vbox = wx.BoxSizer(wx.VERTICAL) sort, majd cseréljük a következőre:
vbox = wx.BoxSizer(wx.HORIZONTAL)
Futtassuk a programot, nézzük meg.
A méretezőbe több widgets elem is elhelyezhető.
Az elhelyezett widgets elemek Általában több sorból és oszlopból állnak. Ebben a példában két sorba helyezünk el elemeket.
Készítünk vbox1 néven egy függőleges méretezőt, és két belső méretezőt, amelyik vízszintes elrendezést használ. A méretezőket így egymásba ágyazzuk.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") self.vbox1 = wx.BoxSizer(wx.VERTICAL) self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) self.hbox2 = wx.BoxSizer(wx.HORIZONTAL) self.vbox1.Add(self.hbox1) self.vbox1.Add(self.hbox2) self.hbox1.Add(self.text1) self.hbox1.Add(self.button1) self.hbox2.Add(self.text2) self.hbox2.Add(self.button2) self.SetSizer(self.vbox1) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
A harmadik sorba egy újabb gombot szeretnénk elhelyezni.
Az ábrán azt látjuk, hogy nem hoztunk létre újabb vízszintes méretezőt. Ezt megtehetjük és működni fog. Ha később még több elemre is számíthatunk a harmadik sorba, akkor viszont érdemes ezt egy újabb méretezőbe tenni.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") self.button3 = wx.Button(self, label="Harmadik") vbox1 = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox1.Add(hbox1) vbox1.Add(hbox2) vbox1.Add(self.button3) hbox1.Add(self.text1) hbox1.Add(self.button1) hbox2.Add(self.text2) hbox2.Add(self.button2) self.SetSizer(vbox1) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Most, hogy ilyen sok utasításunk van, az elrendezést egy külön függvénybe rendezzük.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") self.button3 = wx.Button(self, label="Harmadik") self.DoLayout() def DoLayout(self): vbox1 = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox1.Add(hbox1) vbox1.Add(hbox2) vbox1.Add(self.button3) hbox1.Add(self.text1) hbox1.Add(self.button1) hbox2.Add(self.text2) hbox2.Add(self.button2) self.SetSizer(vbox1) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Térjünk vissza az egyetlen widget soros programunkhoz. Szeretnénk, ha két widget kitöltené az ablakban a rendelkezésre álló helyet. El kell döntenünk, milyen arányban töltse ki a widget a rendelkezésre álló helyet. Lehet 1:1, 1:2, vagy ami éppen tetszik.
Lehet 0:1 arány is. Ilyenkor a 0 aránnyal rendelkező widget marad alapértelmezett méretű, a másik widget pedig kitölti a maradék helyet.
Ehhez ki kell egészítenünk a kódot. A példában, az első elem számára 1, a második elem számára 2-t állítunk be.
vbox.Add(self.text1, 1) vbox.Add(self.button1, 2)
Ahogy látjuk, az Add() függvénynek egy második paramétert adtunk meg.
A teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") vbox = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(self.text1, 1) vbox.Add(self.button1, 2) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
A két sor widgetünk van, az egy sorban lévő beviteli mező és gomb nem töltik ki a rendelkezésre álló helyet. Az eredmény ilyen:
De ezt szeretnénk:
A kész programablak:
Ez azért van, mert a vbox1 méretezőnek függőleges elrendezése van.
A megoldás, ha a hbox1 és a hbox2 számára megmondjuk, hogy töltse ki a rendelkezésre álló helyet:
vbox1.Add(hbox1, 0, wx.EXPAND) vbox1.Add(hbox2, 0, wx.EXPAND)
Az arányokat, mindkét esetben 0 értéken hagyjuk.
Teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) hbox1.Add(self.text1, 1) hbox1.Add(self.button1, 2) hbox2.Add(self.text2, 1) hbox2.Add(self.button2, 2) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
A megfelelő eredmény:
Az előző munkánkhoz felteszünk egy gombot, harmadik sorként, és szeretnénk középre igazítani.
Ha az wx.EXPAND-ot használnánk, az egészet kitöltené. Helyette a wx.ALIGN_CENTER_HORIZONTAL állandót használjuk.
vbox.Add(self.button3, 0, wx.ALIGN_CENTER_HORIZONTAL)
A teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") self.button3 = wx.Button(self, label="Másik") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button3, 0, wx.ALIGN_CENTER_HORIZONTAL) hbox1.Add(self.text1, 1) hbox1.Add(self.button1, 2) hbox2.Add(self.text2, 1) hbox2.Add(self.button2, 2) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Az eredmény:
Szeretnénk 6 pixeles szegélyt minden widget köré.
hbox1.Add(self.text1, 1, wx.ALL, 6) hbox1.Add(self.button1, 2, wx.ALL, 6) ... hbox2.Add(self.text2, 1, wx.ALL, 6) hbox2.Add(self.button2, 2, wx.ALL, 6) ... vbox.Add(self.button3, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6)
A button3 objektum esetén már van egy harmadik paraméter, ezért egy (|) pipe karakterrel elválasztva vezetjük be a wx.ALL állandót.
A wx.ALL a szegélyre vonatkozik. Azt jelenti minden oldalon.
Lehetséges értékek:
Természetesen pipe karakterrel tagolva, ezekből is megadható több. Az Add() függvényünknek lett egy negyedik paraméter is, ami megmondja hány pixel széles legyen a szegély.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Egyik") self.button2 = wx.Button(self, label="Másik") self.button3 = wx.Button(self, label="Másik") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button3, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6) hbox1.Add(self.text1, 1, wx.ALL, 6) hbox1.Add(self.button1, 2, wx.ALL, 6) hbox2.Add(self.text2, 1, wx.ALL, 6) hbox2.Add(self.button2, 2, wx.ALL, 6) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Cseréljük le a gombokat feliratokra, és tegyük azokat baloldalra.
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.label1 = wx.StaticText(self, label="Egyik") self.label2 = wx.StaticText(self, label="Másik") self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Mehet") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button1, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6) hbox1.Add(self.label1, 1, wx.ALL, 6) hbox1.Add(self.text1, 2, wx.ALL, 6) hbox2.Add(self.label2, 1, wx.ALL, 6) hbox2.Add(self.text2, 2, wx.ALL, 6) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Látható, hogy a feliratok függőlegesen nincsenek középen a nyomógombhoz képest.
Az idevonatkozó sorok:
hbox1.Add(self.label1, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) ... hbox2.Add(self.label2, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6)
A teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.label1 = wx.StaticText(self, label="Egyik") self.label2 = wx.StaticText(self, label="Másik") self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Mehet") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button1, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6) hbox1.Add(self.label1, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox1.Add(self.text1, 2, wx.ALL, 6) hbox2.Add(self.label2, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox2.Add(self.text2, 2, wx.ALL, 6) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
Szeretnénk a widgeten belül jobbra igazítani a szöveget. Ehhez a style=wx.ALIGN_RIGH beállítást használjuk.
self.label1 = wx.StaticText(self, label="Egyik", style=wx.ALIGN_RIGHT) self.label2 = wx.StaticText(self, label="Másik", style=wx.ALIGN_RIGHT)
A teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.label1 = wx.StaticText(self, label="Egyik", style=wx.ALIGN_RIGHT) self.label2 = wx.StaticText(self, label="Másik", style=wx.ALIGN_RIGHT) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Mehet") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button1, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6) hbox1.Add(self.label1, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox1.Add(self.text1, 2, wx.ALL, 6) hbox2.Add(self.label2, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox2.Add(self.text2, 2, wx.ALL, 6) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
A beviteli mezőktől jobbra nem ártana több hely. Ezt helykitöltővel érjük el:
hbox1.Add((20, 20), 1) ... hbox2.Add((20, 20), 1)
A teljes kód:
import wx class MainFrame(wx.Frame): def __init__(self, parent): super(MainFrame, self).__init__(parent) self.label1 = wx.StaticText(self, label="Egyik", style=wx.ALIGN_RIGHT) self.label2 = wx.StaticText(self, label="Másik", style=wx.ALIGN_RIGHT) self.text1 = wx.TextCtrl(self) self.text2 = wx.TextCtrl(self) self.button1 = wx.Button(self, label="Mehet") vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) hbox2 = wx.BoxSizer(wx.HORIZONTAL) vbox.Add(hbox1, 0, wx.EXPAND) vbox.Add(hbox2, 0, wx.EXPAND) vbox.Add(self.button1, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 6) hbox1.Add(self.label1, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox1.Add(self.text1, 2, wx.ALL, 6) hbox1.Add((20, 20), 1) hbox2.Add(self.label2, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 6) hbox2.Add(self.text2, 2, wx.ALL, 6) hbox2.Add((20, 20), 1) self.SetSizer(vbox) self.Layout() def OnClickButton(self, event): self.text.SetValue("42") class ButtonApp(wx.App): def OnInit(self): frame = MainFrame(None) frame.Show() return True app = ButtonApp() app.MainLoop()
#!/usr/bin/python #coding: utf-8 import wx app = wx.App() frame = wx.Frame(None) frame.SetSize(wx.Size(800,600)) frame.SetCursor(wx.StockCursor(wx.CURSOR_MAGNIFIER)) frame.SetPosition(wx.Point(0,0)) frame.SetTitle("Első program") frame.Show() app.MainLoop()