2011-01-05 11 views
6

Sto riscontrando un problema con wxPython. Una versione semplificata del codice è pubblicata di seguito (spazio bianco, commenti, ecc. Rimossi per ridurre le dimensioni - ma il formato generale del mio programma è approssimativamente lo stesso). Quando eseguo lo script, il testo statico si adatta correttamente come dovrebbe, ma gli altri elementi nel pannello non si spostano verso il basso (si comportano come se il testo statico fosse solo una riga e quindi non tutto fosse visibile). Se ridimensiono manualmente la finestra/frame, anche solo una piccola quantità, tutto viene corretto e visualizzato come dovrebbe. Ho scattato schermate per mostrare questo comportamento, ma ho appena creato questo account e quindi non ho i 10 punti reputazione necessari per poter pubblicare le foto.Problemi wxPython con Wrapping StaticText

Perché non viene visualizzato correttamente per iniziare? Ho provato tutti i tipi di combinazioni di GetParent(). Refresh() o Update() e GetTopLevelParent(). Update() o Refresh(). Ho provato tutto quello che posso pensare, ma non riesco a farlo visualizzare correttamente senza ridimensionare manualmente la cornice/finestra. Una volta ridimensionato, funziona esattamente come lo voglio io.

Informazioni:
Windows XP
Python 2.5.2
wxPython 2.8.11.0 (RSU-unicode)

Qualche suggerimento? Grazie!

Codice:

#! /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:
Vedi il mio post qui sotto per una soluzione che funziona!

risposta

3

Utilizzando il codice di Mike Driscoll come riferimento, spero che questo dimostri il mio problema. Esistono due diverse versioni dell'utilizzo di "txt". Ecco tre cose che voglio provare:

  1. Eseguirlo così com'è. Con il mio StaticWrapText. Dapprima mostra male, ma ridimensiona la finestra e funziona ESATTAMENTE come voglio. Non v'è alcun/spazio vuoto sprecato sotto il testo prima che il "pulsante"

  2. modificare queste due righe (modificare le osservazioni):
    txt = wx.StaticText (pannello, label = text)
    #txt = StaticWrapText (pannello, etichetta = testo)
    Ora vedrete che non c'è alcun involucro e il testo è sempre su una sola riga. Sicuramente non quello che vogliamo. Questo è causa di "sizer.Add (txt, 0, wx.EXPAND, 5)" ... in modo da andare a Parte 3 ...

  3. Tenga il resto dalla parte 2 e anche cambiare:
    sizer .Add (txt, 0, wx.EXPAND, 5)
    a:
    sizer.Add (txt, 1, wx.EXPAND, 5)
    Così ora la StaticText si espanderà. Questo è VICINO al lavoro ...MA non voglio tutto quello spazio sprecato tra il testo e il pulsante. Se ingrandisci la finestra, c'è molto spazio sprecato. Vedere la parte 1 dopo che la finestra viene ridimensionata per vedere la differenza.

Codice:

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 ... finalmente! Ho provato ad usare il metodo Layout() praticamente su tutti i livelli del programma, ma in realtà avevo bisogno di usare Layout() sul SIZER che si trova con il metodo GetSizer() - oppure puoi inviare SendSizeEvent() al pannello (commentato nel codice qui sotto). Quindi, il seguente ora fa ESATTAMENTE quello che voglio! Grazie per l'aiuto. L'unica altra modifica è stata quella di memorizzare il pannello con self.panel nella classe frame. Come nota, ho dovuto mettere questa istruzione DOPO il frame.Show() o non ha funzionato correttamente.

Codice:

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

Come nota finale, nel mio programma originale pubblicato, la seguente riga deve essere aggiunto appena prima o dopo frame.Show():
frame.panel.Panel2.GetSizer() .Layout()

È interessante notare che ... con quell'esempio originale questo può essere prima o dopo frame.Show() ma l'altro esempio richiede che sia dopo frame.Show(). Non sono sicuro del perché, ma lo metto dopo e sei al sicuro.

+0

Avrei dovuto pensarci. Di solito vuoi chiamare Layout sul genitore dei widget o sul sizer che contiene i widget. Oh bene. Mi spiace di non averlo notato. –

+0

Grazie per l'aiuto! Ancora non funziona come dovrebbe quando massimizzo/minimizzo la finestra. Ma per il momento, è abbastanza buono. –

+0

Ah, questo funziona anche quando si utilizza il pulsante di ingrandimento ... nella funzione wrap, utilizzare self.statictext.Wrap (self.GetParent(). GetSize(). Width) anziché self.statictext.Wrap (self .GetSize(). Width) –

2

Perché la si sottoclassa? Hai bisogno di un foglio di carta? Se è così, c'è un modulo per quello in wx.lib.wordwrap che puoi usare.

In risposta al commento del PO, 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() 

ho usato il commento del PO per il testo. Ad ogni modo, per me funziona bene su Windows XP, Python 2.5 e wxPython 2.8.10.1.

+0

io sono sottoclassi della StaticText perché io vuoi che funzioni esattamente come un testo statico, ma che sia correttamente scritto a seconda delle necessità. Ne ho trovato diversi esempi sul web, ma nessuno ha funzionato come volevo. Il wordwrap lo rende molto più bello quando l'utente può decidere di ridimensionare la finestra, quindi mi piacerebbe sicuramente che fosse wordwrapped. Conosco il wx.lib.wordwrap, ma ho scelto di usare invece la funzione Wrap integrata del controllo statictext. Fondamentalmente fa la stessa cosa da ciò che capisco. –

+0

Potrebbe essere utile utilizzare SetSizeHints per evitare di ridimensionare troppo il fotogramma. –

+0

OK, il tuo esempio è più piccolo, quindi sarà più facile lavorare con. Vedi la mia risposta per una modifica al tuo codice che dimostri il mio problema (più chiaramente, spero). –

5

Io uso

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

Questa grande opera e le prossime widget sono posizionati correttamente. Puoi facilmente fare il txt.Wrap(width) in modo dinamico.

+0

grazie! Questo è semplice e funziona perfettamente – Harry

1

Ho trovato quello che penso sia un modo molto più semplice e automatico per gestire questo problema.

Dopo aver creato il controllo StaticText, associare il controllo wx.EVT_SIZE a un gestore che chiama la funzione Wrap() di StaticText con l'oggetto GetSize() [0] come argomento (e quindi ignora l'evento).

Un esempio:

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

Questo è quello che sembra sul mio sistema (RSU, Python 2.7.5, WX 2.8.12.1): StaticText Wrapping Dialog

+0

Chiamare Wrap all'interno di un gestore EVT_SIZE sembra chiamare di nuovo lo stesso gestore, questa volta con una dimensione diversa. – Pod