проблемы wxPython с упаковкой StaticText

У меня проблема с wxPython. Упрощенная версия кода размещена ниже (пробел, комментарии и т. д. удалены для уменьшения размера, но общий формат моей программы сохраняется примерно таким же). Когда я запускаю скрипт, статический текст правильно обертывается, как и должен, но другие элементы на панели не перемещаются вниз (они действуют так, как будто statictext-это только одна строка, и поэтому не все видно). Если я вручную изменю размер окна / рамки, даже на крошечную сумму, все получает исправления и отображает, как это должно быть. Я сделал снимки экрана, чтобы показать это поведение, но я только что создал эту учетную запись и, таким образом, не имею необходимых 10 очков репутации для публикации фотографий.

почему он не отображается правильно Для начала? Я пробовал всевозможные комбинации GetParent ().Refresh() или Update () и GetTopLevelParent ().Update () или Refresh (). Я пробовал все, что мог придумать, но не могу заставить его правильно отображаться без ручного изменения размера фрейм окна. После изменения размера он работает именно так, как я хочу.

информация:
Windows XP
Python 2.5.2
wxPython 2.8.11.0 (msw-unicode)

какие предложения? Спасибо!

код:

#! /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()

EDIT:
См. мой пост ниже для решения, которое работает!

4 ответов


Я использую

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

это отлично работает, и следующие виджеты расположены правильно. Вы можете легко сделать txt.Wrap(width) динамически.


используя код Майка Дрисколла в качестве базовой линии, я надеюсь, что это демонстрирует мою проблему. Существует две разные версии использования "txt". Вот три вещи, которые я хочу попробовать:

  1. запустить его как есть. С моим StaticWrapText. Сначала он отображается неправильно, но измените размер окна, и он работает точно так, как я хочу. Нет пустого / пустого места под текстом перед "кнопкой"

  2. измените эти две строки (измените комментарии):
    формат txt= wx.StaticText (панель, метка=текст)
    #txt = StaticWrapText (панель, метка=текст)
    Теперь вы увидите, что нет упаковки, и текст всегда находится только на одной строке. Определенно не то, чего мы хотим. Это из-за " sizer.Добавить (txt, 0, wx.Разверните, 5) " ... Итак, переходим к части 3...

  3. Сохранить изменения из части 2, а также изменить:
    классификатор.Добавить (txt, 0, wx.Разверните, 5)
    кому:
    классификатор.Добавить (txt, 1, wx.Разверните, 5)
    Так что теперь statictext будет расширяться. Это близко к работе...Но я не хочу, чтобы все это пустое пространство между текстом и кнопкой. Если вы сделаете окно большим, то будет много расточительствованного космоса. См. Часть 1 после изменения размера окна, чтобы увидеть разницу.

код:

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:

АААА...наконец-то! Я попытался использовать метод Layout() практически на каждом уровне программы, но мне действительно нужно было использовать Layout() на SIZER, который находится с методом GetSizer () - или вы можете отправить SendSizeEvent () на панель (прокомментировано в коде ниже). Таким образом, следующее теперь делает именно то, что я хочу! Спасибо за помощь. Единственное изменение состояло в том, чтобы сохранить панель с self.панель в классе frame. В качестве примечания я должен был поставить это заявление после кадра.Show () или он работал неправильно.

код:

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()

в качестве заключительного примечания в моей оригинальной программе должна быть опубликована следующая строка добавляется непосредственно перед или после кадра.Show ():
рамка.панель.Панель2.GetSizer().Layout ()

интересно...с этим оригинальным примером это может быть до или после кадра.Show () но другой пример требует, чтобы он был после кадра.Шоу.)( Не знаю почему, но просто положи его после, и ты в безопасности.


почему вы его подклассы? Вам нужен wordwrap? Если это так, в wx есть модуль для этого.движение за освобождение.wordwrap, который вы можете использовать.

в ответ на комментарий OP, проверьте это:

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()

я использовал комментарий OP для текста. Во всяком случае, это отлично работает для меня в Windows XP, Python 2.5 и wxPython 2.8.10.1.


Я нашел, что я думаю, гораздо проще и автоматический способ справиться с этой проблемой.

после создания элемента управления StaticText свяжите WX элемента управления.EVT_SIZE обработчику, который вызывает функцию Wrap() StaticText с getsize () события[0] в качестве аргумента (а затем пропускает событие).

пример:

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()

вот как это выглядит в моей системе (MSW, Python 2.7.5, wx 2.8.12.1): StaticText Wrapping Dialog