Dnes se naučíme rozmisťovat komponenty v okně absolutně (pomocí souřadnic) a pomocí sizerů. Představíme si wx.BoxSizer, wx.GridSizer, wx.FlexGridSizer a wx.GridBagSizer.
Typická aplikace se skládá z různých komponent. Tyto komponenty jsou nějakým způsobem rozmístěny v rodičovských kontejnerech. O toto rozmístění se musí starat programátor, tedy vy. V podstatě máte dvě možnosti:
- absolutní pozicování
- použití sizerů
Absolutní pozicování
Programátor musí přesně určit pozici a velikost každé komponenty, což je pochopitelně celkem náročné, a proto se upřednostňuje programování pomocí sizerů. Následuje několik důvodů, proč neprogramovat absolutně:
- Když změníte velikost okna, tak se velikost ostatních komponent nezmění.
- Změna písma může rozhodit vzhled aplikace.
- Pokud se rozhodnete přidat někam nějakou komponentu, musíte opět přepočítat pozice ostatních komponent.
Samozřejmě mohou nastat situace, kdy je absolutní pozicování lepší než užití sizerů. Například v tomto tutoriálu, protože použití sizerů by některé ukázky udělalo zbytečně složité. Ale ve skutečném světe programátoři užívají sizery.
V následujícím příkladě máme kostru textového editoru. Pokud změníme velikost okna, tak se velikost objektu wx.TextCtrl
nezmění.
import wx class Absolute(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(250, 180)) panel = wx.Panel(self, -1) menubar = wx.MenuBar() file = wx.Menu() edit = wx.Menu() help = wx.Menu() menubar.Append(file, '&File') menubar.Append(edit, '&Edit') menubar.Append(help, '&Help') self.SetMenuBar(menubar) wx.TextCtrl(panel, -1, pos=(-1, -1), size=(250, 150)) self.Centre() self.Show(True) app = wx.App(0) Absolute(None, -1, '') app.MainLoop()
Komponentě wx.TextCtrl
jsme nastavili šířku 250px a výšku 150px.
Používání sizerů
Můžeme si vybrat z několika druhů sizerů. Všechny si je ve zbytku článku popíšeme a ukážeme si, jak se používají.
- wx.BoxSizer
- wx.StaticBoxSizer
- wx.GridSizer
- wx.FlexGridSizer
- wx.GridBagSizer
import wx class Sizer(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(250, 180)) menubar = wx.MenuBar() file = wx.Menu() edit = wx.Menu() help = wx.Menu() menubar.Append(file, '&File') menubar.Append(edit, '&Edit') menubar.Append(help, '&Help') self.SetMenuBar(menubar) wx.TextCtrl(self, -1) self.Centre() self.Show(True) app = wx.App(0) Sizer(None, -1, '') app.MainLoop()
Objekt wx.TextCtrl
nyní mění svou velikost v závislosti na velikosti okna. Ale jak to? Vždyť jsme žádný sizer nepoužili. On má totiž wx.Frame
jeden zabudovaný. Do tohoto zabudovaného sizeru se dá umístit pouze jedna komponenta a ta pak vyplní všechen možný prostor.
wx.BoxSizer
Pomocí sizeru můžeme rozmístit komponenty buď do sloupce, nebo do řádku. Navíc můžeme jeden sizer vkládat do druhého, což nám umožňuje vytvářet celkem komplexní layout.
box = wx.BoxSizer(integer orient) box.Add(wx.Window window, integer proportion=0, integer flag = 0, integer border = 0)
Orientace může být buď vertikální (wx.VERTICAL
), nebo horizontální (wx.HORIZONTAL
). Vkládání komponent do sizerů se děje zavoláním metody Add()
. Tato metoda přijímá 4 parametry.
Parametr proportion
definuje poměr, podle kterého se změní velikost komponent. Lépe si to vysvětlíme na příkladu. Mějme tři tlačítka s parametrem proporion
nastaveným na 0, 1 a 2. Tlačítko s proporion = 0
se nezmění vůbec. Tlačítko s proportion = 2
bude dvakrát větší než tlačítko s proportion = 1
.
Pomocí parametru flag
můžeme nastavit, jak se budou chovat komponenty uvnitř sizeru. Můžeme například nastavit okraje jednotlivých komponent. Pokud chceme přidat mezi komponenty nějakou mezeru, musíme nastavit parametr border
a určit, kde se okraj zobrazí. Tedy například flag = wx.LEFT
. Parametr flag
může nabývat hodnot:
- wx.LEFT
- wx.RIGHT
- wx.BOTTOM
- wx.TOP
- wx.ALL
Tyto možnosti můžeme kombinovat pomocí operátoru |
: flag = wx.LEFT | wx.RIGHT
.
import wx class Border(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(250, 200)) panel = wx.Panel(self, -1) panel.SetBackgroundColour('#4f5049') vbox = wx.BoxSizer(wx.VERTICAL) midPan = wx.Panel(panel, -1) midPan.SetBackgroundColour('#ededed') vbox.Add(midPan, 1, wx.EXPAND | wx.ALL, 20) panel.SetSizer(vbox) self.Centre() self.Show(True) app = wx.App() Border(None, -1, '') app.MainLoop()
vbox.Add(midPan, 1, wx.EXPAND | wx.ALL, 20)
V ukázce jsme vytvořili 20px okraj kolem panelu midPan
. Tím, že jsme specifikovali parametr flag = wx.ALL
, jsme vykreslili okraj na všechny čtyři strany.
Do parametru flag přibylo pro nás ještě neznámé nastavení: wx.EXPAND
. Tím jsme nastavili, že se daná komponenta roztáhne do volného prostoru. Můžeme také nastavit zarovnání pomocí následujících parametrů:
- wx.ALIGN_LEFT
- wx.ALIGN_RIGHT
- wx.ALIGN_TOP
- wx.ALIGN_BOTTOM
- wx.ALIGN_CENTER_VERTICAL
- wx.ALIGN_CENTER_HORIZONTAL
- wx.ALIGN_CENTER
Reálná ukázka
V předchozím příkladě jsme sice použili sizery, ale takovou aplikaci bychom asi nikdy nevytvářeli. Nyní si ukážeme použití sizerů na reálnějším příkladě.
import wx class GoToClass(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(450, 350)) panel = wx.Panel(self, -1) font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT) font.SetPointSize(9) vbox = wx.BoxSizer(wx.VERTICAL) hbox1 = wx.BoxSizer(wx.HORIZONTAL) st1 = wx.StaticText(panel, -1, 'Class Name') st1.SetFont(font) hbox1.Add(st1, 0, wx.RIGHT, 8) tc = wx.TextCtrl(panel, -1) hbox1.Add(tc, 1) vbox.Add(hbox1, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10) vbox.Add((-1, 10)) hbox2 = wx.BoxSizer(wx.HORIZONTAL) st2 = wx.StaticText(panel, -1, 'Matching Classes') st2.SetFont(font) hbox2.Add(st2, 0) vbox.Add(hbox2, 0, wx.LEFT | wx.TOP, 10) vbox.Add((-1, 10)) hbox3 = wx.BoxSizer(wx.HORIZONTAL) tc2 = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) hbox3.Add(tc2, 1, wx.EXPAND) vbox.Add(hbox3, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10) vbox.Add((-1, 25)) hbox4 = wx.BoxSizer(wx.HORIZONTAL) cb1 = wx.CheckBox(panel, -1, 'Case Sensitive') cb1.SetFont(font) hbox4.Add(cb1) cb2 = wx.CheckBox(panel, -1, 'Nested Classes') cb2.SetFont(font) hbox4.Add(cb2, 0, wx.LEFT, 10) cb3 = wx.CheckBox(panel, -1, 'Non-Project classes') cb3.SetFont(font) hbox4.Add(cb3, 0, wx.LEFT, 10) vbox.Add(hbox4, 0, wx.LEFT, 10) vbox.Add((-1, 25)) hbox5 = wx.BoxSizer(wx.HORIZONTAL) btn1 = wx.Button(panel, -1, 'Ok', size=(70, 30)) hbox5.Add(btn1, 0) btn2 = wx.Button(panel, -1, 'Close', size=(70, 30)) hbox5.Add(btn2, 0, wx.LEFT | wx.BOTTOM , 5) vbox.Add(hbox5, 0, wx.ALIGN_RIGHT | wx.RIGHT, 10) panel.SetSizer(vbox) self.Centre() self.Show(True) app = wx.App() GoToClass(None, -1, 'Go To Class') app.MainLoop()
Na začátku jsme vytvořili jeden vertikální sizer, do kterého jsme pak umístili pět horizontálních sizerů.
vbox.Add(hbox3, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10) vbox.Add((-1, 25))
Už víme, jak nastavovat vzdálenost mezi komponentami pomocí parametru flag
a border
. Je zde ale jedno omezení. V metodě Add()
sice můžeme nastavit okraj, ale ten bude pro všechny strany stejný. V našem příkladě jsme nastavili okraj nalevo a napravo 10px. Ale už nemůžeme nastavit okraj 25px směrem dolů. Pokud tedy potřebujeme různé velikosti okrajů, můžeme mezi komponenty vložit nějaký volný prostor: vbox.Add((-1, 25))
.
Dialog Najít/Nahradit
Následuje ukázka již celkem komplexního designu.
import wx class FindReplace(wx.Dialog): def __init__(self, parent, id, title): wx.Dialog.__init__(self, parent, id, title, size=(255, 365)) vbox_top = wx.BoxSizer(wx.VERTICAL) panel = wx.Panel(self, -1) vbox = wx.BoxSizer(wx.VERTICAL) # panel1 panel1 = wx.Panel(panel, -1) grid1 = wx.GridSizer(2, 2) grid1.Add(wx.StaticText(panel1, -1, 'Find: ', (5, 5)), 0, wx.ALIGN_CENTER_VERTICAL) grid1.Add(wx.ComboBox(panel1, -1, size=(120, -1))) grid1.Add(wx.StaticText(panel1, -1, 'Replace with: ', (5, 5)), 0, wx.ALIGN_CENTER_VERTICAL) grid1.Add(wx.ComboBox(panel1, -1, size=(120, -1))) panel1.SetSizer(grid1) vbox.Add(panel1, 0, wx.BOTTOM | wx.TOP, 9) # panel2 panel2 = wx.Panel(panel, -1) hbox2 = wx.BoxSizer(wx.HORIZONTAL) sizer21 = wx.StaticBoxSizer(wx.StaticBox(panel2, -1, 'Direction'), orient=wx.VERTICAL) sizer21.Add(wx.RadioButton(panel2, -1, 'Forward', style=wx.RB_GROUP)) sizer21.Add(wx.RadioButton(panel2, -1, 'Backward')) hbox2.Add(sizer21, 1, wx.RIGHT, 5) sizer22 = wx.StaticBoxSizer(wx.StaticBox(panel2, -1, 'Scope'), orient=wx.VERTICAL) sizer22.Add(wx.RadioButton(panel2, -1, 'All', style=wx.RB_GROUP)) sizer22.Add(wx.RadioButton(panel2, -1, 'Selected Lines')) hbox2.Add(sizer22, 1) panel2.SetSizer(hbox2) vbox.Add(panel2, 0, wx.BOTTOM, 9) # panel3 panel3 = wx.Panel(panel, -1) sizer3 = wx.StaticBoxSizer(wx.StaticBox(panel3, -1, 'Options'), orient=wx.VERTICAL) vbox3 = wx.BoxSizer(wx.VERTICAL) grid = wx.GridSizer(3, 2, 0, 5) grid.Add(wx.CheckBox(panel3, -1, 'Case Sensitive')) grid.Add(wx.CheckBox(panel3, -1, 'Wrap Search')) grid.Add(wx.CheckBox(panel3, -1, 'Whole Word')) grid.Add(wx.CheckBox(panel3, -1, 'Incremental')) vbox3.Add(grid) vbox3.Add(wx.CheckBox(panel3, -1, 'Regular expressions')) sizer3.Add(vbox3, 0, wx.TOP, 4) panel3.SetSizer(sizer3) vbox.Add(panel3, 0, wx.BOTTOM, 15) # panel4 panel4 = wx.Panel(panel, -1) sizer4 = wx.GridSizer(2, 2, 2, 2) sizer4.Add(wx.Button(panel4, -1, 'Find', size=(120, -1))) sizer4.Add(wx.Button(panel4, -1, 'Replace/Find', size=(120, -1))) sizer4.Add(wx.Button(panel4, -1, 'Replace', size=(120, -1))) sizer4.Add(wx.Button(panel4, -1, 'Replace All', size=(120, -1))) panel4.SetSizer(sizer4) vbox.Add(panel4, 0, wx.BOTTOM, 9) # panel5 panel5 = wx.Panel(panel, -1) sizer5 = wx.BoxSizer(wx.HORIZONTAL) sizer5.Add((191, -1), 1, wx.EXPAND | wx.ALIGN_RIGHT) sizer5.Add(wx.Button(panel5, -1, 'Close', size=(50, -1))) panel5.SetSizer(sizer5) vbox.Add(panel5, 1, wx.BOTTOM, 9) vbox_top.Add(vbox, 1, wx.LEFT, 5) panel.SetSizer(vbox_top) self.Centre() self.SetClientSize(panel.GetBestSize()) self.ShowModal() self.Destroy() app = wx.App() FindReplace(None, -1, 'Find/Replace') app.MainLoop()
Než začneme programovat náš layout, bylo by dobré si situaci nakreslit na kus papíru. Věřte, občas to pomůže ;-). Pokud se podíváme na obrázek dialogu, je jasně vidět, že se celé okno skládá z pěti panelů.
Každý z nich bude nový objekt wx.Panel
. Všech pět panelů je pod sebou, a proto použijeme jako hlavní sizer vertikální wx.BoxSizer
. V kódu jsme také použili pro nás zatím neznámý sizer wx.GridSizer
, který bude vysvětlen za chvíli. Použili jsme ho proto, že nám velmi zjednodušuje práci. wx.GridSizer
vytvoří mřížku (v našem případě má mřížka velikost 2x2) a do každé buňky umístí jedno tlačítko. Pokud bychom nepoužili wx.GridSizer, museli bychom použít vertikální BoxSizer, do kterého bychom vložili dva horizontální sizery.
wx.GridSizer
Sizer wx.GridSizer
rozdělí komponenty do tabulky. Každá buňka tabulky je stejně široká.
wx.GridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
V konstruktoru musíme určit, kolik bude mít sizer řad a kolik sloupců. Pomocí parametrů vgap
a hgap
se nastavují mezery mezi jednotlivými buňkami.
Vše si ukážeme na následujícím kódu. Jedná se o kostru kalkulačky, což je skvělý příklad pro vysvětlení GridSizeru.
import wx class GridSizer(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(300, 250)) menubar = wx.MenuBar() file = wx.Menu() file.Append(1, '&Quit', 'Exit Calculator') menubar.Append(file, '&File') self.SetMenuBar(menubar) self.Bind(wx.EVT_MENU, self.OnClose, id=1) sizer = wx.BoxSizer(wx.VERTICAL) self.display = wx.TextCtrl(self, -1, '', style=wx.TE_RIGHT) sizer.Add(self.display, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4) gs = wx.GridSizer(4, 4, 3, 3) gs.AddMany( [(wx.Button(self, -1, 'Cls'), 0, wx.EXPAND), (wx.Button(self, -1, 'Bck'), 0, wx.EXPAND), (wx.StaticText(self, -1, ''), 0, wx.EXPAND), (wx.Button(self, -1, 'Close'), 0, wx.EXPAND), (wx.Button(self, -1, '7'), 0, wx.EXPAND), (wx.Button(self, -1, '8'), 0, wx.EXPAND), (wx.Button(self, -1, '9'), 0, wx.EXPAND), (wx.Button(self, -1, '/'), 0, wx.EXPAND), (wx.Button(self, -1, '4'), 0, wx.EXPAND), (wx.Button(self, -1, '5'), 0, wx.EXPAND), (wx.Button(self, -1, '6'), 0, wx.EXPAND), (wx.Button(self, -1, '*'), 0, wx.EXPAND), (wx.Button(self, -1, '1'), 0, wx.EXPAND), (wx.Button(self, -1, '2'), 0, wx.EXPAND), (wx.Button(self, -1, '3'), 0, wx.EXPAND), (wx.Button(self, -1, '-'), 0, wx.EXPAND), (wx.Button(self, -1, '0'), 0, wx.EXPAND), (wx.Button(self, -1, '.'), 0, wx.EXPAND), (wx.Button(self, -1, '='), 0, wx.EXPAND), (wx.Button(self, -1, '+'), 0, wx.EXPAND) ]) sizer.Add(gs, 1, wx.EXPAND) self.SetSizer(sizer) self.Centre() self.Show(True) def OnClose(self, event): self.Close() app = wx.App() GridSizer(None, -1, 'GridSizer') app.MainLoop()
Všimněte si, jak je vytvořená mezera mezi tlačítky Bck
a Close
. Jednoduše jsme tam vložili prázdný wx.StaticText
. Takové triky jsou celkem časté.
Místo metody Add()
jsme použili metodu AddMany()
. Pokud najednou vkládáte více komponent do sizeru, ušetříte několik znaků.
AddMany(list items)
Komponenty se v sizeru zarovnají podle toho, v jakém pořadí byly přidány. Nejprve se zaplní první řádek, pak druhý atd.
wx.FlexGridSizer
Tento sizer je velmi podobný wx.GridSizeru. Také umisťuje komponenty do tabulky, ale je trochu přizpůsobivější. Všechny buňky ve wx.GridSizeru mají stejnou velikost. U wx.FlexGridSizeru je tomu jinak. Všechny buňky v rámci jednoho řádku mají stejnou výšku. Všechny buňky v rámci jednoho sloupce mají stejnou šířku. Ale všechny řádky a sloupce nemusejí mít nutně stejnou výšku a šířku.
wx.FlexGridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
Parametry rows
a cols
určují, kolik bude mít tabulka řádků a sloupců. Pomocí parametrů vgap
a hgap
se dá nastavit mezera mezi jednotlivými buňkami.
import wx class FlexGridSizer(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(290, 250)) panel = wx.Panel(self, -1) hbox = wx.BoxSizer(wx.HORIZONTAL) fgs = wx.FlexGridSizer(3, 2, 9, 25) title = wx.StaticText(panel, -1, 'Title') author = wx.StaticText(panel, -1, 'Author') review = wx.StaticText(panel, -1, 'Review') tc1 = wx.TextCtrl(panel, -1) tc2 = wx.TextCtrl(panel, -1) tc3 = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE) fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author), (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)]) fgs.AddGrowableRow(2, 1) fgs.AddGrowableCol(1, 1) hbox.Add(fgs, 1, wx.ALL | wx.EXPAND, 15) panel.SetSizer(hbox) self.Centre() self.Show(True) app = wx.App() FlexGridSizer(None, -1, 'FlexGridSizer') app.MainLoop()
Analýza kódu:
hbox = wx.BoxSizer(wx.HORIZONTAL) ... hbox.Add(fgs, 1, wx.ALL | wx.EXPAND, 15)
Vytvořili jsme horizontální wx.BoxSizer
, protože chceme nějak oddělit okraj okna od krajů komponent (v tomto případě je to 15px).
fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author), (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])
Metoda AddMany()
je stejná jako u wx.GridSizeru.
fgs.AddGrowableRow(2, 1) fgs.AddGrowableCol(1, 1)
Třetí řádek a druhý sloupec jsme nastavili zavoláním metod AddGrowableRow()
a AddGrowableCol()
tak, že se roztáhnou, pokud se okno zvětší. První dva řádky tabulky se mohou roztahovat horizontálním směrem. Třetí řádek se může roztahovat oběma směry.
wx.GridBagSizer
Toto je nejsložitější sizer ze všech. Mnoho programátorů pokládá za příliš složité ho používat. Přesto se práce s ním dá celkem dobře naučit. Chce to vytvořit několik grafických návrhů, prostě si to zažít.
Přestože tento sizer tvoří tabulky, je zde několik rozdílů oproti wx.FlexGridSizeru. Tento sizer umožňuje v metodě Add()
specifikovat do jaké buňky se má komponenta vložit. Lze také nastavit span
, tedy kolik buněk bude komponenta zabírat.
wx.GridBagSizer(integer vgap, integer hgap)
Parametry vgap
a hgap
definují, jaká bude mezera mezi jednotlivými buňkami. Stejně jako u všech předchozích sizerů se komponenta přidává zavoláním metody Add()
.
Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0, integer border=0, userData=None)
Parametr pos
je umístění komponenty ve virtuální tabulce (levý horní roh má souřadnice (0, 0)). Pomocí parametru span
můžeme určit, přes kolik buněk se daná buňka roztáhne (pokud je span = (3, 2)
, tak se komponenta roztáhne přes 3 řádky a 2 sloupce). Parametry flag
a border
už byly vysvětleny.
Buňky mohou měnit svou velikost v závislosti na změně velikosti okna. Standardně to ale není nastavené. Toto nastavení se dá změnit pomocí dvou metod:
AddGrowableRow(integer row) AddGrowableCol(integer col)
Dialog Přejmenovat
Náš první příklad bude velmi lehký, takže není třeba se bát, že byste něco nepochopili. Vytvoříme dialog Přejmenovat, který bude obsahovat jeden objekt wx.StaticText
, jeden objekt wx.TextCtrl
a dva objekty wx.Button
.
import wx class Rename(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(320, 130)) panel = wx.Panel(self, -1) sizer = wx.GridBagSizer(4, 4) text = wx.StaticText(panel, -1, 'Rename To') sizer.Add(text, (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5) tc = wx.TextCtrl(panel, -1) sizer.Add(tc, (1, 0), (1, 5), wx.EXPAND | wx.LEFT | wx.RIGHT, 5) buttonOk = wx.Button(panel, -1, 'Ok', size=(90, 28)) buttonClose = wx.Button(panel, -1, 'Close', size=(90, 28)) sizer.Add(buttonOk, (3, 3)) sizer.Add(buttonClose, (3, 4), flag=wx.RIGHT | wx.BOTTOM, border=5) sizer.AddGrowableCol(1) sizer.AddGrowableRow(2) panel.SetSizerAndFit(sizer) self.Centre() self.Show(True) app = wx.App() Rename(None, -1, 'Rename Dialog') app.MainLoop()
Analýza kódu:
text = wx.StaticText(panel, -1, 'Rename To') sizer.Add(text, (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
Text 'Rename to' se má umístit do levého horního rohu. Proto jsme určili, že pos = (0, 0)
.
tc = wx.TextCtrl(panel, -1) sizer.Add(tc, (1, 0), (1, 5), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
Objekt wx.TextCtrl
se má vykreslit na dalším řádku, tedy (1, 0), a má se roztáhnout přes pět buňek (horizontálním směrem).
sizer.Add(buttonOk, (3, 3)) sizer.Add(buttonClose, (3, 4), flag=wx.RIGHT | wx.BOTTOM, border=5)
Tlačítka jsme vykreslili do čtvrtého řádku. Třetí je prázdný - tvoří mezeru mezi vstupem a tlačítky. Tlačítko Ok
jsme umístili do 4. sloupce a tlačítko Close
do pátého. Všimněte si, že jsme větší okraj nastavili pouze jednou tlačítku, ale změnila se výška celého řádku.
sizer.AddGrowableCol(1) sizer.AddGrowableRow(2)
Poslední věcí, kterou musíme udělat, je upravit dialog tak, aby se šířka vstupu měnila současně s velikostí okna. Proto jsme nastavili, že druhý sloupec a třetí řádek se bude roztahovat společně se změnou velikosti okna.
Open Resource
Následující příklad je trochu složitější. Vytvoříme dialog, který můžete najít v Eclipse IDE.
import wx class OpenResource(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(400, 500)) panel = wx.Panel(self, -1) sizer = wx.GridBagSizer(4, 4) text1 = wx.StaticText(panel, -1, 'Select a resource to open') sizer.Add(text1, (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5) tc = wx.TextCtrl(panel, -1) sizer.Add(tc, (1, 0), (1, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5) text2 = wx.StaticText(panel, -1, 'Matching resources') sizer.Add(text2, (2, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5) list1 = wx.ListBox(panel, -1, style=wx.LB_ALWAYS_SB) sizer.Add(list1, (3, 0), (5, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5) text3 = wx.StaticText(panel, -1, 'In Folders') sizer.Add(text3, (8, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5) list2 = wx.ListBox(panel, -1, style=wx.LB_ALWAYS_SB) sizer.Add(list2, (9, 0), (3, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5) cb = wx.CheckBox(panel, -1, 'Show derived resources') sizer.Add(cb, (12, 0), flag=wx.LEFT | wx.RIGHT, border=5) buttonOk = wx.Button(panel, -1, 'OK', size=(90, 28)) buttonCancel = wx.Button(panel, -1, 'Cancel', size=(90, 28)) sizer.Add(buttonOk, (14, 1)) sizer.Add(buttonCancel, (14, 2), flag=wx.RIGHT | wx.BOTTOM, border=5) help = wx.BitmapButton(panel, -1, wx.Bitmap('icons/help16.png'), style=wx.NO_BORDER) sizer.Add(help, (14, 0), flag=wx.LEFT, border=5) sizer.AddGrowableCol(0) sizer.AddGrowableRow(3) sizer.AddGrowableRow(9) sizer.SetEmptyCellSize((5, 5)) panel.SetSizer(sizer) self.Centre() self.Show(True) app = wx.App() OpenResource(None, -1, 'Open Resource') app.MainLoop()
sizer.AddGrowableRow(3) sizer.AddGrowableRow(9)
Chceme mít oba wx.ListBoxy
roztahovatelné.