Problems with wxPython with staticText wrapping

A simplified version of the code is posted below (spaces, comments, etc. Deleted to reduce size, but the general format of my program remains approximately the same).

When I run the script, the static text is correctly wrapped, as it should, but the other elements in the panel do not move down (they act as if the static text was only one line and, therefore, not everything was visible).

If I manually resize the window / frame, even a small amount, everything is fixed and displayed as it should.

Why is it not showing right from the start? I tried all kinds of combinations of GetParent().Refresh() or Update() and GetTopLevelParent().Update() or Refresh() . I also tried everything I can think of, but I can not get it to display correctly without resizing the frame / window manually. After resizing, it works exactly the way I want.

Information:

  • Windows XP
  • Python 2.5.2
  • wxPython 2.8.11.0 (MSW-Unicode)

My code is:

 #! /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() 
+7
python static wrapping wrap wxpython
source share
4 answers

Using Mike Driscoll's code as a baseline, I hope this demonstrates my problem. There are two different versions of using "txt". Here are three things I want you to try:

  • Run it as is. With my StaticWrapText. At first it does not display correctly, but it resized the window, and it works EXACTLY as I want. The empty / empty space below the text in front of the "button"

  • Change these two lines (change the comments):
    txt = wx.StaticText (panel, label = text)
    #txt = StaticWrapText (panel, label = text)
    Now you will see that there is no wrapper, and the text is always on only one line. Definitely not what we want. This is due to "sizer.Add (txt, 0, wx.EXPAND, 5)" ... so we move on to Part 3 ...

  • Save the changes from Part 2, and also change:
    sizer.Add (txt, 0, wx.EXPAND, 5)
    in:
    sizer.Add (txt, 1, wx.EXPAND, 5)
    So now the static text will expand. This is CLOSED to work ... BUT I do not want all this empty space between the text and the button. If you make the window large, there will be a lot of lost space. See Part 1 after resizing a window to see the difference.

the 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 at almost every level of the program, but I really needed to use Layout () on SIZER, which was found using the GetSizer () method, or you can send SendSizeEvent () to the panel (commented in the code below). So the following is now EXACTLY what I want! Thanks for the help. The only other change was to save the panel with self.panel in the frame class. As a note, I had to put this statement AFTER the .Show () frame or it did not work correctly.

the 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 source program, the next line should be added immediately before or after the frame. Show ():
frame.panel.Panel2.GetSizer (). Layout ()

Interesting ... with this original example, it may be before or after frame.Show (), but another example requires it to be after frame.Show (). I don’t know why, but just put it and you are safe.

+4
source share

I use

 width = 200 # panel width txt = wx.StaticText(panel, label=text) txt.Wrap(width) 

This works great and the following widgets are positioned correctly. You can easily do txt.Wrap(width) dynamically.

+5
source share

Why do you subclass it? Do you need a word? If so, there is a module for wx.lib.wordwrap that you can use.

In response to the OP comment, check this:

 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 comment for the text. Anyway, this works fine for me on Windows XP, Python 2.5, and wxPython 2.8.10.1.

+2
source share

I found something that, in my opinion, is a much simpler and automatic way to deal with this problem.

After creating the StaticText control, bind the wx.EVT_SIZE control to a handler that calls the StaticText Wrap () function with the GetSize () [0] event as an argument (and then skips the event).

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 looks like my system (MSW, Python 2.7.5, wx 2.8.12.1): StaticText Binding Dialog

+2
source share

All Articles