为什么.hide()ing和.Show()面板在wxPython中导致Sizer更改布局?

时间:2010-04-01 16:46:20

标签: wxpython wxwidgets sizer

正如我previous question中提到的那样,我试图在功能上做一些类似向导的东西。我已经选择了添加了sizer的单帧。我为希望用户看到的每个屏幕构建面板,将它们添加到框架的sizer中,然后通过.Hide()一个面板在面板之间切换,然后在下一个面板上调用自定义.ShowYourself()。显然,我希望按钮与用户在整个过程中保持同一位置。

我通过“Back”和“Next”按钮将两个面板链接在一个无限循环中,这样你就可以看到发生了什么。第一个小组看起来很棒; tom10的代码在那个级别上起作用,因为它避开了我最初的,过度花哨的尝试,边界各处飞行。然后第二个小组似乎缩小到最低限度。当我们返回第一个面板时,这里也发生了收缩。为什么它在第一个面板上看起来很好,但是在我返回后没有?如果我不想要10像素乘10像素的灰色,为什么要调用.Fit()?如果有必要,为什么.Fit()会产生不一致的结果?

这个无限循环似乎是我对此经历的一个特征:我在面板上修复了布局,但却发现切换会破坏其他面板的布局。我使用sizer_h.Add(self.panel1, 0)代替sizer_h.Add(self.panel1, 1, wx.EXPAND)解决了这个问题,现在我的布局再次关闭了。

到目前为止,我的“解决方案”是为每个面板的主sizer添加mastersizer.SetMinSize((475, 592))(在下面的代码中注释掉)。这是一个肮脏的解决方案,因为1)我必须找到通过试验和错误工作的数字(宽度为-5像素,高度为-28像素)。 2)我不明白为什么潜在的问题仍然存在。

什么是正确的,非丑陋的解决方案?不是一次将所有面板添加到框架的大小调整器中,切换面板是否需要.Detach()来自框架大小调整器的面板,然后.Add()将下一个面板添加到框架的大小调整器中?是否有.JustMakeThisFillThePanel()方法隐藏在wxWidgets和wxPython在线文档中我错过的地方?

我在布局的心智模型中显然遗漏了一些东西。下面粘贴了极简主义代码。

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

2 个答案:

答案 0 :(得分:17)

我想我明白了。您需要调用根分析器的ShowHide方法,而不是调用面板的ShowHide方法:

self.Show()

变为

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

......等等。

此外,每次通话后,您都需要

self.GetParent().GetSizer().Layout()

答案 1 :(得分:4)

是的,我知道这已经回答了,但无论如何你要去了:

你应该只需要调用面板父节点上的Layout(),这样就像self.GetParent()。Layout()应该这样做。请参阅此文章:http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/

如果您希望按钮始终显示,请在一个垂直尺寸显示器中创建两个面板。顶部的那个将显示您的面板,底部的一个将显示按钮。然后使用PubSub或其他东西在它们之间进行通信。