Padding in Panel and static text wrap in wxpython - python

I would like to have a layout something like this
There is a Main Panel just inside the frame with blank padding in the left and right which another Sub Panel located in the middle. A Static Text element located at the top of Sub Panel and it should wrap properly when changing the window size.
My code snippet listed as following
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent)
self.hsizer = wx.BoxSizer()
self.hsizer.AddStretchSpacer()
self.panel = wx.Panel(self)
self.panel.SetSize((350, -1))
self.vsizer = wx.BoxSizer(wx.VERTICAL)
label = (
"This is a long scentence that I want it wrapped properly, "
"but it doesn't seem to work at work. "
"I prefer if you guys can give any sugeestions or help. "
"For Long Long Long Long Long scentence."
)
style = wx.ALIGN_LEFT
self.static_text = wx.StaticText(self, label=label, style=style)
self.vsizer.Add(self.static_text, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
self.static_text.Wrap(self.panel.Size[0])
self.static_text.SetAutoLayout(True)
self.panel.SetSizer(self.vsizer)
self.hsizer.Add(self.panel, flag=wx.ALIGN_CENTER)
self.hsizer.AddStretchSpacer()
self.SetSizer(self.hsizer)
self.Layout()
print self.Size
print self.panel.Size
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame(None)
sizer = wx.BoxSizer()
sizer.Add(MyPanel(frame), flag=wx.EXPAND)
frame.SetSizer(sizer)
frame.Show()
app.MainLoop()
Currently, not only the Sub Panel is not located in the middle, but also the text in static text doesn't wrap properly when changing the window size. Any suggestions to make it work?

It is often helpful to set some background colours while trying to implement a layout with sizers, that way it's easy to visualize where the boundaries are, and how they behave while resizing things. Another helpful tool is the Widget Inspection Tool. For example:
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent)
self.SetBackgroundColour('pink')
self.hsizer = wx.BoxSizer()
self.hsizer.AddStretchSpacer()
self.panel = wx.Panel(self)
self.panel.SetSize((350, -1))
self.panel.SetBackgroundColour('green')
self.vsizer = wx.BoxSizer(wx.VERTICAL)
label = (
"This is a long scentence that I want it wrapped properly, "
"but it doesn't seem to work at work. "
"I prefer if you guys can give any sugeestions or help. "
"For Long Long Long Long Long scentence."
)
style = wx.ALIGN_LEFT
self.static_text = wx.StaticText(self, label=label, style=style)
self.static_text.SetBackgroundColour('yellow')
self.vsizer.Add(self.static_text, flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
self.static_text.Wrap(self.panel.Size[0])
self.static_text.SetAutoLayout(True)
self.panel.SetSizer(self.vsizer)
self.hsizer.Add(self.panel, flag=wx.ALIGN_CENTER)
self.hsizer.AddStretchSpacer()
self.SetSizer(self.hsizer)
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame(None)
frame.SetBackgroundColour('sky blue')
sizer = wx.BoxSizer()
sizer.Add(MyPanel(frame), flag=wx.EXPAND)
frame.SetSizer(sizer)
frame.Show()
import wx.lib.inspection
wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
After running that we can see that things don't really match your sketch of the layout, that things like the text don't change size or position when the frame is resized, and that the MyPanel (the pink one) is also not resizing to fill the frame. Also, it appears from the code that you intend the text to be the child of the green panel (self.panel) but looking at the colours at runtime it obviously is not. Looking again at the code we see that it is being created with self as the parent instead of self.panel.
So after a few more tweaks to address those issues, we end up with this code:
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
super(MyPanel, self).__init__(parent)
self.SetBackgroundColour('pink')
self.hsizer = wx.BoxSizer()
self.hsizer.AddStretchSpacer()
self.panel = wx.Panel(self)
self.panel.SetSize((350, -1))
self.panel.SetBackgroundColour('green')
self.vsizer = wx.BoxSizer(wx.VERTICAL)
label = (
"This is a long scentence that I want it wrapped properly, "
"but it doesn't seem to work at work. "
"I prefer if you guys can give any sugeestions or help. "
"For Long Long Long Long Long scentence."
)
style = wx.ALIGN_LEFT
self.static_text = wx.StaticText(self.panel, label=label, style=style)
self.static_text.SetBackgroundColour('yellow')
self.vsizer.Add(self.static_text,
flag=wx.EXPAND | wx.ALL | wx.ALIGN_TOP, border=5)
self.static_text.Wrap(self.panel.Size[0])
self.panel.SetSizer(self.vsizer)
self.hsizer.Add(self.panel, 1, flag=wx.EXPAND)
self.hsizer.AddStretchSpacer()
self.SetSizer(self.hsizer)
if __name__ == '__main__':
app = wx.App()
frame = wx.Frame(None)
frame.SetBackgroundColour('sky blue')
sizer = wx.BoxSizer()
sizer.Add(MyPanel(frame), 1, flag=wx.EXPAND)
frame.SetSizer(sizer)
frame.Show()
import wx.lib.inspection
wx.lib.inspection.InspectionTool().Show()
app.MainLoop()
Finally, if you want the text to be rewrapped when the size gets narrower than 350 then you'll need to do something like catch EVT_SIZE events and call Wrap again with a different size when needed.

Related

Fitting a wxWindows frame to a grid

In my wxPython GUI app I want to show a dialog with a grid on it and just two buttons below that grid. The grid may be initialised with a number of rows, which is not known in advance. My goal is to automatically let the dialog window become as large as necessary in order to include the whole grid (i.e. I would like to avoid the scrollbars of the grid).
However, I can't get that to work, even when using sizers and the wx.EXPAND flag. Any ideas what I am doing wrong here? This is a fully working example of my problem:
import wx
import wx.grid
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)
# Keras model to product / pipe type mapping grid
logtab = wx.grid.Grid(self.panel)
logtab.CreateGrid(25, 3)
logtab.SetColLabelValue(0, "One")
logtab.SetColLabelValue(1, "Two")
logtab.SetColLabelValue(2, "Three")
grid_sizer = wx.BoxSizer(wx.VERTICAL)
grid_sizer.Add(logtab, wx.ID_ANY, wx.EXPAND)
self.panel.SetSizer(grid_sizer)
# Dialog buttons
btns = wx.BoxSizer(wx.HORIZONTAL)
save_button = wx.Button(self, label="Save")
cancel_button = wx.Button(self, label="Cancel")
btns.Add(save_button)
btns.Add(cancel_button)
# Set final dialog layout
self.main_sizer.Add(self.panel, proportion=1, flag=wx.ALL | wx.EXPAND, border=15)
self.main_sizer.Add(btns, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=15)
self.SetSizerAndFit(self.main_sizer)
self.Layout()
self.Center()
self.Show()
if __name__ == "__main__":
wxapp = wx.App()
myApp = MyApp()
wxapp.MainLoop()

wxpython: how to keep three wxTextCtrls having same size in flexgridsizer

I want to use wxpython to implement a GUI that has three wxTextCtrls widgets, and I want to keep them having the same size when I change the size of the window
If I do nothing to these wxTextCtrls, it works well. But when I add many lines of contents in one of these three widgets, like the first one, it's size will be bigger than the others' when I change the size of the window. How could I keep these widgets having same size? Thanks!
(PS: I think the image of the generated GUI could explain my question better, but I can't post image. Sorry)
My code is
import os
import wx
class My_Gui(wx.Frame):
def __init__(self, parent, title):
super(My_Gui, self).__init__(parent, title = title,size=(800,600))
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
my_panel = wx.Panel(self)
hbox = wx.BoxSizer(wx.HORIZONTAL)
fgs = wx.FlexGridSizer(3, 2, 25, 30)
button1 = wx.Button(my_panel, label='button1', size=(120,150))
button2 = wx.Button(my_panel, label='button2', size=(120,150))
button3 = wx.Button(my_panel, label='button3', size=(120,150))
self.tc1 = wx.TextCtrl(my_panel, style=wx.TE_MULTILINE | wx.HSCROLL)
self.tc2 = wx.TextCtrl(my_panel, style=wx.TE_MULTILINE | wx.HSCROLL)
self.tc3 = wx.TextCtrl(my_panel, style=wx.TE_MULTILINE | wx.HSCROLL)
fgs.AddMany([(button1),(self.tc1, 1, wx.EXPAND), (button2), \
(self.tc2, 1, wx.EXPAND), (button3), (self.tc3, 1, wx.EXPAND)])
fgs.AddGrowableRow(2, 1)
fgs.AddGrowableRow(1, 1)
fgs.AddGrowableRow(0, 1)
fgs.AddGrowableCol(1, 1)
hbox.Add(fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=40)
my_panel.SetSizer(hbox)
if __name__ == "__main__":
app = wx.App()
My_Gui(None, title='Example')
app.MainLoop()
Since wxWidgets 2.5.0, wxFlexGridSizer can also size items equally in one direction but unequally ("flexibly") in the other. If the sizer is only flexible in one direction (this can be changed using SetFlexibleDirection), it needs to be decided how the sizer should grow in the other ("non-flexible") direction in order to fill the available space. The SetNonFlexibleGrowMode method serves this purpose. (from: docs.wxwidgets.org)
So change:
fgs.SetFlexibleDirection( wx.BOTH )
Into:
fgs.SetFlexibleDirection( wx.HORIZONTAL )
fgs.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_ALL )
The only problem I see here is that the largest minimal size of the TextCtrls is applied to all the TextCtrls.

wxListCtrl not displaying properly

Help!
I am a non-GUI programmer who is trying to write a simple (!) program using wxPython.
I have read everything I can online, but my overall lack of GUI experience is presumably causing me to not see the problem.
In a nutshell, I want to have a window with a wxNotebook with several tabs. Each tab, of course, will have its own child widgets. I envision having either a wxListCtrl (as in my code) or possibly a wxGrid control, along with several buttons.
Here is my "EmployeesPanel" class. When I run this, I see a tiny square that must represent the listctrl, but for the life of me I cannot figure out how to make it look correct. Of course, it is possible that I am way off base in some other area(s) as well.
Any help as to what I am doing wrong would be greatly appreciated.
Here is the code:
import wx
import sys
employees = [('Earl Boffo', 'Software'), ('Mildred Plotka', 'Software'), ('Sugar Kane', 'QA')]
classes = [('Python'), ('Java'), ('C#')]
class EmployeesPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
grid = wx.GridBagSizer(hgap=5, vgap=5)
#hSizer = wx.BoxSizer(wx.HORIZONTAL|wx.EXPAND)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
panel = wx.Panel(self, -1)
self.list = wx.ListCtrl(panel, size=(100,100), style=wx.LC_REPORT)
self.list.InsertColumn(0, 'Name')
self.list.InsertColumn(1, 'Group')
for i in employees:
index = self.list.InsertStringItem(sys.maxint, i[0])
self.list.SetStringItem(index, 1, i[1])
# A button
self.button = wx.Button(self, label="Exit")
self.Bind(wx.EVT_BUTTON, self.OnClick,self.button)
self.list.Show(True)
# add the listctrl widget to the grid
grid.Add(self.list, pos=(0,0), flag=wx.EXPAND|wx.ALL)
# add the button to the grid
grid.Add(self.button, pos=(1,0))
# add a spacer to the sizer
grid.Add((10, 40), pos=(1,1))
# add grid to hSizer
hSizer.Add(grid, 0, wx.ALL, 5)
# add hSizer to main (v) sizer
mainSizer.Add(hSizer, 0, wx.ALL, 5)
self.SetSizerAndFit(mainSizer)
self.Show()
def EvtComboBox(self, event):
self.logger.AppendText('EvtComboBox: %s\n' % event.GetString())
def OnClick(self,event):
sys.exit(3)
app = wx.App(False)
frame = wx.Frame(None, title="Training Tracker", size=(700,500))
nb = wx.Notebook(frame)
nb.AddPage(EmployeesPanel(nb), "Employees")
frame.Show()
app.MainLoop()
Welcome to wxPython! It's actually a lot of fun once you get the hang of it. I almost never use the grid sizers as they're just a pain for simple layouts like this. If you have a grid like interface and you don't have controls that are going to stretch across cells, then it's great. Otherwise, I almost always use BoxSizers nested in each other. I simplified your code quite a bit to show the two widgets. Currently the list control only stretches horizontally. If you need it to go vertically too, then change the proportion from 0 to 1 in the sizer.Add part.
import wx
import sys
employees = [('Earl Boffo', 'Software'), ('Mildred Plotka', 'Software'), ('Sugar Kane', 'QA')]
classes = [('Python'), ('Java'), ('C#')]
class EmployeesPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
# create some sizers
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.list = wx.ListCtrl(self, size=(100,100), style=wx.LC_REPORT)
self.list.InsertColumn(0, 'Name')
self.list.InsertColumn(1, 'Group')
for i in employees:
index = self.list.InsertStringItem(sys.maxint, i[0])
self.list.SetStringItem(index, 1, i[1])
# A button
self.button = wx.Button(self, label="Exit")
self.Bind(wx.EVT_BUTTON, self.OnClick,self.button)
mainSizer.Add(self.list, 0, wx.EXPAND|wx.ALL, 5)
mainSizer.Add(self.button, 0, wx.ALL, 5)
self.SetSizer(mainSizer)
self.Show()
def EvtComboBox(self, event):
self.logger.AppendText('EvtComboBox: %s\n' % event.GetString())
def OnClick(self,event):
sys.exit(3)
app = wx.App(False)
frame = wx.Frame(None, title="Training Tracker", size=(700,500))
nb = wx.Notebook(frame)
nb.AddPage(EmployeesPanel(nb), "Employees")
frame.Show()
app.MainLoop()
I also think these articles might help you:
wxPython: wx.ListCtrl Tips and Tricks
wxPython: Using ObjectListView instead of a ListCtrl
http://wiki.wxpython.org/ListControls

wxPython: wx.Panel of AuiManager has empty space of gray

I am trying to make a window with 2 panels. One panel is just a notebook panel. The second panel contains a toolbar on top and a text control on the bottom. I want to arrange this panel in my frame using wx.aui.AuiManager.
The problem is that I get a big empty space of grey in my custom panel.
Here is my code:
import wx
import wx.aui
import images # contains toolbar icons
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"AUI Tutorial",
size=(600,400))
self._mgr = wx.aui.AuiManager()
self._mgr.SetManagedWindow(self)
notebook = wx.aui.AuiNotebook(self)
nb_panel = TabPanel(notebook)
my_panel = MyPanel(self)
notebook.AddPage(nb_panel, "First Tab", False)
self._mgr.AddPane(notebook,
wx.aui.AuiPaneInfo().Name("notebook-content").
CenterPane().PaneBorder(False))
self._mgr.AddPane(my_panel,
wx.aui.AuiPaneInfo().Name("txtctrl-content").
CenterPane().PaneBorder(False))
self._mgr.GetPane("notebook-content").Show().Top().Layer(0).Row(0).Position(0)
self._mgr.GetPane("txtctrl-content").Show().Bottom().Layer(1).Row(0).Position(0)
self._mgr.Update()
class MyPanel(wx.Panel):
"""
My panel with a toolbar and richtextctrl
"""
def __init__(self,parent):
wx.Panel.__init__(self,parent=parent,id=wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
toolbar = wx.ToolBar(self,-1)
toolbar.AddLabelTool(wx.ID_EXIT, '', images._rt_smiley.GetBitmap())
self.Bind(wx.EVT_TOOL, self.OnExit, id=wx.ID_EXIT)
toolbar.Realize()
sizer.Add(toolbar,proportion=0,flag=wx.ALL | wx.ALIGN_TOP)
text = ""
txtctrl = wx.TextCtrl(self,-1, text, wx.Point(0, 0), wx.Size(150, 90),
wx.NO_BORDER | wx.TE_MULTILINE | wx.TE_READONLY|wx.HSCROLL)
sizer.Add(txtctrl,proportion=0,flag=wx.EXPAND)
self.SetSizer(sizer)
def OnExit(self,event):
self.Close()
class TabPanel(wx.Panel):
def __init__(self,parent):
wx.Panel.__init__(self,parent=parent,id=wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
txtOne = wx.TextCtrl(self, wx.ID_ANY, "")
txtTwo = wx.TextCtrl(self, wx.ID_ANY, "")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(txtOne, 0, wx.ALL, 5)
sizer.Add(txtTwo, 0, wx.ALL, 5)
self.SetSizer(sizer)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show()
app.MainLoop()
So, how do I fix my code so that I don't have that grey block taking up MyPanel? Also, my toolbar button doesn't seem to run self.OnExit(). Why is that?
Thank you for your help.
Take out the line:
self._mgr.GetPane("notebook-content").Show().Top().Layer(0).Row(0).Position(0)
As for the OnExit() handler, it is firing!
If you want to exit the application, replace it with app.Exit()

wxPython problems with wrapping staticText

A simplified version of the code is posted below (white space, comments, etc. removed to reduce size - but the general format to my program is kept roughly the same).
When I run the script, the static text correctly wraps as it should, but the other items in the panel do not move down (they act as if the statictext is only one line and thus not everything is visible).
If I manually resize the window/frame, even just a tiny amount, everything gets corrected, and displays as it is should.
Why doesn't it display correctly to begin with? I've tried all sorts of combination's of GetParent().Refresh() or Update() and GetTopLevelParent().Update() or Refresh(). I've also tried everything I can think of but cannot get it to display correctly without manually resizing the frame/window. Once re-sized, it works exactly as I want it to.
Information:
Windows XP
Python 2.5.2
wxPython 2.8.11.0 (msw-unicode)
My Code:
#! /usr/bin/python
import wx
class StaticWrapText(wx.PyControl):
def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER,
validator=wx.DefaultValidator, name='StaticWrapText'):
wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style)
self.wraplabel = label
#self.wrap()
def wrap(self):
self.Freeze()
self.statictext.SetLabel(self.wraplabel)
self.statictext.Wrap(self.GetSize().width)
self.Thaw()
def DoGetBestSize(self):
self.wrap()
#print self.statictext.GetSize()
self.SetSize(self.statictext.GetSize())
return self.GetSize()
class TestPanel(wx.Panel):
def __init__(self, *args, **kwargs):
# Init the base class
wx.Panel.__init__(self, *args, **kwargs)
self.createControls()
def createControls(self):
# --- Panel2 -------------------------------------------------------------
self.Panel2 = wx.Panel(self, -1)
msg1 = 'Below is a List of Files to be Processed'
staticBox = wx.StaticBox(self.Panel2, label=msg1)
Panel2_box1_v1 = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
Panel2_box2_h1 = wx.BoxSizer(wx.HORIZONTAL)
Panel2_box3_v1 = wx.BoxSizer(wx.VERTICAL)
self.wxL_Inputs = wx.ListBox(self.Panel2, wx.ID_ANY, style=wx.LB_EXTENDED)
sz = dict(size=(120,-1))
wxB_AddFile = wx.Button(self.Panel2, label='Add File', **sz)
wxB_DeleteFile = wx.Button(self.Panel2, label='Delete Selected', **sz)
wxB_ClearFiles = wx.Button(self.Panel2, label='Clear All', **sz)
Panel2_box3_v1.Add(wxB_AddFile, 0, wx.TOP, 0)
Panel2_box3_v1.Add(wxB_DeleteFile, 0, wx.TOP, 0)
Panel2_box3_v1.Add(wxB_ClearFiles, 0, wx.TOP, 0)
Panel2_box2_h1.Add(self.wxL_Inputs, 1, wx.ALL|wx.EXPAND, 2)
Panel2_box2_h1.Add(Panel2_box3_v1, 0, wx.ALL|wx.EXPAND, 2)
msg = 'This is a long line of text used to test the autowrapping '
msg += 'static text message. '
msg += 'This is a long line of text used to test the autowrapping '
msg += 'static text message. '
msg += 'This is a long line of text used to test the autowrapping '
msg += 'static text message. '
msg += 'This is a long line of text used to test the autowrapping '
msg += 'static text message. '
staticMsg = StaticWrapText(self.Panel2, label=msg)
Panel2_box1_v1.Add(staticMsg, 0, wx.ALL|wx.EXPAND, 2)
Panel2_box1_v1.Add(Panel2_box2_h1, 1, wx.ALL|wx.EXPAND, 0)
self.Panel2.SetSizer(Panel2_box1_v1)
# --- Combine Everything -------------------------------------------------
final_vbox = wx.BoxSizer(wx.VERTICAL)
final_vbox.Add(self.Panel2, 1, wx.ALL|wx.EXPAND, 2)
self.SetSizerAndFit(final_vbox)
class TestFrame(wx.Frame):
def __init__(self, *args, **kwargs):
# Init the base class
wx.Frame.__init__(self, *args, **kwargs)
panel = TestPanel(self)
self.SetClientSize(wx.Size(500,500))
self.Center()
class wxFileCleanupApp(wx.App):
def __init__(self, *args, **kwargs):
# Init the base class
wx.App.__init__(self, *args, **kwargs)
def OnInit(self):
# Create the frame, center it, and show it
frame = TestFrame(None, title='Test Frame')
frame.Show()
return True
if __name__ == '__main__':
app = wxFileCleanupApp()
app.MainLoop()
Using Mike Driscoll's code as a baseline, I hope this demonstrates my issue. There are two different versions of using "txt". Here are three things I want you to try:
Run it as-is. With my StaticWrapText. It displays wrong at first, but re-size the window and it works EXACTLY as I want. There is no blank/wasted space below the text before the "button"
Change these two lines (change the comments):
txt = wx.StaticText(panel, label=text)
#txt = StaticWrapText(panel, label=text)
Now you will see there is no wrapping and the text is always on only one line. Definitely not what we want. This is because of "sizer.Add(txt, 0, wx.EXPAND, 5) "...so going on to Part 3...
Keep the change from Part 2 and also change:
sizer.Add(txt, 0, wx.EXPAND, 5)
to:
sizer.Add(txt, 1, wx.EXPAND, 5)
So now the statictext will expand. This is CLOSE to working...BUT I don't want all that wasted space between the text and the button. If you make the window large, there is a lot of wasted space. See Part 1 after the window is re-sized to see the difference.
Code:
import wx
class StaticWrapText(wx.PyControl):
def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER,
validator=wx.DefaultValidator, name='StaticWrapText'):
wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style)
self.wraplabel = label
#self.wrap()
def wrap(self):
self.Freeze()
self.statictext.SetLabel(self.wraplabel)
self.statictext.Wrap(self.GetSize().width)
self.Thaw()
def DoGetBestSize(self):
self.wrap()
#print self.statictext.GetSize()
self.SetSize(self.statictext.GetSize())
return self.GetSize()
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)
text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand."
#txt = wx.StaticText(panel, label=text)
txt = StaticWrapText(panel, label=text)
wxbutton = wx.Button(panel, label='Button', size=wx.Size(120,50))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(txt, 0, wx.EXPAND, 5)
sizer.Add(wxbutton, 1, wx.EXPAND, 5)
panel.SetSizer(sizer)
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
EDIT:
AHHH...finally! I tried using the Layout() method on virtually every level of the program, but I actually needed to use Layout() on the SIZER which is found with the method GetSizer() - or you can send SendSizeEvent() to the panel (commented in code below). Thus, the following now does EXACTLY what I want! Thanks for the help. The only other change was to store the panel with self.panel in the frame class. As a note, I had to put this statement AFTER the frame.Show() or it didn't work correctly.
Code:
import wx
class StaticWrapText(wx.PyControl):
def __init__(self, parent, id=wx.ID_ANY, label='', pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.NO_BORDER,
validator=wx.DefaultValidator, name='StaticWrapText'):
wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name)
self.statictext = wx.StaticText(self, wx.ID_ANY, label, style=style)
self.wraplabel = label
#self.wrap()
def wrap(self):
self.Freeze()
self.statictext.SetLabel(self.wraplabel)
self.statictext.Wrap(self.GetSize().width)
self.Thaw()
def DoGetBestSize(self):
self.wrap()
#print self.statictext.GetSize()
self.SetSize(self.statictext.GetSize())
return self.GetSize()
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
self.panel = wx.Panel(self, wx.ID_ANY)
text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand."
txt = StaticWrapText(self.panel, label=text)
wxbutton = wx.Button(self.panel, label='Button', size=wx.Size(120,50))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(txt, 0, wx.EXPAND, 5)
sizer.Add(wxbutton, 1, wx.EXPAND, 5)
self.panel.SetSizer(sizer)
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm()
frame.Show()
#frame.panel.SendSizeEvent()
frame.panel.GetSizer().Layout()
app.MainLoop()
As a final note, in my original program posted, the following line needs to be added just before or after frame.Show():
frame.panel.Panel2.GetSizer().Layout()
Interestingly...with that original example this can be before or after frame.Show() but the other example requires that it be after frame.Show(). I'm not sure why, but just put it after and you're safe.
I use
width = 200 # panel width
txt = wx.StaticText(panel, label=text)
txt.Wrap(width)
This works great and the next widgets are positioned correctly. You can easily do the txt.Wrap(width) dynamically.
Why are you subclassing it? Do you need wordwrap? If so, there's a module for that in wx.lib.wordwrap that you can use.
In answer the the OP's comment, check this out:
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)
text = "I'm subclasses the statictext because I want it to act exactly like a static text, but correctly wordwrap as needed. I've found several examples of it on the web, but none that worked how I wanted. The wordwrap makes it look much nicer when the user may decide to re-size the window, so I would definitely like to have it be wordwrapped. I know about the wx.lib.wordwrap, but chose to use the built in Wrap function of the statictext control instead. It basically does the same thing from what I understand."
txt = wx.StaticText(panel, label=text)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(txt, 1, wx.EXPAND, 5)
panel.SetSizer(sizer)
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
I used the OP's comment for the text. Anyway, this works fine for me on Windows XP, Python 2.5 and wxPython 2.8.10.1.
I found what I think is a much easier and automatic way to handle this issue.
After creating the StaticText control, bind the control's wx.EVT_SIZE to a handler that calls the StaticText's Wrap() function with the event's GetSize()[0] as an argument (and then skips the event).
An example:
class MyDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent = parent, title = "Test Dialog", style = wx.CAPTION)
bigstr = "This is a really long string that is intended to test the wrapping functionality of the StaticText control in this dialog. If it works correctly, it should appear as multiple lines of text with a minimum of fuss."
self.__label__ = wx.StaticText(parent = self, label = bigstr)
self.__actionbutton__ = wx.Button(parent = self, label = "Go")
self.__label__.Bind(wx.EVT_SIZE, self.__WrapText__)
self.__actionbutton__.Bind(wx.EVT_BUTTON, self.__OnButton__)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.__label__, flag = wx.ALL | wx.EXPAND, border = 5)
sizer.Add(self.__actionbutton__, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.CENTER, border = 0)
self.SetSizer(sizer)
self.Layout()
def __OnButton__(self, event):
self.EndModal(wx.ID_OK)
def __WrapText__(self, event):
self.__label__.Wrap(event.GetSize()[0])
event.Skip()
This is what it looks like on my system (MSW, Python 2.7.5, wx 2.8.12.1):

Categories