why is my text not aligning properly in wxPython? - python

I'm using wxPython to build a GUI and I'm trying to align some text but it's not working at all.
I'm trying align three different static text items in three places (right aligned, center aligned, and left aligned) in three seperate panels. The result that I'm getting though is that all three static text controls are aligned in the top left corners of their respective panels.
This is code I have:
self.lastText=wx.StaticText(self.textDisplayPanel1, label=self.lastWords, style=wx.ALIGN_RIGHT)
self.currentText=wx.StaticText(self.textDisplayPanel2, label=self.currentWords, style=wx.ALIGN_CENTRE)
self.nextText=wx.StaticText(self.textDisplayPanel3, label=self.nextWords, style=wx.ALIGN_LEFT)
Any ideas on how I fix this?
Thank you!
I'm running mac OSX 10.7.2 with Python 2.7.1 and wxPython 2.8.12.1

Edit: Although everything commented below works on windows, the first option would not work on, for example, Ubuntu due to maybe a bug. A previous post given in the comments indicate that the same problem is found in OSX.
In any case, the second option using vertical sizers works both in Ubuntu and windows so you could try it on OSX.
Your text has the instruction to align in the way you want with wx.ALIGN... and, in fact, it is aligned. However the size of the StaticText is not that of the panel but just the size of the text. Having restricted its position to its own size, you can not see the diference between the alignment modes.
You have two options to solve the problem:
Option 1. Expand the StaticText widget size and position your text on it
You could expand the size of your StaticText widget using its size parameter. This is a bad solution except for fixed size parents or frames you are not going to change size or reuse in other applications. If the size of the widget containing the text changes then the relative position of the text will be also modified because its size stays fixed. So it is always better to organize your widgets by means of sizers.
The proportion of the available space the widget occupies in the sizer slot is given by the second parameter in sizer.Add() (0 is minimal size, 1 is full occupation):
sizer_2.Add(self.label_1, 0, 0, 0)
To see the text aligned in the panel as you want you have to tell the StaticText to expand to all the space available:
sizer_2.Add(self.label_1, 1, 0, 0)
Here you have the relevant code:
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.panel_1 = wx.Panel(self, -1)
self.label_1 = wx.StaticText(self.panel_1, -1, "label_1", style=wx.ALIGN_RIGHT)
self.panel_2 = wx.Panel(self, -1)
self.label_2 = wx.StaticText(self.panel_2, -1, "label_2", style=wx.ALIGN_CENTRE)
self.panel_3 = wx.Panel(self, -1)
self.label_3 = wx.StaticText(self.panel_3, -1, "label_3")
self.panel_1.SetBackgroundColour(wx.Colour(0, 255, 0))
self.panel_2.SetBackgroundColour(wx.Colour(0, 255, 255))
self.panel_3.SetBackgroundColour(wx.Colour(219, 112, 147))
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2.Add(self.label_1, 1, 0, 0)
sizer_3.Add(self.label_2, 1, 0, 0)
sizer_4.Add(self.label_3, 1, 0, 0)
self.panel_1.SetSizer(sizer_2)
self.panel_2.SetSizer(sizer_3)
self.panel_3.SetSizer(sizer_4)
sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
sizer_1.Add(self.panel_2, 1, wx.EXPAND, 0)
sizer_1.Add(self.panel_3, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
Note the code is longer than needed in order to mimick your example with three panels. You obtain the same frame view using one only panel. In fact it could be simplified further not using panels and setting the StaticText directly on the sizer:
class MyFrame2(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.label_1 = wx.StaticText(self, -1, "label_1", style=wx.ALIGN_RIGHT)
self.label_2 = wx.StaticText(self, -1, "label_2", style=wx.ALIGN_CENTRE)
self.label_3 = wx.StaticText(self, -1, "label_3")
self.label_1.SetBackgroundColour(wx.Colour(127, 255, 0))
self.label_2.SetBackgroundColour(wx.Colour(0, 255, 255))
self.label_3.SetBackgroundColour(wx.Colour(219, 112, 147))
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.label_1, 1, wx.EXPAND, 0)
sizer.Add(self.label_2, 1, wx.EXPAND, 0)
sizer.Add(self.label_3, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
Option 2. Locate the widget itself in the desired position at the available space of the sizer.
You could use the position parameter of StaticText for that purpose. But this would have the same problems indicated above for the use of size. So again you want to control the geometry of your views with sizers.
You position the widget in the sizer using one of:
sizer_6.Add(self.label_5, 0, wx.ALIGN_RIGHT, 0)
or
sizer_7.Add(self.label_6, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
For some reason, for this to work you need a vertical BoxSizer (and in the same way, if you would like to use wx.ALIGN_CENTER_VERTICAL you will need an horizontal BoxSizer:
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.panel_4 = wx.Panel(self, -1)
self.label_5 = wx.StaticText(self.panel_4, -1, "label_5")
self.panel_5 = wx.Panel(self, -1)
self.label_6 = wx.StaticText(self.panel_5, -1, "label_6")
self.panel_6 = wx.Panel(self, -1)
self.label_7 = wx.StaticText(self.panel_6, -1, "label_7")
self.panel_4.SetBackgroundColour(wx.Colour(0, 255, 255))
self.panel_5.SetBackgroundColour(wx.Colour(127, 255, 0))
self.panel_6.SetBackgroundColour(wx.Colour(219, 112, 219))
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_8 = wx.BoxSizer(wx.VERTICAL)
sizer_7 = wx.BoxSizer(wx.VERTICAL)
sizer_6 = wx.BoxSizer(wx.VERTICAL)
sizer_6.Add(self.label_5, 0, wx.ALIGN_RIGHT, 0)
sizer_7.Add(self.label_6, 0, wx.ALIGN_CENTER_HORIZONTAL, 0)
sizer_8.Add(self.label_7, 0, 0, 0)
self.panel_4.SetSizer(sizer_6)
self.panel_5.SetSizer(sizer_7)
self.panel_6.SetSizer(sizer_8)
sizer_1.Add(self.panel_4, 1, wx.EXPAND, 0)
sizer_1.Add(self.panel_5, 1, wx.EXPAND, 0)
sizer_1.Add(self.panel_6, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
This option implies a combination of panels and sizers that produces a code that is more difficult to simplify than that shown for the first option.

I think that text is not aligned because the size is not set. Try:
t1=wx.StaticText(smth, label="foo", pos=(0,0), size=(200,20), style=wx.ALIGN_RIGHT)
t2=wx.StaticText(smth, label="bar", pos=(0,0), size=(200,20), style=wx.ALIGN_CENTRE)
And it will be aligned inside a 200*20 box. By default the size is "auto" i.e. (-1,-1) i.e. just enough for the text to be visible, and aligning in that box will not give visible effect.
However, this does not always work.

I also had the same problem yesterday, I use MAC OS X, wxpython 4.0.6.
At last I find out this script works for me.
And I realise that if u don't SetSizer at last, the statictext will not align at center.
My code

Related

In wxPython, how can I use sizers to left- and right-justify statictext beneath a slider?

I'm trying to make a GUI like so:
The big square is a wxGrid, the small ones are wxButtons, and they all act fine. The drawing at left is intended to be a wxSlider, with text labels "slow" and "fast" beneath each end of the slider.
So I lay out a bunch of BoxSizers, like this:
From outside in:
Blue is vertical, and contains a wxGrid and the green BoxSizer
Green is horizontal, and contains the orange BoxSizer and two buttons
Orange is vertical, and contains a wxSlider and the purple BoxSizer
Purple is horizontal, and contains two StaticTexts, with the words "slow" and "fast"
But the closest I can get it to render is this.
Notice especially how the slider is tiny, and the slow and fast labels (intended to mark the ends of the slider!) are a mess.
I've messed with alignments and expands, I've read a bunch of posts from other people complaining about BoxSliders, and I've gotten nowhere. I thought for sure I had it when I read about wx.ST_NO_AUTORESIZE, but that didn't do anything. I even rebuilt my window with wxGlade, and got the same thing, especially with the static text laid out far left.
The one thing I haven't done is specified the size of anything in pixels. It doesn't seem like any layout should require that, because who knows what size screen I'll be running on or what a reasonable number of pixels is. And if I've understood proportions correctly in sizers, I don't have to specify sizes in pixels.
But I'm out of ideas, and I haven't even found a good example, just similar veins of frustration.
How do I make my slider take up the full width of the orange boxsizer, and how do I get the slow and fast text to label the ends of the slider?
What I'm running, stripped to the layout essentials (and it's got the slider and labels problem):
import wx
import wx.grid
app = wx.App()
frame = wx.Frame(None, title="MyUnhappyLayout")
blue_sizer = wx.BoxSizer(wx.VERTICAL)
grid = wx.grid.Grid(frame)
blue_sizer.Add(grid, 6, wx.EXPAND, 8)
green_sizer = wx.BoxSizer()
blue_sizer.Add(green_sizer, 1, wx.EXPAND)
button1 = wx.Button(frame)
button2 = wx.Button(frame)
slider = wx.Slider(frame, name="Speed", value=1, minValue=1, maxValue=100)
purple_sizer = wx.BoxSizer()
label_slow = wx.StaticText(frame, label="Slow")
label_fast = wx.StaticText(frame, label="Fast")
purple_sizer.Add(label_slow, wx.ALIGN_LEFT)
purple_sizer.Add(label_fast, wx.ALIGN_RIGHT)
orange_sizer = wx.BoxSizer(wx.VERTICAL)
green_sizer.Add(orange_sizer, 2)
orange_sizer.Add(slider)
orange_sizer.Add(purple_sizer, wx.EXPAND)
green_sizer.Add(button1, 1, wx.EXPAND)
green_sizer.Add(button2, 1, wx.EXPAND)
frame.SetSizerAndFit(blue_sizer)
frame.Show()
app.MainLoop()
There is a "built-in" option for showing min and max labels for a slider: use wxSL_MIN_MAX_LABELS when creating it (unless you are using wxWidgets older than 2.9.1).
Otherwise, for your specific sizer layout (it might be easier to review if you create each sizer just before using it):
purple_sizer = wx.BoxSizer()
purple_sizer.Add(label_slow)
purple_sizer.AddStretchSpacer()
purple_sizer.Add(label_fast)
orange_sizer = wx.BoxSizer(wx.VERTICAL)
# when adding to a sizer, the second argument would be proportion;
# use SizerFlags to avoid mistakenly skipping an argument
orange_sizer.Add(slider, wx.SizerFlags().Expand())
orange_sizer.Add(purple_sizer, wx.SizerFlags().Expand())
green_sizer = wx.BoxSizer()
green_sizer.Add(orange_sizer, wx.SizerFlags(1)) # no need for proportion=2, 1 should do
green_sizer.Add(button1) # you probably meant to enlarge the slider, not the buttons
green_sizer.Add(button2)
blue_sizer = wx.BoxSizer(wx.VERTICAL)
blue_sizer.Add(grid, wx.SizerFlags(1).Expand().Border(8)) # no need for proportion=6, 1 should do
blue_sizer.Add(green_sizer, wx.SizerFlags().Expand())
As #VZ has pointed out to me, the old Align within a boxsizer in it's orientation, never worked but now throws an error in newer iterations of wxWidgets.
Now, the old way to achieve the same result, is to insert dummy entries into the sizer and ask for them to be expanded.
For the new way see the answer from #catalin.
Some of the changes to your code are cosmetic to help me understand what is what, by explicit rather than implicit with the defaults for widgets.
import wx
import wx.grid
app = wx.App()
frame = wx.Frame(None, title="MyUnhappyLayout")
blue_sizer = wx.BoxSizer(wx.VERTICAL)
grid = wx.grid.Grid(frame)
blue_sizer.Add(grid, 6, wx.EXPAND, 8)
green_sizer = wx.BoxSizer(wx.HORIZONTAL)
blue_sizer.Add(green_sizer, 1, wx.EXPAND)
button1 = wx.Button(frame)
button2 = wx.Button(frame)
slider = wx.Slider(frame, name="Speed", value=1, minValue=1, maxValue=100)
purple_sizer = wx.BoxSizer(wx.HORIZONTAL)
label_slow = wx.StaticText(frame, label="Slow")
label_fast = wx.StaticText(frame, label="Fast")
purple_sizer.Add(label_slow, 0, 0, 0)
purple_sizer.Add((-1,-1), 1, wx.EXPAND, 0)
purple_sizer.Add(label_fast, 0, 0, 0)
orange_sizer = wx.BoxSizer(wx.VERTICAL)
orange_sizer.Add(slider, 0, wx.EXPAND)
orange_sizer.Add(purple_sizer, 0, wx.EXPAND)
green_sizer.Add(orange_sizer, 2, 0, 0)
green_sizer.Add(button1, 1, wx.EXPAND)
green_sizer.Add(button2, 1, wx.EXPAND)
frame.SetSizerAndFit(blue_sizer)
frame.Show()
app.MainLoop()
Note:
This is the dummy entry:
purple_sizer.Add((-1,-1), 1, wx.EXPAND, 0)

wx python BoxSizer not expanding to window plus an odd blank gap at top of GUI

I am having some issues properly expanding my sizers. I have added two sub panels which I was hoping would solve my issue, but it seems to have made it worse. What I am hoping to do is have top_panel expand to the extents of the width of the main panel. vbox_top_right should expand to fill the rest of hbox_top. The bottom_panel should then expand both horizontally and vertically to fill in the rest of the space of the main panel. None of this is happening.
Once I split everything up into two sub panels, I am now having an issues where I have a large blank space up top. Also, my bottom_panel does not seem to be expanding anywhere. I am also not sure if I am using SetSizerAndFit correctly because I haven't seen anywhere mentioning the use of it on multiple panels. Am I only supposed to be applying it to the main panel?
Note that I am forcing use of wx 3.0. I have 2.8 and 3.0 installed and had issues with wx.StaticBoxSizer with 2.8. I know this likely has nothing to do with my issue, just the code won't work correctly if you are trying it in 2.8.
CODE:
import wxversion
wxversion.select('3.0')
import wx
import os
import sys
VERSION = '1.0.0'
class GUI(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=title, pos=wx.DefaultPosition,
size=wx.Size(1280, 768), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
menu_bar = wx.MenuBar()
file_menu = wx.Menu()
self.cwd = os.getcwd()
# Quit code
file_item = file_menu.Append(wx.ID_EXIT, 'Quit', 'Quit Application')
menu_bar.Append(file_menu, '&File')
self.SetMenuBar(menu_bar)
# Add Main panel
self.panel = wx.Panel(self)
# Add Top and Bottom Panels
self.top_panel = wx.Panel(self.panel)
self.bottom_panel = wx.Panel(self.panel)
# Create horizontal and vertical boxes
self.hbox_main = wx.BoxSizer(wx.HORIZONTAL)
self.vbox_main = wx.BoxSizer(wx.VERTICAL)
self.hbox_top = wx.BoxSizer(wx.HORIZONTAL)
self.vbox_top_left = wx.BoxSizer(wx.VERTICAL)
self.vbox_top_right = wx.BoxSizer(wx.VERTICAL)
####################################################
# TOP
####################################################
##########################
# TOP LEFT
##########################
# List box text
self.lbl_filter = wx.StaticText(self.top_panel, wx.ID_ANY,
u"Select all cases to apply file to",
wx.DefaultPosition, wx.DefaultSize, 0)
self.lbl_filter.Wrap(-1)
self.vbox_top_left.Add(self.lbl_filter, 0, wx.EXPAND)
# The list box that all the file names are in
self.list_box = wx.CheckListBox(self.top_panel, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(300, 300),
choices=[], style=wx.LB_HSCROLL|wx.LB_MULTIPLE|wx.LB_NEEDED_SB|wx.LB_SORT)
self.vbox_top_left.Add(self.list_box, 0, wx.EXPAND, 5)
# List box filter text
self.lbl_filter = wx.StaticText(self.top_panel, wx.ID_ANY,
u"Case filter (separate wildcards with a comma and choose filter logic (AND or OR)\n(i.e. HS, 2022 with AND selected will modify all 2022 HS cases)",
wx.DefaultPosition, wx.DefaultSize, 0)
self.lbl_filter.Wrap(-1)
self.vbox_top_left.Add(self.lbl_filter, 0, wx.EXPAND)
# List box filter
self.hbox_filter = wx.BoxSizer(wx.HORIZONTAL)
self.txt_filter = wx.TextCtrl(self.top_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
self.txt_filter.SetMinSize(wx.Size(300, -1))
self.hbox_filter.Add(self.txt_filter, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5)
# List box radio buttons
logic_choices = [u"AND", u"OR"]
self.rdo_logic = wx.RadioBox(self.top_panel, wx.ID_ANY, u"Filter Logic", wx.DefaultPosition, wx.DefaultSize,
logic_choices, 1, wx.RA_SPECIFY_ROWS)
self.rdo_logic.SetSelection(0)
self.hbox_filter.Add(self.rdo_logic, 0, wx.EXPAND, 5)
# Add filter stuff to vbox_top
self.vbox_top_left.Add(self.hbox_filter, 0, wx.EXPAND)
# Add top components to hbox
self.hbox_top.Add(self.vbox_top_left, 0, wx.EXPAND)
##########################
# TOP RIGHT
##########################
# Add warning text
self.lbl_warning = wx.StaticText(self.top_panel, wx.ID_ANY,
u"*** WARNING *** HELLO WORLD ",
wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTER_HORIZONTAL)
self.lbl_warning.Wrap(-1)
self.vbox_top_right.Add(self.lbl_warning, 0, wx.EXPAND, 5)
# Radio buttons for software choice
rdo_choices = [u"App 1", u"App 2", u"App 3"]
self.rdo_software = wx.RadioBox(self.top_panel, wx.ID_ANY, u"Select Software", wx.DefaultPosition,
wx.DefaultSize, rdo_choices, 1, wx.RA_SPECIFY_COLS)
self.rdo_software.SetSelection(0)
self.vbox_top_right.Add(self.rdo_software, 0, wx.EXPAND, 5)
# Checkbox for archive
self.cb_archive = wx.CheckBox(self.top_panel, wx.ID_ANY, u"Archive files before running", wx.DefaultPosition,
wx.DefaultSize, 0)
self.vbox_top_right.Add(self.cb_archive, 0, wx.EXPAND, 5)
# Checkbox for saving
self.cb_save = wx.CheckBox(self.top_panel, wx.ID_ANY, u"Save files after running", wx.DefaultPosition,
wx.DefaultSize, 0)
self.vbox_top_right.Add(self.cb_save, 0, wx.EXPAND, 5)
# Folder selection label
self.lbl_cases = wx.StaticText(self.top_panel, wx.ID_ANY, u"Select Folder With Cases", wx.DefaultPosition,
wx.DefaultSize, 0)
self.lbl_cases.Wrap(-1)
self.vbox_top_right.Add(self.lbl_cases, 0, wx.EXPAND, 5)
# Add Folder selection
self.hbox_folder = wx.BoxSizer(wx.HORIZONTAL)
self.txt_cases = wx.TextCtrl(self.top_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
self.txt_cases.SetMinSize(wx.Size(400, -1))
self.hbox_folder.Add(self.txt_cases, 0, wx.EXPAND, 5)
# Folder select button
self.btn_cases = wx.Button(self.top_panel, wx.ID_ANY, u"Case Folder", wx.DefaultPosition, wx.DefaultSize, 0)
self.hbox_folder.Add(self.btn_cases, 0, wx.EXPAND, 5)
# Add to sizer
self.vbox_top_right.Add(self.hbox_folder, 1, wx.SHAPED, 5)
self.hbox_top.Add(self.vbox_top_right, 0, wx.EXPAND, 5)
self.vbox_main.Add(self.hbox_top, 0, wx.EXPAND)
####################################################
# BOTTOM
####################################################
self.bottom_box = wx.StaticBox(self.bottom_panel, label='Progress Output')
self.hbox_output = wx.StaticBoxSizer(self.bottom_box, wx.HORIZONTAL)
self.txt_output = wx.TextCtrl(self.bottom_box, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
wx.TE_MULTILINE | wx.TE_READONLY)
# Put it all together
self.vbox_main.Add(self.top_panel, 1, wx.EXPAND)
self.vbox_main.Add(self.bottom_panel, 1, wx.EXPAND)
self.top_panel.SetSizerAndFit(self.hbox_top)
self.bottom_panel.SetSizerAndFit(self.hbox_output)
self.panel.SetSizerAndFit(self.vbox_main)
self.Centre()
self.Layout()
if __name__ == '__main__':
app = wx.App(0)
MainFrame = GUI(None, title='Batch Apply %s' % VERSION)
app.SetTopWindow(MainFrame)
MainFrame.Show()
app.MainLoop()
Here is a crude drawing of the GUI
Here is what I am getting:
The main frame has only one child called panel. So, this only child of a frame (not of another kind of window) will fit it's parent's client area when it gets resized. Good. It would'nt be true in case of more than one child.
You have two more panels, as children of panel. This would be good if, for example, you want different background colors. If not, that's not necessary, but there's nothing wrong with these superfluous panels.
There are two different regions: top (not resizable in vertical direction) and bottom (resizable). This would require two sub-sizers of the 'main sizer' that handles the layout of the contents of panel. But you are using two panels for these regions, so better let's use a main sizer (I'll use vbox_main) for the layout inside panel of these two panels. The layout of the contents of a sub-panel will be handled by a sizer.
In the 'top' region there are also two different areas; so another two sub-sizers. Your design is correct.
vbox_top_left wants the controls it manages (children of top_panel) to fit in the available space. Because this is a vertical sizer we need:
1) A child can change vertical size: use proportion=1
2) A child can change horizontal size: use wx.EXPAND flag.
3) If would be good to add vertical resizable spacers between some controls.
Apply similar criteria for the controls size-handled by vbox_top_right (with children of top_panel too).
Bottom area is peculiar because you want a rectangle to be drawn around a label and a text control. For this, we need a special sizer: StaticBoxSizer. It's peculiar in the sense that the controls it handles are children not of a panel, but of the underlaying wx.StaticBox. See the upper docs link for an example and more explanations.
self.hbox_output = wx.StaticBoxSizer(wx.HORIZONTAL, self.bottom_panel)
self.hbox_output.Add(wx.StaticText(self.hbox_output.GetStaticBox(), ....), ...)
self.hbox_output.Add(wx.TextCtrl(self.hbox_output.GetStaticBox(), ....), 1, wx.EXPAND, 5)
To add children to this sizer follow the same criteria as for 'top' area. There's nothing distinct here.
Now, behaviours of the sizers (I skip other sub-sizers you use):
# No vertical nor horizontal expanding
# self.hbox_top.Add(self.vbox_top_left, 0, wx.EXPAND) <<== not what expected
self.hbox_top.Add(self.vbox_top_left, 0)
# Only horizontal expanding
# self.hbox_top.Add(self.vbox_top_right, 0, wx.EXPAND, 5) <<== not what expected
self.hbox_top.Add(self.vbox_top_right, 1, 0, 5)
The last job is to bind panels and sizers:
self.top_panel.SetSizer(self.hbox_top)
self.bottom_panel.SetSizer(self.hbox_output)
# Top panel expands only in horizontal
self.vbox_main.Add(self.top_panel, 0, wx.EXPAND)
# Bottom part expands in both directions
self.vbox_main.Add(self.bottom_panel, 1, wx.EXPAND)
self.panel.SetSizerAndFit(self.vbox_main)
self.Centre()
self.Layout()
Using a single panel is easier. I've used your two sub-panels just to demostrate how it works: Main sizer handles sub-panels, each panel uses a sizer for its sizers that handle children.

Cannot set the size of the wxPython CustomTreeCtrl

I have created a small test form for trying out the custom tree control. But I cannot set the size of the tree. I want a fixed width on the left and a variable width on the right so I used a box sizer to split the form up. I have placed the tree in the left part with a fixed width of 300. A text box is in the right part that takes up the rest of the space. So far so good... but if I change the size of the tree control to 400 or 500, I do not see the tree get any bigger. If I use the normal tree control it works.
I would like to use the CustomTreeCtrl because of the check boxes. The normal tree control does not have check boxes for the items.
Here the code of the test form:
import wx
from wx.lib.agw.customtreectrl import CustomTreeCtrl
class TestFrame(wx.Frame):
def __init__(self):
super(TestFrame, self).__init__(None, -1, "Test frame", size=(800, 600), pos=(200, 100))
panel = wx.Panel(self, -1)
textBox = wx.TextCtrl(panel, -1, "This will show the item's content", style=wx.TE_MULTILINE)
# This one works as expected
#tree = wx.TreeCtrl(panel, -1, size=(300, -1), style=wx.SUNKEN_BORDER)
# This one does not seem to have the correct size...
tree = CustomTreeCtrl(panel, -1, size=(300, -1), style=wx.SUNKEN_BORDER)
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(tree, 0, wx.EXPAND | wx.ALL, 5)
box.Add(textBox, 1, wx.EXPAND | wx.ALL, 5)
panel.SetSizer(box)
# Show the frame
app = wx.App(redirect=False)
frame = TestFrame()
frame.Show()
app.MainLoop()
I tried calling the Layout() method and calling the SetBestFittingSize() method of the panel or box sizer, but nothing seems to work.
I am running this on Ubuntu with Python 2.7 and wxPython 2.8.12.1.
Thanks in advance!

wxPython Nested Panel and Sizers

Started learning wxPython so I could make an application. I'm having issues with nested sizers in particular.
class browser_mainPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent)
self.toolbar()
self.searchBar = wx.SearchCtrl(self)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer2 = wx.BoxSizer(wx.VERTICAL)
main_sizer2.Add(self.toolBar, 0, wx.EXPAND, 5)
main_sizer2.Add(self.searchBar, 0, wx.EXPAND, 5)
main_sizer.Add(main_sizer2, wx.EXPAND)
tree_panel = wx.Panel(self)
tree_panel.SetBackgroundColour(wx.BLACK)
entry_panel = wx.Panel(self)
entry_panel.SetBackgroundColour(wx.GREEN)
main_sizer3 = wx.BoxSizer(wx.HORIZONTAL)
main_sizer3.Add(tree_panel, 0, wx.EXPAND, 5)
main_sizer3.Add(entry_panel, 0, wx.EXPAND, 5)
main_sizer2.Add(main_sizer3, wx.EXPAND)
self.SetSizer(main_sizer)
Right, so the problem is that the two panels in main_sizer3 aren't expanding out as I want them to. Here's a picture.
What I want is for the two panels to expand to the rest of the panel with the black portion
being smaller than the green panel width-wise. Can't find a solution for the life of me.
I plan on making these two panels have their own special instances because there's going to be stuff happening in them but for now, I'm looking to implement them as simply as possible before I start getting into the details.
You forgot a few proportions:
# to use the last parameter (border), you have to
# specify which border(s) to use in the flag parameter:
# wx.TOP, wx.BOTTOM, wx.LEFT, wx.RIGHT, a combination
# of them, or wx.ALL
main_sizer2.Add(self.toolBar, 0, wx.EXPAND|wx.BOTTOM, 5)
main_sizer2.Add(self.searchBar, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
# proportion missing:
main_sizer.Add(main_sizer2, 1, wx.EXPAND)
# set the green panel to twice the size of the black one
main_sizer3.Add(tree_panel, 1, wx.EXPAND|wx.RIGHT, 5)
main_sizer3.Add(entry_panel, 2, wx.EXPAND)
# and another proportion missing:
main_sizer2.Add(main_sizer3, 1, wx.EXPAND|wx.ALL, 5)
Furthermore, your main_sizer only contains one entry which makes it superfluous. Also try to give your sizers somewhat meaningful names to make it easier to read.
Last but not least, if you want the user to be able to dynamically resize the proportions of the two panels (tree and entry), you
can use a wx.SplitterWindow:
# ...
layout = wx.BoxSizer(wx.VERTICAL)
layout.Add(self.toolBar, 0, wx.EXPAND|wx.BOTTOM, 5)
layout.Add(self.searchBar, 0, wx.EXPAND|wx.LEFT|wx.RIGHT,5)
splitter = wx.SplitterWindow(self,style=wx.SP_LIVE_UPDATE)
tree_panel = wx.Panel(splitter)
tree_panel.SetBackgroundColour(wx.BLACK)
entry_panel = wx.Panel(splitter)
entry_panel.SetBackgroundColour(wx.GREEN)
splitter.SplitVertically(tree_panel,entry_panel)
splitter.SetMinimumPaneSize(50)
layout.Add(splitter,1,wx.EXPAND|wx.ALL,5)
self.SetSizer(layout)
You are giving wrong parameters to the Add method in several lines of code.
The second parameter of Add is the proportion of the widget that should be an integer (usually 1, fill as you can keeping proportion, or 0, maintain your minimum size). You missed it in some lines. Actually, this parameter took the value of wx.EXPAND that in fact is a constant used for the third parameter, that also got lost as a side-effect.
If you want a Panel to be smaller than the other (50% for example) you can give values 1 and 2 respectively for the smaller and the bigger panels.
This works in Python 3.2 with Phoenix:
main_sizer.Add(main_sizer2, 1, wx.EXPAND)
tree_panel = wx.Panel(self)
tree_panel.SetBackgroundColour(wx.BLACK)
entry_panel = wx.Panel(self)
entry_panel.SetBackgroundColour(wx.GREEN)
main_sizer3 = wx.BoxSizer(wx.HORIZONTAL)
main_sizer3.Add(tree_panel, 1, wx.EXPAND, 5) #smaller
main_sizer3.Add(entry_panel, 2, wx.EXPAND, 5) #bigger
main_sizer2.Add(main_sizer3, 1, wx.EXPAND)
self.SetSizer(main_sizer)

wxpython HtmlWindow: show full content?

How can I display the full content of a HtmlWindow? I have some HtmlWindows in a scrollable panel and I want to see the full text in these windows. I have tried setting the proportion to 1 and the style to wx.EXPAND, but that doesn't work.
Currently it looks like this:
But I want to see in the windows the full text:
some long text
with multiple lines
and another line
Sample code:
import wx
from wx import html
from wx.lib.scrolledpanel import ScrolledPanel
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.notebook_1 = wx.Notebook(self, -1, style=0)
self.notebook_1_pane_1 = ScrolledPanel(self.notebook_1, -1)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.VERTICAL)
for _ in xrange(10):
self.html = html.HtmlWindow(self.notebook_1_pane_1)
self.html.SetPage('some long text<br />with multiple lines<br />' \
'and another line')
self.html.SetBorders(0)
self.sizer_3_staticbox = wx.StaticBox(self.notebook_1_pane_1, -1,
'a')
sizer_3 = wx.StaticBoxSizer(self.sizer_3_staticbox, wx.VERTICAL)
sizer_3.Add(self.html, 1, wx.EXPAND, 0)
sizer_2.Add(sizer_3, 0, wx.EXPAND, 0)
self.notebook_1_pane_1.SetSizer(sizer_2)
self.notebook_1.AddPage(self.notebook_1_pane_1, "tab1")
sizer_1.Add(self.notebook_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
self.notebook_1_pane_1.SetScrollRate(20, 20)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame_1 = MyFrame(None, -1, size=(400, 300))
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()
You need to give sizer_2 a proportion of 1 or more as well.
sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
This makes the sizer_3 element stretch appropriately too. Otherwise, it only stretches in one direction. I would reduce the number of HTMLWindows you're putting in too unless you're using a high resolution monitor. Expanding this out so that all the text was visible in all the Windows is difficult on these low res wide screens.

Categories

Resources