Почему .Hide () и .Show () панели в wxPython приводят к изменению макета Sizer? - PullRequest
12 голосов
/ 01 апреля 2010

Как указано в моем предыдущем вопросе , я пытаюсь сделать что-то немного похожее на волшебство в функции. Я остановился на одном кадре с добавленным в него сайзером. Я строю панели для каждого из экранов, которые должны видеть пользователи, добавляю их в размер рамки, затем переключаюсь между панелями с помощью .Hide() на одной панели, затем вызываю пользовательский .ShowYourself() на следующей панели. Очевидно, я бы хотел, чтобы кнопки оставались в том же месте, что и пользователь во время процесса.

Я связал две панели в бесконечном цикле с помощью кнопок «Назад» и «Далее», чтобы вы могли видеть, что происходит. Первая панель выглядит великолепно; Код tom10 работал на этом уровне, поскольку он избегал моей первоначальной, чрезмерной попытки сделать границы, летящие в разные стороны. И тогда вторая панель, кажется, сократилась до минимума. Когда мы вернемся к первой панели, усадка произошла и здесь. Почему на первой панели все выглядит нормально, а не после того, как я туда вернусь? Зачем нужен .Fit(), если я не хочу, чтобы 10 на 10 пикселей был серым? И если это необходимо, почему .Fit() дает противоречивые результаты?

Этот бесконечный цикл, кажется, характеризует мой опыт с этим: я фиксирую макет на панели, только чтобы обнаружить, что переключение разрушает макет для других панелей. Я исправил эту проблему, используя sizer_h.Add(self.panel1, 0) вместо sizer_h.Add(self.panel1, 1, wx.EXPAND), и теперь мои макеты снова отключены.

Пока что мое "решение" заключается в добавлении 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 ]

17 голосов
/ 02 апреля 2010

Думаю, я понял это. Вместо вызовов методов Show и Hide панелей, вам нужно вызвать методы Show и Hide корневого классификатора:

self.Show()

становится

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

... и т. Д.

Также после каждого звонка вам нужно

self.GetParent().GetSizer().Layout()
4 голосов
/ 05 апреля 2011

Да, я знаю, что на это уже есть ответ, но все равно вы идете:

Вам нужно всего лишь вызвать Layout () для родительского элемента панели, поэтому что-то вроде self.GetParent (). Layout () должно помочь. Смотрите эту статью: http://www.blog.pythonlibrary.org/2010/06/16/wxpython-how-to-switch-between-panels/

Если вы хотите, чтобы кнопки всегда отображались, создайте две панели в одном вертикальном классификаторе. Один сверху покажет ваши панели, а другой внизу покажет кнопки. Затем используйте PubSub или что-то еще для связи между ними.

...