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)
Related
I am trying to plot 1D txt files in a part of the window created using wxpython. For this purpose, a directory selection tool was included which lists all txt files. Now, I would like to select a txt file and plot it in a panel on the right side.
Further, I am thinking to implement a button that does some operations on the data and replot again.
What I have tried is this :
import os
import wx
import numpy as np
import matplotlib
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
class mainFrame (wx.Frame):
def __init__(self):
super().__init__(None, id=wx.ID_ANY, title=u" test ",
size=wx.Size(854, 698),
style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.Size(600, -1), wx.DefaultSize)
sizer = wx.BoxSizer(wx.VERTICAL)
self.panel = MainPanel(self, style=wx.TAB_TRAVERSAL)
self.Layout()
sizer.Add(self.panel, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
self.Layout()
self.Centre()
# Connect Events
self.panel.dirPicker.Bind(wx.EVT_DIRPICKER_CHANGED, self.dirPickerOnDirChanged)
self.panel.listBox.Bind(wx.EVT_LISTBOX, self.listBoxOnListBox)
# ------------ Add widget program settings
# ------------ Call Populates
self.Show()
# Virtual event handlers, override them in your derived class
def dirPickerOnDirChanged(self, event):
self.FilePath = event.GetPath()
self.populateFileList()
def populateFileList(self):
self.panel.listBox.Clear()
allFiles = os.listdir(self.FilePath)
for file in allFiles:
if file.endswith('.txt'):
self.panel.listBox.Append(file)
def listBoxOnListBox(self, event):
try:
selected_file = event.GetString()
file_address = os.path.join(self.FilePath, selected_file)
# load file
data = np.loadtxt(file_address)
# select the first column
if isinstance(data, np.ndarray):
print("\tdata is np.array")
dim = data.ndim
if dim == 2:
input1D = data[:, 0]
else:
input1D = data
print(input1D.shape)
# plot here
else:
print("\tdata is not np.array")
except: # Do not use bare except
print("Some error.")
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.FONT_11 = wx.Font(11, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL, False, "Consolas")
self.FONT_12 = wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL, False, wx.EmptyString)
self.FONT_13 = wx.Font(13, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL, False, wx.EmptyString)
self.FONT_14 = wx.Font(14, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_BOLD, False, "Consolas")
self.FONT_16 = wx.Font(16, wx.FONTFAMILY_SCRIPT, wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_BOLD, False, wx.EmptyString)
sizer = wx.BoxSizer(wx.VERTICAL)
quick_display = self._quick_display()
directory_sizer = self._directory_sizer()
list_box_sizer = self._list_box_sizer()
self.text_details = self._detail_input()
details_sizer = self._details_sizer()
status_sizer = self._status_sizer()
message_sizer = wx.BoxSizer(wx.VERTICAL)
message_sizer.Add(details_sizer, 1, wx.EXPAND, 5)
message_sizer.Add(status_sizer, 1, wx.EXPAND, 5)
sizer.Add(quick_display, 0, wx.EXPAND, 0)
sizer.Add(directory_sizer, 0, wx.EXPAND, 0)
sizer.Add(list_box_sizer, 1, wx.EXPAND, 0)
sizer.Add(message_sizer, 1, wx.EXPAND, 5)
self.SetSizer(sizer)
def _quick_display(self):
quick_display = wx.StaticText(self, label=u"quick display")
quick_display.Wrap(-1)
quick_display.SetFont(self.FONT_16)
return quick_display
def _directory_sizer(self):
sbSizerDir = wx.StaticBoxSizer(wx.StaticBox(self, label=u" working directory"))
self.dirPicker = wx.DirPickerCtrl(sbSizerDir.GetStaticBox(), message=u"Select a folder")
sbSizerDir.Add(self.dirPicker, 0, wx.ALL | wx.EXPAND, 5)
return sbSizerDir
def _list_box(self):
listBoxChoices = []
self.listBox = wx.ListBox(self, size=wx.Size(300, -1), choices=listBoxChoices)
self.listBox.SetMinSize(wx.Size(250, -1))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.listBox, 1, wx.ALL, 10)
return sizer
def _plot_sizer(self):
self.panelPlot = PlotPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panelPlot, 1, wx.EXPAND | wx.ALL, 5)
return sizer
def _list_box_sizer(self):
file_list_sizer = self._list_box()
bSizer_plot = self._plot_sizer()
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(file_list_sizer, 1, wx.EXPAND, 0)
sizer.Add(bSizer_plot, 1, wx.EXPAND, 5)
bSizerSplitHor = wx.BoxSizer(wx.HORIZONTAL)
bSizerSplitHor.Add(sizer, 1, wx.EXPAND, 2)
bSizerSplit = wx.BoxSizer(wx.VERTICAL)
bSizerSplit.Add(bSizerSplitHor, 1, wx.EXPAND, 0)
return bSizerSplit
def _detail_label(self):
detail_label = wx.StaticText(self, label="Details")
detail_label.Wrap(-1)
detail_label.SetFont(self.FONT_14)
return detail_label
def _detail_input(self):
text_details = wx.TextCtrl(self, size=wx.Size(250, -1))
text_details.SetFont(self.FONT_11)
return text_details
def _button_sizer(self):
self.button = wx.Button(self, label=u"do some operation")
self.button.SetFont(self.FONT_13)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.button, 0, wx.ALL, 5)
return sizer
def _details_sizer(self):
detail_label = self._detail_label()
button_sizer = self._button_sizer()
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(detail_label, 0, wx.ALL, 5)
sizer.Add(self.text_details, 1, wx.EXPAND, 5)
sizer.Add(button_sizer, 1, wx.EXPAND, 5)
return sizer
def _status_sizer(self):
self.staticline3 = wx.StaticLine(self)
self.status_label = wx.StaticText(self, label=u"Status bar")
self.status_label.Wrap(-1)
self.status_label.SetFont(self.FONT_12)
self.staticline4 = wx.StaticLine(self)
self.textCtrl_status = wx.TextCtrl(self)
self.textCtrl_status.SetFont(self.FONT_11)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.staticline3, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(self.status_label, 0, wx.ALL, 5)
sizer.Add(self.staticline4, 0, wx.EXPAND | wx.ALL, 5)
sizer.Add(self.textCtrl_status, 0, wx.ALL | wx.EXPAND, 5)
status_sizer = wx.BoxSizer(wx.VERTICAL)
status_sizer.Add(sizer, 1, wx.EXPAND, 5)
return status_sizer
class PlotPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.SetMinSize(wx.Size(100, -1))
if __name__ == "__main__":
app = wx.App(False)
frame = mainFrame()
app.MainLoop()
This creates a window as follows :
The right portion is assigned as a panel, and I not sure how to place the matplotlib plot in it. Thank you.
There are several good questions on SE probing this topic, such as Q1 and Q2; however, most are limited to the plot being shown on the main window.
wxGlade includes some wxPython / matplotlib examples. Use these as starting point.
https://github.com/wxGlade/wxGlade/tree/master/examples
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 a screen which has 6 grids as follows:
I'm adding a 7th grid.
This causes the screen to look like:
however I want the screen to be:
I tried to do it with flexgrid but it's not working.
This is my code:
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.AddSpacer(10)
sizer_4 = wx.BoxSizer(wx.VERTICAL)
sizer_4.Add(self.grid1, 1, wx.EXPAND, 0)
sizer_4.AddSpacer(20)
sizer_4.Add(self.grid4, 1, wx.EXPAND, 0)
sizer_4.AddSpacer(20)
sizer_4.Add(self.grid7, 1, wx.EXPAND, 0)
sizer_5 = wx.BoxSizer(wx.VERTICAL)
sizer_5.Add(self.grid2, 1, wx.EXPAND, 0)
sizer_5.AddSpacer(20)
sizer_5.Add(self.grid5, 1, wx.EXPAND, 0)
sizer_6 = wx.BoxSizer(wx.VERTICAL)
sizer_6.Add(self.grid3, 1, wx.EXPAND, 0)
sizer_6.AddSpacer(20)
sizer_6.Add(self.grid6, 1, wx.EXPAND, 0)
sizer_3=wx.BoxSizer(wx.HORIZONTAL)
sizer_3.AddSpacer(20)
sizer_3.Add(sizer_4, 1, wx.EXPAND, 0)
sizer_3.AddSpacer(20)
sizer_3.Add(sizer_5, 1, wx.EXPAND, 0)
sizer_3.AddSpacer(20)
sizer_3.Add(sizer_6, 1, wx.EXPAND, 0)
sizer_1= wx.BoxSizer(wx.VERTICAL)
sizer_1.AddSpacer(10)
sizer_1.Add(sizer_2)
sizer_1.AddSpacer(20)
sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.Layout()
What can I do?
I don't like the grid sizers because I find them pretty confusing. So I typically take something like this and draw boxes around the various groups. The boxes represent BoxSizers. Once I have that done, I know what to do and write my code accordingly. Here's how I would lay this out:
import wx
########################################################################
class GenericPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent, color):
"""Constructor"""
wx.Panel.__init__(self, parent, size=(200, 100))
self.SetBackgroundColour(color)
########################################################################
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent)
left_sizer = wx.BoxSizer(wx.VERTICAL)
for i in range(3):
panel = GenericPanel(self, 'red')
left_sizer.Add(panel, 0, wx.ALL, 5)
top_right_sizer = wx.BoxSizer(wx.HORIZONTAL)
for i in range(2):
panel = GenericPanel(self, 'green')
top_right_sizer.Add(panel, 0, wx.ALL, 5)
bottom_right_sizer = wx.BoxSizer(wx.HORIZONTAL)
for i in range(2):
panel = GenericPanel(self, 'blue')
bottom_right_sizer.Add(panel, 0, wx.ALL, 5)
stack_sizer = wx.BoxSizer(wx.VERTICAL)
stack_sizer.Add(top_right_sizer)
stack_sizer.Add(bottom_right_sizer)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(left_sizer)
main_sizer.Add(stack_sizer)
main_sizer.AddStretchSpacer(prop=1)
self.SetSizer(main_sizer)
########################################################################
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, title='Boxes', size=(700,400))
panel = MainPanel(self)
self.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame()
app.MainLoop()
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.
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.