Проблемы с wxPython с переносом staticText - PullRequest
7 голосов
/ 05 января 2011

Упрощенная версия кода размещена ниже (пробелы, комментарии и т. Д. Удалены, чтобы уменьшить размер, но общий формат моей программы остается примерно таким же).

Когда я запускаю сценарий, статический текст правильно переносится, как и должно, но другие элементы на панели не перемещаются вниз (они действуют так, как если бы statictext был только одной строкой, и, следовательно, не все видно).

Если я вручную изменю размер окна / фрейма, даже на небольшую величину, все исправляется и отображается так, как должно.

Почему он не отображается правильно с самого начала? Я пробовал все виды комбинаций 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()

Ответы [ 4 ]

5 голосов
/ 27 января 2013

Я использую

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

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

4 голосов
/ 06 января 2011

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

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

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

  3. Сохраните изменения из части 2а также изменить:
    sizer.Add (txt, 0, wx.EXPAND, 5)
    на:
    sizer.Add (txt, 1, wx.EXPAND, 5)
    Так что теперь статический текстбудет расширяться.Это близко к работе ... НО я не хочу, чтобы все это впустую пространство между текстом и кнопкой.Если вы сделаете окно большим, будет много потерянного пространства.См. Часть 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()

РЕДАКТИРОВАТЬ:

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

Код:

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

Как заключительная заметка, в моем оригиналеПосле публикации программы следующую строку необходимо добавить непосредственно перед или после frame.Show ():
frame.panel.Panel2.GetSizer (). Layout ()

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

2 голосов
/ 16 января 2016

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

После создания элемента управления StaticText свяжите wx.EVT_SIZE элемента управления с обработчиком, который вызывает функцию Wrap () StaticTextGetSize () [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, Python2.7.5, шх 2.8.12.1): StaticText Wrapping Dialog

2 голосов
/ 05 января 2011

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...