2011-01-05 5 views
6

Tengo un problema con wxPython. A continuación, se publica una versión simplificada del código (se eliminan espacios en blanco, comentarios, etc. para reducir el tamaño, pero el formato general de mi programa se mantiene aproximadamente igual). Cuando ejecuto el script, el texto estático se ajusta correctamente como debería, pero los otros elementos del panel no se mueven hacia abajo (actúan como si el texto estático fuera solo una línea y, por lo tanto, no todo está visible). Si cambio manualmente el tamaño de la ventana/marco, incluso solo una pequeña cantidad, todo se corrige y se muestra como debería. Tomé capturas de pantalla para mostrar este comportamiento, pero acabo de crear esta cuenta y, por lo tanto, no tengo los 10 puntos de reputación necesarios para poder publicar imágenes.wxProblemas de Piython con Wrapping StaticText

¿Por qué no se muestra correctamente para empezar? Intenté todo tipo de combinaciones de GetParent(). Refresh() o Update() y GetTopLevelParent(). Update() o Refresh(). He intentado todo lo que puedo pensar pero no puedo mostrar correctamente sin cambiar manualmente el tamaño del marco/ventana. Una vez redimensionado, funciona exactamente como yo quiero.

información:
Windows XP
Python 2.5.2
wxPython 2.8.11.0 (RSU-Unicode)

¿Alguna sugerencia? ¡Gracias!

Código:

#! /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:
Ver mi post a continuación para una solución que funciona!

Respuesta

3

Usando el código de Mike Driscoll como referencia, espero que esto demuestre mi problema. Hay dos versiones diferentes de usar "txt". Aquí hay tres cosas que quiero que pruebe:

  1. Ejecútelo como está. Con mi StaticWrapText. Se muestra mal al principio, pero cambia el tamaño de la ventana y funciona EXACTAMENTE como yo quiero. No hay ningún desperdicio de espacio en blanco/debajo del texto antes de que el "botón"

  2. Cambio estas dos líneas (cambiar los comentarios):
    txt = wx.StaticText (panel, label = texto)
    #txt = StaticWrapText (panel, etiqueta = texto)
    Ahora verá que no hay envoltura y el texto está siempre en una sola línea. Definitivamente no es lo que queremos. Esto se debe a "sizer.Add (txt, 0, wx.EXPAND, 5)" ... de modo de pasar a la parte 3 ...

  3. Mantenga el cambio de la Parte 2 y también cambia:
    Sizer .Add (txt, 0, wx.EXPAND, 5)
    a:
    sizer.Add (txt, 1, wx.EXPAND, 5)
    Así que ahora la StaticText se expandirá. Esto está CERCA de trabajar ...PERO no quiero todo ese espacio desperdiciado entre el texto y el botón. Si amplía la ventana, hay mucho desperdicio de espacio. Consulte la Parte 1 después de que se vuelva a dimensionar la ventana para ver la diferencia.

Código:

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 ... ¡por fin! Intenté usar el método Layout() en prácticamente todos los niveles del programa, pero en realidad necesitaba usar Layout() en el SIZER que se encuentra con el método GetSizer() - o puede enviar SendSizeEvent() al panel (comentado) en el código a continuación). Por lo tanto, lo siguiente ahora hace EXACTAMENTE lo que quiero! Gracias por la ayuda. El único otro cambio fue almacenar el panel con self.panel en la clase frame. Como nota, tuve que poner esta declaración DESPUÉS del marco. Mostrar() o no funcionó correctamente.

Código:

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

Como nota final, en mi programa original publicada, la siguiente línea necesita ser añadido justo antes o después frame.Show():
frame.panel.Panel2.GetSizer(). Layout()

Curiosamente ... con ese ejemplo original, esto puede ser antes o después de frame.Show() pero el otro ejemplo requiere que sea después del frame.Show(). No estoy seguro por qué, pero solo ponlo y estás a salvo.

+0

Debería haberlo pensado. Por lo general, desea llamar a Diseño en el elemento primario de los widgets o en el tamaño que contiene los widgets. Oh bien. Lamento no haberlo visto. –

+0

¡Gracias por la ayuda! Todavía no funciona como debería cuando maximizo/minimizo la ventana. Pero por el momento, es lo suficientemente bueno. –

+0

Ah, esto hace que funcione incluso cuando se usa el botón maximizar ... en la función de ajuste, use self.statictext.Wrap (self.GetParent(). GetSize(). Width) en lugar de self.statictext.Wrap (self .GetSize(). Width) –

2

¿Por qué lo subclasifica? ¿Necesitas una palabra? Si es así, hay un módulo para eso en wx.lib.wordwrap que puede usar.

En respuesta al comentario de la OP, mira esto:

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

que utiliza el comentario de la OP para el texto. De todos modos, esto funciona bien para mí en Windows XP, Python 2.5 y wxPython 2.8.10.1.

+0

estoy subclases la StaticText porque quiero que actúe exactamente como un texto estático, pero que se corresponda correctamente según sea necesario. Encontré varios ejemplos de esto en la web, pero ninguno funcionó como yo quería. La envoltura de palabra hace que se vea mucho mejor cuando el usuario puede decidir volver a ajustar el tamaño de la ventana, por lo que definitivamente me gustaría que se envuelva con la palabra. Sé sobre wx.lib.wordwrap, pero opté por usar la función integrada Wrap del control statictext en su lugar. Básicamente hace lo mismo por lo que yo entiendo. –

+0

Es posible que desee utilizar SetSizeHints para evitar que el tamaño del marco también sea demasiado pequeño. –

+0

OK, su ejemplo es más pequeño, por lo que será más fácil trabajar con él. Vea mi respuesta para una modificación de su código que demuestre mi problema (más claramente, espero). –

5

utilizo

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

Esto funciona muy bien y los siguientes widgets se coloca correctamente. Puede hacer fácilmente el txt.Wrap(width) dinámicamente.

+0

gracias! Esto es simple y funciona muy bien – Harry

1

Encontré lo que creo que es una manera mucho más fácil y automática de manejar este problema.

Después de crear el control StaticText, vincula el wx.EVT_SIZE del control a un controlador que llama a la función Wrap() del StaticText con GetSize() [0] como argumento (y luego omite el evento).

Un ejemplo:

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

Esto es lo que parece en mi sistema (RSU, Python 2.7.5, wx 2.8.12.1): StaticText Wrapping Dialog

+0

Calling Wrap dentro de un controlador EVT_SIZE parece llamar al mismo controlador nuevamente, esta vez con un tamaño diferente. – Pod

Cuestiones relacionadas