2010-04-01 36 views
10

Comme référencé dans mon previous question, j'essaye de faire quelque chose de légèrement magicien en fonction. Je me suis installé sur une seule image avec un calibreur ajouté. Je construis des panneaux pour chacun des écrans que je voudrais que les utilisateurs voient, les ajoute au calibreur du cadre, puis permute entre les panneaux par .Hide() sur un panneau, puis appelle un .ShowYourself() personnalisé sur le panneau suivant. Évidemment, j'aimerais que les boutons restent au même endroit pendant que l'utilisateur progresse dans le processus.Pourquoi .Hide() ing et .Show() des panneaux dans wxPython aboutissent-ils à la modification de la mise en page?

J'ai relié deux panneaux dans une boucle infinie par leurs boutons "Précédent" et "Suivant" afin que vous puissiez voir ce qui se passe. Le premier panneau est superbe. Le code de tom10 a fonctionné à ce niveau, car il a évité ma première tentative de fantaisie avec des frontières qui volaient dans tous les sens. Et puis le deuxième panel semble s'être réduit au strict minimum. En revenant au premier panel, le rétrécissement s'est également produit ici. Pourquoi ça a l'air bien sur le premier panneau, mais pas après mon retour? Pourquoi appeler .Fit() nécessaire si je ne veux pas un wad de 10 pixels par 10 pixels de gris? Et si cela est nécessaire, pourquoi .Fit() donne des résultats incohérents?

Cette boucle infinie semble caractériser mon expérience avec ceci: je fixe la mise en page sur un panneau, seulement pour constater que la commutation ruine la disposition pour d'autres panneaux. Je corrige ce problème, en utilisant sizer_h.Add(self.panel1, 0) au lieu de sizer_h.Add(self.panel1, 1, wx.EXPAND), et maintenant mes mises en page sont de nouveau hors tension. Jusqu'ici, ma «solution» consiste à ajouter un mastersizer.SetMinSize((475, 592)) au calibreur principal de chaque panneau (commenté dans le code ci-dessous). Ceci est une solution cruddy parce que 1) J'ai dû trouver les nombres qui fonctionnent par essais et erreurs (-5 pixels pour la largeur, -28 pixels pour la hauteur). 2) Je ne comprends pas pourquoi le problème sous-jacent se produit encore.

Quelle est la solution correcte et non-laide? Au lieu d'ajouter tous les panneaux au calibreur du cadre en même temps, les panneaux de commutation doivent-ils impliquer ce panneau à partir du calibreur du cadre, puis .Add() le panneau suivant au calibreur du cadre? Existe-t-il une méthode .JustMakeThisFillThePanel() qui cache quelque part les documents wxWidgets et wxPython que j'ai manqués en ligne? Je manque évidemment quelque chose dans mon modèle mental de mise en page. Code minimaliste collé ci-dessous.

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

Je vais examiner cela. –

+0

ça marche bien sur GTK –

+0

Je me demande s'il y a une différence fonctionnelle entre GTK et Windows 7 (ma plate-forme cible) qui n'a pas été prise en compte dans la version actuelle de wxPython pour Windows. C'est pratique à savoir, Steven. Cela veut dire que peut-être que je ne pense pas à cela n'est pas complètement éteint. – MetaHyperBolic

Répondre

16

Je pense que je compris. Au lieu d'appels aux méthodes de Show et Hide les panneaux, vous devez appeler les Show et Hide méthodes de la sizer racine:

self.Show() 

devient

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

... et ainsi de suite.

En outre, après chaque appel, vous avez besoin

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

Je l'ai fait. J'ai déplacé l'instruction self.SetSizer (sizer_h) dans la classe My_Frame avant la création des panneaux, ou bien self.GetParent(). GetSizer() renvoie None. Après cela, il trouve définitivement le calibreur. Mais, self.GetParent(). GetSizer(). Show (self) renvoie "False" sur le premier appel et je vois les deux panneaux entassés sur le cadre. Une fois que je commence à cliquer sur les boutons Précédent et Suivant, nous revenons au même comportement de réduction de la taille du panneau à quelque chose de beaucoup plus petit que le cadre. À ce stade, self.GetParent(). GetSizer(). Show (self) renvoie True dans la méthode ShowYourself. – MetaHyperBolic

+0

Ah, et je peaufinais mon programme lorsque vous avez ajouté Layout! Sur le point de donner un coup de feu. – MetaHyperBolic

+0

Cela a fonctionné! Cela doit uniquement être appelé à la fin de la fonction ShowYourself(). Donc, mon problème conceptuel était que j'ignorais la hiérarchie des calibreurs, et votre solution est que ceux-ci aussi doivent être appelés. Avez-vous une liste de souhaits Amazon où je pourrais vous acheter un livre? Sérieusement, ce problème particulier m'avait tout à fait déprimé. – MetaHyperBolic

2

Ouais, je sais que cela est déjà répondu, mais là, vous aller quand même:

Vous ne devriez avoir à appeler la mise en page() sur le panneau de parent, donc quelque chose comme self.GetParent(). Layout() devrait faire l'affaire.Voir cet article: http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/

Si vous voulez que les boutons apparaissent toujours, créez deux panneaux dans un calibreur vertical. Celui sur le dessus montrera vos panneaux et celui sur le fond montrera les boutons. Ensuite, utilisez PubSub ou quelque chose pour communiquer entre eux.