I am trying to nest an sizer with horizontal layout inside the vertical layout sizer of a notebookPage panel.
I took some inspiration from wxPython: Resizing a notebook within a notebook but cannot make it work properly.
Instead of getting this layout
Tonnage limit (in tons): [3000]
[x] Enable filter on matchings categories
Everything is mangled on a single line in the panel
I am running this on Win7, python 2.6.6, wx 2.8.12.1
Here is the relevant code:
import sys
import os
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,title):
self.ID_LOAD=101
self.ID_SAVE=102
# based on a frame, so set up the frame
wx.Frame.__init__(self,parent,wx.ID_ANY, title, size=(640,480))
self.CreateStatusBar()
self.tab = wx.Notebook(self, -1, style=(wx.NB_TOP))
self.globPanel = wx.NotebookPage(self.tab, -1)
self.orderPanel = wx.NotebookPage(self.tab, -1)
self.slabsPanel = wx.NotebookPage(self.tab, -1)
self.tab.AddPage(self.globPanel, "Global filter")
self.tab.AddPage(self.orderPanel, "Orders filter")
self.tab.AddPage(self.slabsPanel, "Slabs filter")
self.toolbar = wx.ToolBar(self, wx.ID_ANY, style=wx.TB_HORIZONTAL)
self.toolbar.SetToolBitmapSize((20,20))
load_ico = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (20,20))
self.toolbar.AddLabelTool(self.ID_LOAD, "Load", load_ico, bmpDisabled=wx.NullBitmap, shortHelp='Load', longHelp="Loads a text file to the filter editor")
save_ico = wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, (20,20))
self.toolbar.AddLabelTool(self.ID_SAVE, "Save", save_ico, bmpDisabled=wx.NullBitmap, shortHelp='Save', longHelp="Saves the contents of the filter editor")
self.toolbar.AddSeparator()
self.tonnageStatic = wx.StaticText(self.globPanel, wx.ID_ANY, "Tonnage limit (in tons): ")
self.tonnageEdit = wx.TextCtrl(self.globPanel, wx.ID_ANY, '30000')
self.tonnageSizer = wx.BoxSizer(wx.HORIZONTAL)
self.tonnageSizer.Add(self.tonnageStatic, flag=wx.EXPAND | wx.RIGHT | wx.LEFT | wx.TOP | wx.BOTTOM, border=10)
self.tonnageSizer.Add(self.tonnageEdit, flag=wx.EXPAND | wx.RIGHT | wx.LEFT | wx.TOP | wx.BOTTOM, border=10)
self.filterCheck = wx.CheckBox(self.globPanel, wx.ID_ANY, "Enable filter on matchings categories")
self.globSizer = wx.BoxSizer(wx.VERTICAL)
self.globSizer.Add(self.tonnageSizer)
self.globSizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
self.globSizer.Add(self.filterCheck, 0, wx.EXPAND)
self.globPanel.SetSizer(self.globSizer)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.toolbar,0,wx.EXPAND)
self.sizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
self.sizer.Add(self.tab, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.Layout()
self.toolbar.Realize()
# Show it !!!
self.Show(1)
def main():
app = wx.PySimpleApp()
view = MainWindow(None, "Input filter")
app.MainLoop()
if __name__ == "__main__":
main()
It is slighlty better like this, but I don't get the static line and only the first character of the checkox label is displayed
self.tonnageStatic = wx.StaticText(self.globPanel, wx.ID_ANY, "Tonnage limit (in tons): ")
self.tonnageEdit = wx.TextCtrl(self.globPanel, wx.ID_ANY, '30000')
self.tonnageSizer = wx.BoxSizer(wx.HORIZONTAL)
self.tonnageSizer.Add(self.tonnageStatic, 0, flag=wx.EXPAND|wx.ALL)
self.tonnageSizer.Add(self.tonnageEdit, 0, flag=wx.EXPAND|wx.ALL)
self.filterCheck = wx.CheckBox(self.globPanel, wx.ID_ANY, "Enable filter on matchings categories")
self.globSizer = wx.BoxSizer(wx.VERTICAL)
self.globSizer.Add(self.tonnageSizer)
self.globSizer.Add(wx.StaticLine(self.globPanel), 0, wx.EXPAND)
self.globSizer.Add(self.filterCheck, 0, wx.EXPAND)
self.globPanel.SetSizer(self.globSizer)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.toolbar,0,wx.EXPAND)
self.sizer.Add(wx.StaticLine(self), 0, wx.EXPAND)
self.sizer.Add(self.tab, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.globPanel.Layout()
self.Layout()
self.toolbar.Realize()
# Show it !!!
self.Show(1)
I just ran it on windows and if you call .Layout() on the globPanel after the self.Layout() line it should kick the sizers into shape :)
Also you can use wx.ALL which is the same as right, left, top and bottom
EDIT: I was curious why the weird behaviour and looked into a bit more. I looked at places I've used notebooks and I always use panels for the pages. If you change the NotebookPages to Panels you can do away with the Layout calls and it works as expected.
Related
I've been trying to learn wxPython and just can't get my head around sizers. As an exercise, I'm trying to lay out three panels so they appear inside of each other. Firstly, I've used an image editing program to show an approximation window I'm trying to achieve:
This is the code I'm using to attempt this:
import wx
class MyApp(wx.Frame):
def __init__(self):
super().__init__(None, title="Test")
outer_sizer = wx.BoxSizer()
outer_panel = wx.Panel(self)
outer_panel.SetBackgroundColour(wx.Colour("#94f7e7"))
inner_panel = wx.Panel(outer_panel)
inner_panel.SetBackgroundColour(wx.Colour("#b8e8a9"))
inner_sizer = wx.BoxSizer()
inner_inner_panel = wx.Panel(inner_panel)
inner_inner_panel.SetBackgroundColour(wx.Colour("#cbebf5"))
inner_inner_sizer = wx.BoxSizer()
inner_inner_sizer.Add(inner_inner_panel, 1, wx.ALL | wx.EXPAND, 20)
inner_sizer.Add(inner_inner_panel, 1, wx.ALL | wx.EXPAND, 20)
outer_sizer.Add(inner_sizer, 1, wx.EXPAND)
outer_panel.SetSizer(outer_sizer)
if __name__ == '__main__':
app = wx.App()
ma = MyApp()
ma.Show()
app.MainLoop()
And this is what it actually results with:
The reason I had hoped the above code would work is because I had some success with the following code:
import wx
class MyApp(wx.Frame):
def __init__(self):
super().__init__(None, title="Test")
outer_sizer = wx.BoxSizer()
outer_panel = wx.Panel(self)
outer_panel.SetBackgroundColour(wx.Colour("#94f7e7"))
inner_panel = wx.Panel(outer_panel)
inner_panel.SetBackgroundColour(wx.Colour("#b8e8a9"))
inner_sizer = wx.BoxSizer()
inner_sizer.Add(inner_panel, 1, wx.ALL | wx.EXPAND, 20)
outer_sizer.Add(inner_sizer, 1, wx.EXPAND)
outer_panel.SetSizer(outer_sizer)
if __name__ == '__main__':
app = wx.App()
ma = MyApp()
ma.Show()
app.MainLoop()
Which produced this:
Now obviously I'm not getting something. I'm hoping the above will enable some kind soul to identify what I'm not understanding.
None of the related posts here seem to help much as they don't ever nest panels more than one layer.
Ok, the first step will be putting in just one panel and make a hierarchy of 3 sizers. This works exactly as you expect, only you cannot change the background color of a sizer:
def __init__(self):
super().__init__(None, title="Test")
sz1 = wx.BoxSizer()
sz2 = wx.BoxSizer()
sz3 = wx.BoxSizer()
p1 = wx.Panel(self)
p1.SetBackgroundColour(wx.RED)
sz3.Add(p1, 1, wx.ALL | wx.EXPAND, 20)
sz2.Add(sz3, 1, wx.ALL | wx.EXPAND, 20)
sz1.Add(sz2, 1, wx.ALL | wx.EXPAND, 20)
self.SetSizer(sz1)
Now, to really use the panels you have to put the panel into sizer (sizer.Add) and than the sizer into the panel (panel.SetSizer) and than into a sizer and so on... Just be careful about setting the right parent.
def __init__(self):
super().__init__(None, title="Test")
sz1 = wx.BoxSizer()
sz2 = wx.BoxSizer()
sz3 = wx.BoxSizer()
p1 = wx.Panel(self)
p2 = wx.Panel(p1)
p3 = wx.Panel(p2)
p1.SetBackgroundColour(wx.RED)
p2.SetBackgroundColour(wx.GREEN)
p3.SetBackgroundColour(wx.BLUE)
sz3.Add(p3, 1, wx.ALL | wx.EXPAND, 20) # innermost
p2.SetSizer(sz3)
sz2.Add(p2, 1, wx.ALL | wx.EXPAND, 20)
p1.SetSizer(sz2)
sz1.Add(p1, 1, wx.ALL | wx.EXPAND, 0)
self.SetSizer(sz1)
I an trying to get a minimal wxPython GUI working, but I failed so far in achieving the desired result. What I want is to expand the text input widget in the first line so that it fills up the width of the dialog/frame. I want the input box become as wide so that its right border aligns with the right border of the button in the (wider) second line.
I thought that's what the wx.EXPAND flag is for when adding to the sizer, but apparently I am doing something wrong. Here is my code in a working example:
import wx
class MyApp(wx.Frame):
def __init__(self):
super(MyApp, self).__init__(None, title="wxPython Sizers", style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.panel = wx.Panel(self)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
# First line, should expand it's width to fit the second line
panel_sizer = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
text = wx.StaticText(self.panel, label="Short label:")
hbox.Add(text, flag=wx.ALIGN_CENTER_VERTICAL)
numtext = wx.TextCtrl(self.panel)
hbox.Add(numtext, flag=wx.LEFT | wx.EXPAND, border=10)
panel_sizer.Add(hbox)
# The second, wider line
hbox = wx.BoxSizer(wx.HORIZONTAL)
text = wx.StaticText(self.panel, label="This is a long label:")
hbox.Add(text, flag=wx.ALIGN_CENTER_VERTICAL)
img_folder_button = wx.Button(self.panel, label="Button")
hbox.Add(img_folder_button, flag=wx.LEFT, border=10)
panel_sizer.Add(hbox, flag=wx.TOP, border=15)
# We need only this one sizer for the panel
self.panel.SetSizer(panel_sizer)
# Set final dialog layout
self.main_sizer.Add(self.panel, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
self.SetSizer(self.main_sizer)
self.Layout()
self.Fit()
self.Center()
self.Show()
if __name__ == "__main__":
wxapp = wx.App()
myApp = MyApp()
wxapp.MainLoop()
Be consistent with the use of proportion and border.
Rather than re-use hbox declare them separately and expand the button as well in case the user the expands the frame.
import wx
class MyApp(wx.Frame):
def __init__(self):
super(MyApp, self).__init__(None, title="wxPython Sizers", style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
self.panel = wx.Panel(self)
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
# First line, should expand it's width to fit the second line
panel_sizer = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
text = wx.StaticText(self.panel, label="Short label:")
hbox1.Add(text, flag=wx.ALIGN_CENTER_VERTICAL)
numtext = wx.TextCtrl(self.panel)
hbox1.Add(numtext, proportion=1, flag=wx.LEFT | wx.EXPAND, border=15)
# The second, wider line
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
text = wx.StaticText(self.panel, label="This is a long label:")
hbox2.Add(text, flag=wx.ALIGN_CENTER_VERTICAL)
img_folder_button = wx.Button(self.panel, label="Button")
hbox2.Add(img_folder_button, proportion=1, flag=wx.LEFT | wx.EXPAND, border=15)
panel_sizer.Add(hbox1, flag=wx.TOP | wx.EXPAND, border=15)
panel_sizer.Add(hbox2, flag=wx.TOP | wx.EXPAND, border=15)
# We need only this one sizer for the panel
self.panel.SetSizer(panel_sizer)
# Set final dialog layout
self.main_sizer.Add(self.panel, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
self.SetSizerAndFit(self.main_sizer)
self.Layout()
self.Center()
self.Show()
if __name__ == "__main__":
wxapp = wx.App()
myApp = MyApp()
wxapp.MainLoop()
You are expanding your numtext inside the horizontal box sizer. That's correct. But you must also expand your horizontal box sizer inside the vertical box sizer.
I have been working on creating a python GUI for some work. I would self-describe as a novice when it comes to by Python knowledge. I am using wxPython and wxGlade to help with the GUI development, as well.
The problem is as follows:
I have an empty TextCtrl object and a Button next to it.
The Button is meant to open a FileDialog and populate or replace the TextCtrl with the value of the file location that is selected. I have created the functionality for the button to open the FileDialog but I can't seem to figure out how to populate the TextCtrl with that resulting value.
import wx
class frmCheckSubmital(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: frmCheckSubmitall.__init__
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.rbxUtilitySelect = wx.RadioBox(self, wx.ID_ANY, "Utility", choices=["Stormwater", "Sewer", "Water"], majorDimension=1, style=wx.RA_SPECIFY_ROWS)
self.txtFeaturesPath = wx.TextCtrl(self, wx.ID_ANY, "")
self.btnSelectFeatures = wx.Button(self, wx.ID_ANY, "Select")
# selectEvent = lambda event, pathname=txt: self.dialogFeatures(event, pathname)
self.btnSelectFeatures.Bind(wx.EVT_BUTTON, self.dialogFeatures)
self.txtPipesPath = wx.TextCtrl(self, wx.ID_ANY, "")
self.btnSelectPipes = wx.Button(self, wx.ID_ANY, "Select")
self.bxOutput = wx.Panel(self, wx.ID_ANY)
self.cbxDraw = wx.CheckBox(self, wx.ID_ANY, "Draw")
self.btnClear = wx.Button(self, wx.ID_ANY, "Clear")
self.btnZoom = wx.Button(self, wx.ID_ANY, "Zoom")
self.btnRun = wx.Button(self, wx.ID_ANY, "Run", style=wx.BU_EXACTFIT)
self.__set_properties()
self.__do_layout()
# end wxGlade
def __set_properties(self):
# begin wxGlade: frmCheckSubmitall.__set_properties
self.SetTitle("Check Submittal")
self.rbxUtilitySelect.SetSelection(0)
self.btnSelectFeatures.SetMinSize((80, 20))
self.btnSelectPipes.SetMinSize((80, 20))
self.cbxDraw.SetValue(1)
self.btnClear.SetMinSize((50, 20))
self.btnZoom.SetMinSize((50, 20))
# end wxGlade
def __do_layout(self):
# begin wxGlade: frmCheckSubmitall.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_5 = wx.BoxSizer(wx.VERTICAL)
sizer_8 = wx.BoxSizer(wx.HORIZONTAL)
sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
sizer_5.Add(self.rbxUtilitySelect, 0, wx.ALIGN_CENTER | wx.BOTTOM, 10)
lblFeatures = wx.StaticText(self, wx.ID_ANY, "Features: ")
sizer_6.Add(lblFeatures, 0, wx.ALIGN_CENTER | wx.LEFT, 16)
sizer_6.Add(self.txtFeaturesPath, 1, 0, 0)
sizer_6.Add(self.btnSelectFeatures, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, 5)
sizer_5.Add(sizer_6, 0, wx.EXPAND, 0)
lblPipes = wx.StaticText(self, wx.ID_ANY, "Pipes: ")
sizer_7.Add(lblPipes, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 16)
sizer_7.Add(self.txtPipesPath, 1, 0, 0)
sizer_7.Add(self.btnSelectPipes, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, 5)
sizer_5.Add(sizer_7, 0, wx.ALL | wx.EXPAND, 0)
sizer_5.Add(self.bxOutput, 1, wx.ALL | wx.EXPAND, 10)
sizer_8.Add(self.cbxDraw, 0, wx.LEFT | wx.RIGHT, 10)
sizer_8.Add(self.btnClear, 0, wx.RIGHT, 10)
sizer_8.Add(self.btnZoom, 0, 0, 0)
sizer_8.Add((20, 20), 1, 0, 0)
sizer_8.Add(self.btnRun, 0, wx.BOTTOM | wx.RIGHT, 10)
sizer_5.Add(sizer_8, 0, wx.EXPAND, 0)
sizer_1.Add(sizer_5, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
self.SetSize((400, 300))
# end wxGlade
# Begin Dialog Method
def dialogFeatures(self, event):
# otherwise ask the user what new file to open
#with wx.FileDialog(self, "Select the Features File", wildcard="Text files (*.txt)|*.txt",
# style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
fileDialog = wx.FileDialog(self, "Select the Features File", wildcard="Text files (*.txt)|*.txt",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
if fileDialog.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
# Proceed loading the file chosen by the user
pathname = fileDialog.GetPath()
self.txtFeaturesPath.SetValue = pathname
self.txtFeaturesPath.SetValue(pathname)
try:
with open(pathname, 'r') as file:
self.txtFeaturesPath = file
except IOError:
wx.LogError("Cannot open file '%s'." % newfile)
# End Dialog Method
# end of class frmCheckSubmitall
if __name__ == '__main__':
app=wx.PySimpleApp()
frame = frmCheckSubmital(parent=None, id=-1)
frame.Show()
app.MainLoop()
I've tried to do several things and I am just burnt out and in need of some help.
Some things I've tried to do:
- Add a third argument in the dialog method to return that (just not sure where to assign)
- Use a lambda event to try and assign the value with the constructors?
Any help or insight would be greatly appreciated. Thank you!
As others have already pointed out, the way to go is by using the text control's SetValue. But here's a small runnable example:
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
open_file_dlg_btn = wx.Button(self, label="Open FileDialog")
open_file_dlg_btn.Bind(wx.EVT_BUTTON, self.on_open_file)
self.file_path = wx.TextCtrl(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(open_file_dlg_btn, 0, wx.ALL, 5)
sizer.Add(self.file_path, 1, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer)
def on_open_file(self, event):
wildcard = "Python source (*.py)|*.py|" \
"All files (*.*)|*.*"
dlg = wx.FileDialog(
self, message="Choose a file",
defaultDir='',
defaultFile="",
wildcard=wildcard,
style=wx.FD_OPEN | wx.FD_MULTIPLE | wx.FD_CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPath()
print("You chose the following file(s):")
for path in paths:
print(path)
self.file_path.SetValue(str(paths))
dlg.Destroy()
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None,
title="File Dialogs Tutorial")
panel = MyPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame()
app.MainLoop()
Try:
self.txtFeaturesPath.SetValue(pathname)
You have a few other buggy "features" in your example code, so watch out.
I realized that what I was assigning was not the value the fileDialog opens, but was instead the location in ram of the fileDialog object.
the solution was the following
value = fileDialog.Directory + "\\" + fileDialog.filename
self.txtFeaturesPath.SetValue(value)
thank you!
I've recently started using wxPython to build a GUI and I'm trying to create the following layout:
Button1 Button2 Button3
----------------------------------------
listbox | textctrl
The buttons should have a flexible width, expanding to fill the full width of the frame with a border between them (each buttons has a width (incl. border) of 1/3 frame). Their height should be set to a height in pixels.
The listbox should fill the frame vertically and have a set width of x pixels
The textctrol should be a textbox which expands to fill the width of the frame vertically as well as horizontally.
This is the code I have:
mainPanel = wx.Panel(self, -1)
parentBox = wx.BoxSizer(wx.VERTICAL)
menubar = wx.MenuBar()
filem = wx.Menu()
menubar.Append(filem, '&File')
self.SetMenuBar(menubar)
navPanel = wx.Panel(mainPanel, -1, size=(1000, 80))
navBox = wx.BoxSizer(wx.HORIZONTAL)
newSection = wx.Button(navPanel, self.ID_NEW, 'New')
renSection = wx.Button(navPanel, self.ID_RENAME, 'Rename')
dltSection = wx.Button(navPanel, self.ID_DELETE, 'Delete')
navBox.Add(newSection, 1, wx.EXPAND | wx.ALL, 5)
navBox.Add(renSection, 1, wx.EXPAND | wx.ALL, 5)
navBox.Add(dltSection, 1, wx.EXPAND | wx.ALL, 5)
navPanel.SetSizer(navBox)
contentPanel = wx.Panel(mainPanel, -1, size=(1000, 600))
contentBox = wx.BoxSizer(wx.HORIZONTAL)
self.listbox = wx.ListBox(contentPanel, -1, size=(300, 700))
self.settings = wx.TextCtrl(contentPanel, -1)
contentBox.Add(self.listbox, 0)
contentBox.Add(self.settings, 1, wx.EXPAND | wx.ALL, 5)
contentPanel.SetSizer(contentBox)
parentBox.Add(navPanel, 0, wx.EXPAND | wx.ALL, 5)
parentBox.Add(contentPanel, 1, wx.EXPAND | wx.ALL, 5)
mainPanel.SetSizer(parentBox)
Something is going wrong since what I see is not what I expect to see, anybody who can help me out?
It is working for me, I'm on win64, python 32bit 2.7.3.3, wx '2.8.12.1 (msw-unicode)'. The full working test example is:
import wx
class testframe(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'some title')
mainPanel = wx.Panel(self, -1)
parentBox = wx.BoxSizer(wx.VERTICAL)
menubar = wx.MenuBar()
filem = wx.Menu()
menubar.Append(filem, '&File')
self.SetMenuBar(menubar)
navPanel = wx.Panel(mainPanel, -1, size=(1000, 80))
navBox = wx.BoxSizer(wx.HORIZONTAL)
newSection = wx.Button(navPanel, -1, 'New')
renSection = wx.Button(navPanel, -1, 'Rename')
dltSection = wx.Button(navPanel, -1, 'Delete')
navBox.Add(newSection, 1, wx.EXPAND | wx.ALL, 5)
navBox.Add(renSection, 1, wx.EXPAND | wx.ALL, 5)
navBox.Add(dltSection, 1, wx.EXPAND | wx.ALL, 5)
navPanel.SetSizer(navBox)
contentPanel = wx.Panel(mainPanel, -1, size=(1000, 600))
contentBox = wx.BoxSizer(wx.HORIZONTAL)
self.listbox = wx.ListBox(contentPanel, -1, size=(300, 700))
self.settings = wx.TextCtrl(contentPanel, -1)
contentBox.Add(self.listbox, 0, wx.ALL, 5)
contentBox.Add(self.settings, 1, wx.EXPAND | wx.ALL, 5)
contentPanel.SetSizer(contentBox)
parentBox.Add(navPanel, 0, wx.EXPAND | wx.ALL, 5)
parentBox.Add(contentPanel, 1, wx.EXPAND | wx.ALL, 5)
mainPanel.SetSizer(parentBox)
parentBox.Fit(self)
app = wx.PySimpleApp()
app.frame = testframe()
app.frame.Show()
app.MainLoop()
Notice the addition of Fit() of the main sizer, and also 5px border added to the listbox.
Ok I have an application I am coding and am trying to get a layout simpler to this:
Notice how the text is left justified and the input boxes are all aligned, I see this in the wxPython demo code, but they all use the flexgrid sizer and I am trying to only use BoxSizers (due to them being simpler and because I only understand a little of sizers and even struggle with using BoxSizers, in 6 months I would have an even harder time)
I have tried having the input and text in two vertical sizers and then putting those in a horizontal sizer, didn't work because the text was not aligned with the inputs. I also tried doing that and also having each text, input pairing in a sizer, even worse. Any suggestions?
Here's a simple example using just BoxSizers:
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
# create the labels
lblOne = wx.StaticText(panel, label="labelOne", size=(60,-1))
lblTwo = wx.StaticText(panel, label="lblTwo", size=(60,-1))
lblThree = wx.StaticText(panel, label="lblThree", size=(60,-1))
# create the text controls
txtOne = wx.TextCtrl(panel)
txtTwo = wx.TextCtrl(panel)
txtThree = wx.TextCtrl(panel)
# create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
lineOneSizer = wx.BoxSizer(wx.HORIZONTAL)
lineTwoSizer = wx.BoxSizer(wx.HORIZONTAL)
lineThreeSizer = wx.BoxSizer(wx.HORIZONTAL)
# add widgets to sizers
lineOneSizer.Add(lblOne, 0, wx.ALL|wx.ALIGN_LEFT, 5)
lineOneSizer.Add(txtOne, 0, wx.ALL, 5)
lineTwoSizer.Add(lblTwo, 0, wx.ALL|wx.ALIGN_LEFT, 5)
lineTwoSizer.Add(txtTwo, 0, wx.ALL, 5)
lineThreeSizer.Add(lblThree, 0, wx.ALL|wx.ALIGN_LEFT, 5)
lineThreeSizer.Add(txtThree, 0, wx.ALL, 5)
mainSizer.Add(lineOneSizer)
mainSizer.Add(lineTwoSizer)
mainSizer.Add(lineThreeSizer)
panel.SetSizer(mainSizer)
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
But this is kind of messy, so here's a refactored version:
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
# create the main sizer
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
# Add a panel so it looks the correct on all platforms
self.panel = wx.Panel(self, wx.ID_ANY)
lbls = ["labelOne", "lblTwo", "lblThree"]
for lbl in lbls:
self.buildLayout(lbl)
self.panel.SetSizer(self.mainSizer)
#----------------------------------------------------------------------
def buildLayout(self, text):
""""""
lblSize = (60,-1)
lbl = wx.StaticText(self.panel, label=text, size=lblSize)
txt = wx.TextCtrl(self.panel)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(lbl, 0, wx.ALL|wx.ALIGN_LEFT, 5)
sizer.Add(txt, 0, wx.ALL, 5)
self.mainSizer.Add(sizer)
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
For most layouts other than the most basic you usually can't escape using a number of different types of sizers in order to realize your design.
Here is a good tutorial on sizers.