2011-01-05 16 views
6

Ich habe ein Problem mit WxPython. Eine vereinfachte Version des Codes ist unten veröffentlicht (Leerraum, Kommentare, etc. entfernt, um die Größe zu reduzieren - aber das allgemeine Format zu meinem Programm wird ungefähr gleich gehalten). Wenn ich das Skript ausführe, wird der statische Text korrekt umgebrochen, aber die anderen Elemente im Panel werden nicht nach unten bewegt (sie verhalten sich so, als ob der statische Text nur eine Zeile wäre und somit nicht alles sichtbar wäre). Wenn ich das Fenster/den Rahmen manuell verkleinere, wird auch nur eine winzige Menge korrigiert und alles so angezeigt, wie es sein sollte. Ich habe Screenshots gemacht, um dieses Verhalten zu zeigen, aber ich habe gerade dieses Konto erstellt und habe daher nicht die erforderlichen 10 Rufpunkte, um Bilder posten zu dürfen.wxPython Probleme mit Wrapping StaticText

Warum wird es nicht richtig angezeigt, um damit zu beginnen? Ich habe alle möglichen Kombinationen von GetParent(), Refresh() oder Update() und GetTopLevelParent(), Update() oder Refresh() ausprobiert. Ich habe alles versucht, was mir einfällt, aber ich bekomme es nicht richtig angezeigt, ohne den Rahmen/das Fenster manuell zu verändern. Nach der Größenanpassung funktioniert es genau so, wie ich es möchte.

Informationen:
Windows XP
Python 2.5.2
WxPython 2.8.11.0 (msw-Unicode)

Irgendwelche Vorschläge? Vielen Dank!

Code:

#! /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:
Siehe meinen Beitrag unten für eine Lösung, die funktioniert!

Antwort

3

Mit Mike Driscoll-Code als Basis, hoffe ich, dass dies mein Problem demonstriert. Es gibt zwei verschiedene Versionen von "txt". Hier sind drei Dinge, die ich möchte, dass Sie es versuchen:

  1. Führen Sie es wie es ist. Mit meinem StaticWrapText. Es zeigt zuerst falsch an, aber das Fenster wird neu skaliert und es funktioniert GENAU wie ich will. Es gibt keine Leer/verschwendete Raum unter dem Text vor dem "Knopf"

  2. ändern diese beiden Linien (die Kommentare aus):
    txt = wx.StaticText (Panel, label = text)
    #txt = StaticWrapText (Panel, Label = Text)
    Jetzt werden Sie sehen, dass es keine Verpackung gibt und der Text immer nur in einer Zeile ist. Definitiv nicht was wir wollen. Dies ist wegen der "sizer.Add (txt, 0, wx.EXPAND, 5)" ... so zu Teil 3 geht ...

  3. Halten Sie die Änderung von Teil 2 und auch ändern:
    Sizer .Add (txt, 0, wx.EXPAND, 5)
    zu:
    sizer.Add (txt, 1, wx.EXPAND, 5)
    So, jetzt die StaticText- erweitern wird. Das ist nah dran zu arbeiten ...ABER ich will nicht all den verschwendeten Platz zwischen dem Text und dem Knopf. Wenn Sie das Fenster groß machen, wird viel Platz verschwendet. Siehe Teil 1, nachdem das Fenster neu skaliert wurde, um den Unterschied zu sehen.

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 ... endlich! Ich habe versucht, die Layout() -Methode auf praktisch jeder Ebene des Programms, aber ich musste tatsächlich Layout() auf der SIZER verwenden, die mit der Methode GetSizer() gefunden wird - oder Sie können SendSizeEvent() an die Tafel senden (kommentiert im Code unten). Also folgendes tut GENAU, was ich will! Danke für die Hilfe. Die einzige andere Änderung bestand darin, das Panel mit self.panel in der Frame-Klasse zu speichern. Als eine Anmerkung, musste ich diese Anweisung nach dem frame.Show() oder es hat nicht richtig funktioniert.

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

Als abschließende Bemerkung, in meinem ursprüngliches Programm geschrieben, muss die folgende Zeile vor nur hinzugefügt werden, oder nach frame.Show():
frame.panel.Panel2.GetSizer()

Interessanterweise ... mit diesem ursprünglichen Beispiel kann dies vor oder nach frame.Show() sein, aber das andere Beispiel erfordert, dass es nach frame.Show() ist. Ich bin mir nicht sicher warum, aber stell es einfach hin und du bist in Sicherheit.

+0

Ich hätte daran gedacht. Normalerweise möchten Sie Layout entweder auf dem übergeordneten Element der Widgets oder auf dem Sizer, der die Widgets enthält, aufrufen. Naja. Tut mir leid, das habe ich nicht bemerkt. –

+0

Danke für die Hilfe! Es funktioniert immer noch nicht so wie es sollte, wenn ich das Fenster maximiere/minimiere. Aber im Moment ist es gut genug. –

+0

Ah, das macht es funktioniert, auch wenn die Maximieren-Schaltfläche verwendet wird ... in der Umbruch-Funktion verwenden Sie self.statictext.Wrap (self.GetParent(). GetSize(). Width) anstelle von self.statictext.Wrap (self.statictext.Wrap) .GetSize(). Width) –

2

Warum untergliedern Sie es? Brauchst du Wordwrap? Wenn ja, gibt es dafür ein Modul in wx.lib.wordwrap, das Sie verwenden können.

In Antwort der Kommentar des OP, 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() 

habe ich die Bemerkung des OP für den Text. Für Windows XP, Python 2.5 und wxPython 2.8.10.1 funktioniert das jedenfalls gut.

+0

Ich bin Subklassen der StaticText-, weil ich möchte, dass es genau wie ein statischer Text funktioniert, aber bei Bedarf korrekt in ein Wordwrap umgewandelt wird. Ich habe mehrere Beispiele dafür im Internet gefunden, aber keine, die so funktioniert haben, wie ich es wollte. Das Wordwrap lässt es viel schöner aussehen, wenn der Benutzer sich entscheidet, das Fenster neu zu sortieren, also würde ich es auf jeden Fall gerne als Wordwrapped haben. Ich weiß über die wx.lib.wordwrap, aber wählte stattdessen die integrierte Wrap-Funktion des statischen Text-Steuerelement. Es macht grundsätzlich das Gleiche, was ich verstehe. –

+0

Sie können SetSizeHints verwenden, um die Größe des Rahmens nicht zu klein zu halten. –

+0

OK, Ihr Beispiel ist kleiner, so dass es einfacher ist, damit zu arbeiten. Sehen Sie meine Antwort für eine Änderung an Ihrem Code, die mein Problem (deutlicher, hoffe ich) zeigt. –

5

Ich benutze

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

Dies funktioniert gut und die nächsten Widgets richtig positioniert sind. Sie können das txt.Wrap(width) dynamisch machen.

+0

danke! Das ist einfach und funktioniert gut – Harry

1

Ich fand, was ich denke, ist eine viel einfachere und automatische Möglichkeit, um dieses Problem zu behandeln.

Nachdem Sie das StaticText-Steuerelement erstellt haben, binden Sie die wx.EVT_SIZE des Steuerelements an einen Handler, der die Wrap() -Funktion von StaticText mit dem GetSize() [0] des Ereignisses als Argument aufruft (und dann das Ereignis überspringt).

Ein Beispiel:

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

Dies ist, wie es auf meinem System sieht (MSW, Python 2.7.5, wx 2.8.12.1): StaticText Wrapping Dialog

+0

Aufruf Wrap in einem EVT_SIZE-Handler scheint den gleichen Handler erneut aufzurufen, dieses Mal mit einer anderen Größe. – Pod