2010-04-01 9 views
10

Wie in meinem previous question verwiesen, versuche ich etwas etwas Zauberer-wie in Funktion zu machen. Ich habe mich auf einen einzelnen Rahmen mit einem Sizer, der hinzugefügt wird, festgelegt. Ich baue Panels für jeden der Bildschirme, die Benutzer sehen sollen, füge sie dem Frame-Sizer hinzu und wechsle dann zwischen den Panels um .Hide() in einem Panel und rufe dann ein benutzerdefiniertes .ShowYourself() auf dem nächsten Panel an. Offensichtlich möchte ich, dass die Schaltflächen am selben Ort bleiben, an dem der Benutzer den Prozess durchläuft.Warum .Hide() ing und .Show() ing Panels in wxPython Ergebnis im Sizer Ändern des Layouts?

Ich habe zwei Panels in einer Endlosschleife mit ihren "Zurück" und "Weiter" Tasten verbunden, so dass Sie sehen können, was vor sich geht. Das erste Panel sieht gut aus; Der Code von tom10 funktionierte auf dieser Ebene, da er meinen anfänglichen, übertriebenen Versuch mit Grenzen, die in alle Richtungen flogen, vermied. Und dann scheint das zweite Panel auf das absolute Minimum geschrumpft zu sein. Als wir zur ersten Platte zurückkehren, ist auch hier die Schrumpfung aufgetreten. Warum sieht es auf dem ersten Panel gut aus, aber nicht, nachdem ich dorthin zurückgekehrt bin? Warum muss .Fit() aufgerufen werden, wenn ich kein 10 Pixel mal 10 Pixel graues Pixel möchte? Und wenn es notwendig ist, warum gibt .Fit() inkonsistente Ergebnisse?

Diese Endlosschleife scheint meine Erfahrung mit diesem zu charakterisieren: Ich repariere das Layout auf einem Panel, nur um zu finden, dass das Umschalten das Layout für andere Panels ruiniert. Ich behebe dieses Problem, indem ich sizer_h.Add(self.panel1, 0) anstelle von sizer_h.Add(self.panel1, 1, wx.EXPAND) verwende, und jetzt sind meine Layouts wieder aus.

Bis jetzt ist meine "Lösung", einen mastersizer.SetMinSize((475, 592)) zu jedem Master-Sizer des Panels hinzuzufügen (auskommentiert in dem Code unten). Dies ist eine knifflige Lösung, denn 1) Ich musste die Zahlen finden, die durch Versuch und Irrtum funktionieren (-5 Pixel für die Breite, -28 Pixel für die Höhe). 2) Ich verstehe nicht, warum das zugrunde liegende Problem immer noch auftritt.

Was ist die richtige, nicht hässliche Lösung? Anstatt alle Panels gleichzeitig in den Frame-Sizer einzufügen, sollte das Panel beim Wechseln des Panels vom Frame-Sizer und .Add() des nächsten Panels an den Frame-Sizer angeschlossen werden. Gibt es eine .JustMakeThisFillThePanel() Methode, die irgendwo versteckt, die ich in den wxWidgets und den wxPython Dokumenten online verpasst habe?

Ich vermisse offensichtlich etwas in meinem mentalen Layout-Modell. Minimalistischer Code unten eingefügt.

enter image description here

import wx 
import sys 


class My_App(wx.App): 

    def OnInit(self): 
     self.frame = My_Frame(None) 
     self.frame.Show() 
     self.SetTopWindow(self.frame) 
     return True 

    def OnExit(self): 
     print 'Dying ...' 


class My_Frame(wx.Frame): 

    def __init__(self, image, parent=None,id=-1, title='Generic Title', pos=wx.DefaultPosition, style=wx.CAPTION | wx.STAY_ON_TOP):  

     size = (480, 620) 
     wx.Frame.__init__(self, parent, id, 'Program Title', pos, size, style) 

     sizer_h = wx.BoxSizer(wx.HORIZONTAL) 

     self.panel0 = User_Interaction0(self)  
     sizer_h.Add(self.panel0, 1, wx.EXPAND) 

     self.panel1 = User_Interaction1(self)  
     sizer_h.Add(self.panel1, 1, wx.EXPAND) 

     self.SetSizer(sizer_h) 

     self.panel0.ShowYourself() 

    def ShutDown(self): 
     self.Destroy() 


class User_Interaction0(wx.Panel): 

    def __init__(self, parent, id=-1): 

     wx.Panel.__init__(self, parent, id) 

     # master sizer for the whole panel 
     mastersizer = wx.BoxSizer(wx.VERTICAL) 
     #mastersizer.SetMinSize((475, 592)) 
     mastersizer.AddSpacer(15) 


     # build the top row 
     txtHeader = wx.StaticText(self, -1, 'Welcome to This Boring\nProgram', (0, 0)) 
     font = wx.Font(16, wx.DEFAULT, wx.NORMAL, wx.BOLD) 
     txtHeader.SetFont(font) 
     txtOutOf = wx.StaticText(self, -1, '1 out of 7', (0, 0))     
     rowtopsizer = wx.BoxSizer(wx.HORIZONTAL) 
     rowtopsizer.Add(txtHeader, 3, wx.ALIGN_LEFT) 
     rowtopsizer.Add((0,0), 1) 
     rowtopsizer.Add(txtOutOf, 0, wx.ALIGN_RIGHT) 
     mastersizer.Add(rowtopsizer, 0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 


     # build the middle row 
     text = 'PANEL 0\n\n' 
     text = text + 'This could be a giant blob of explanatory text.\n' 

     txtBasic = wx.StaticText(self, -1, text) 
     font = wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL) 
     txtBasic.SetFont(font) 
     mastersizer.Add(txtBasic, 1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 


     # build the bottom row 
     btnBack = wx.Button(self, -1, 'Back') 
     self.Bind(wx.EVT_BUTTON, self.OnBack, id=btnBack.GetId()) 
     btnNext = wx.Button(self, -1, 'Next') 
     self.Bind(wx.EVT_BUTTON, self.OnNext, id=btnNext.GetId()) 
     btnCancelExit = wx.Button(self, -1, 'Cancel and Exit') 
     self.Bind(wx.EVT_BUTTON, self.OnCancelAndExit, id=btnCancelExit.GetId()) 
     rowbottomsizer = wx.BoxSizer(wx.HORIZONTAL) 
     rowbottomsizer.Add(btnBack, 0, wx.ALIGN_LEFT) 
     rowbottomsizer.AddSpacer(5) 
     rowbottomsizer.Add(btnNext, 0) 
     rowbottomsizer.AddSpacer(5) 
     rowbottomsizer.AddStretchSpacer(1) 
     rowbottomsizer.Add(btnCancelExit, 0, wx.ALIGN_RIGHT) 
     mastersizer.Add(rowbottomsizer, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 

     # finish master sizer 
     mastersizer.AddSpacer(15) 
     self.SetSizer(mastersizer) 

     self.Raise() 
     self.SetPosition((0,0)) 
     self.Fit() 
     self.Hide() 


    def ShowYourself(self): 
     self.Raise() 
     self.SetPosition((0,0)) 
     self.Fit() 
     self.Show() 


    def OnBack(self, event): 
     self.Hide() 
     self.GetParent().panel1.ShowYourself() 

    def OnNext(self, event): 
     self.Hide() 
     self.GetParent().panel1.ShowYourself() 

    def OnCancelAndExit(self, event): 
     self.GetParent().ShutDown() 


class User_Interaction1(wx.Panel): 

    def __init__(self, parent, id=-1): 

     wx.Panel.__init__(self, parent, id) 

     # master sizer for the whole panel 
     mastersizer = wx.BoxSizer(wx.VERTICAL) 
     #mastersizer.SetMinSize((475, 592)) 
     mastersizer.AddSpacer(15) 


     # build the top row 
     txtHeader = wx.StaticText(self, -1, 'Read about This Boring\nProgram', (0, 0)) 
     font = wx.Font(16, wx.DEFAULT, wx.NORMAL, wx.BOLD) 
     txtHeader.SetFont(font) 
     txtOutOf = wx.StaticText(self, -1, '2 out of 7', (0, 0))     
     rowtopsizer = wx.BoxSizer(wx.HORIZONTAL) 
     rowtopsizer.Add(txtHeader, 3, wx.ALIGN_LEFT) 
     rowtopsizer.Add((0,0), 1) 
     rowtopsizer.Add(txtOutOf, 0, wx.ALIGN_RIGHT) 
     mastersizer.Add(rowtopsizer, 0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 


     # build the middle row 
     text = 'PANEL 1\n\n' 
     text = text + 'This could be a giant blob of boring text.\n' 

     txtBasic = wx.StaticText(self, -1, text) 
     font = wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.NORMAL) 
     txtBasic.SetFont(font) 
     mastersizer.Add(txtBasic, 1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 


     # build the bottom row 
     btnBack = wx.Button(self, -1, 'Back') 
     self.Bind(wx.EVT_BUTTON, self.OnBack, id=btnBack.GetId()) 
     btnNext = wx.Button(self, -1, 'Next') 
     self.Bind(wx.EVT_BUTTON, self.OnNext, id=btnNext.GetId()) 
     btnCancelExit = wx.Button(self, -1, 'Cancel and Exit') 
     self.Bind(wx.EVT_BUTTON, self.OnCancelAndExit, id=btnCancelExit.GetId()) 
     rowbottomsizer = wx.BoxSizer(wx.HORIZONTAL) 
     rowbottomsizer.Add(btnBack, 0, wx.ALIGN_LEFT) 
     rowbottomsizer.AddSpacer(5) 
     rowbottomsizer.Add(btnNext, 0) 
     rowbottomsizer.AddSpacer(5) 
     rowbottomsizer.AddStretchSpacer(1) 
     rowbottomsizer.Add(btnCancelExit, 0, wx.ALIGN_RIGHT) 
     mastersizer.Add(rowbottomsizer, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=15) 

     # finish master sizer 
     mastersizer.AddSpacer(15) 
     self.SetSizer(mastersizer) 

     self.Raise() 
     self.SetPosition((0,0)) 
     self.Fit() 
     self.Hide() 


    def ShowYourself(self): 
     self.Raise() 
     self.SetPosition((0,0)) 
     self.Fit() 
     self.Show() 


    def OnBack(self, event): 
     self.Hide() 
     self.GetParent().panel0.ShowYourself() 

    def OnNext(self, event): 
     self.Hide() 
     self.GetParent().panel0.ShowYourself() 

    def OnCancelAndExit(self, event): 
     self.GetParent().ShutDown() 


def main(): 
    app = My_App(redirect = False) 
    app.MainLoop() 


if __name__ == '__main__': 
    main() 
+0

Ich werde das untersuchen. –

+0

funktioniert es gut auf GTK –

+0

Ich frage mich, ob es einige funktionale Unterschiede zwischen GTK und Windows 7 (meine Zielplattform) gibt, die in der aktuellen Version von WxPython für Windows nicht berücksichtigt wurde. Das ist praktisch zu wissen, Steven. Es bedeutet, dass es vielleicht nicht vollständig ist, wie ich darüber nachdenke. – MetaHyperBolic

Antwort

16

Ich glaube, ich es herausgefunden. Statt Anrufe an die Show und Hide Methoden der Platten, müssen Sie die Show und Hide Methoden der Wurzel Sizer nennen:

self.Show() 

wird

self.GetParent().GetSizer().Show(self) 

... und so weiter.

Auch nach jedem Anruf, müssen Sie

self.GetParent().GetSizer().Layout() 
+0

Ich habe das getan. Ich habe die Anweisung self.SetSizer (sizer_h) in der My_Frame-Klasse verschoben, bevor die Panels erstellt wurden, oder sonst self.GetParent(). GetSizer() gibt None zurück. Danach findet es definitiv den Sizer. Aber, self.GetParent(). GetSizer(). Show (self) gibt "False" beim ersten Aufruf zurück und ich sehe beide Panels zusammengepfercht auf dem Rahmen. Sobald ich auf die Schaltflächen "Zurück" und "Weiter" klicke, kehren wir zu demselben Verhalten zurück, bei dem die Größe des Panels auf etwas verkleinert wird, das viel kleiner als der Frame ist. An diesem Punkt gibt self.GetParent(). GetSizer(). Show (self) True in der ShowYourself-Methode zurück. – MetaHyperBolic

+0

Ah, und ich habe mein Programm optimiert, als du Layout hinzugefügt hast! Etwa, um einen Schuss zu geben. – MetaHyperBolic

+0

Das hat funktioniert! Das muss nur am Ende der ShowYourself() - Funktion aufgerufen werden. Also war mein konzeptionelles Problem, dass ich die Hierarchie der Sizers ignorierte, und Ihre Lösung ist, dass auch diese aufgerufen werden müssen. Hast du eine Amazon Wunschliste, auf der ich dir ein Buch kaufen könnte? Ernsthaft, dieses spezielle Problem hat mich ziemlich niedergeschlagen. – MetaHyperBolic

2

Ja, ich weiß, das ist schon beantwortet, aber hier geht es trotzdem:

Sie sollten nur Layout() auf dem Bedienfeld des verlangen Eltern, so etwas wie self.GetParent(). Layout() sollte den Trick tun.Siehe diesen Artikel: http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/

Wenn die Schaltflächen immer angezeigt werden sollen, erstellen Sie zwei Bereiche in einem vertikalen Sizer. Der obere zeigt deine Paneele und der untere zeigt die Knöpfe. Dann benutze PubSub oder etwas, um zwischen ihnen zu kommunizieren.