wxPython 分层布局似乎没有正确调整大小

wxPython hierarchical layout appears to be not sizing things correctly

我无法弄清楚为什么我的分层布局没有像我在 wxPython 中期望的那样。

基本思路如下:

+- Win1 ------+ +- Win2 -----+ +- Win3 ----------+
|             | |            | |                 |
+-------------+ +------------+ +-----------------+
+- Win4 ----------+ +- Win5 ---------------------+
|                 | |                            |
+-----------------+ +----------------------------+
+- Win6 -----------------------------------------+
|                                                |
+------------------------------------------------+

我正在创建一个垂直框布局来处理三个区域 {1/2/3, 4/5, 6}。在每个区域中都有另一个(水平)框布局来处理(例如,在第一个区域中){1, 2, 3} 子区域。

然后,在每个子区域中,我都有一个静态框大小调整器,它给我一个带有多行、用户不可编辑的文本控件的边框。

现在下面的代码已简化为两行,第一行有两列,第二行有一列。只有第一行的第一列是尝试绘制nice-border控件,其他都是静态文本控件。

import wx

class MyFrame(wx.Frame):
    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, pos=(150,50), size=(1720,930))
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self.topPanel = wx.Panel(self, wx.ID_ANY)

        self.screenPanel = wx.Panel(self.topPanel, wx.ID_ANY)
        self.spacer0 = wx.StaticText(self.topPanel, wx.ID_ANY, "")
        self.dummy1 = wx.StaticText(self.topPanel, wx.ID_ANY, "dummy1")
        self.dummy2 = wx.StaticText(self.topPanel, wx.ID_ANY, "dummy2")

        self.topSizer = wx.BoxSizer(wx.VERTICAL)
        self.row1Sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.row2Sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.screenSizer = wx.StaticBoxSizer(wx.HORIZONTAL,
            self.screenPanel, "Screen")

        self.screen = wx.TextCtrl(self.screenPanel, wx.ID_ANY,
            "This is the first line\nXYZZY\nPLUGH",
            wx.DefaultPosition, wx.DefaultSize,
            wx.TE_MULTILINE | wx.TE_READONLY)

        self.row1Sizer.Add(self.screenSizer, 0, wx.ALL, 5)
        self.row1Sizer.Add(self.spacer0, 1, wx.ALL, 5)
        self.row1Sizer.Add(self.dummy1, 0, wx.ALL, 5)

        self.row2Sizer.Add(self.dummy2, 0, wx.ALL, 5)

        self.topSizer.Add(self.row1Sizer, 0, wx.ALL | wx.EXPAND, 5)
        self.topSizer.Add(self.row2Sizer, 0, wx.ALL | wx.EXPAND, 5)

        self.screenPanel.SetSizer(self.screenSizer)
        self.topPanel.SetSizer(self.topSizer)
        self.topPanel.Layout()

    def OnClose(self, event):
        self.Destroy()

app = wx.App()
top = MyFrame("My")
top.Show()
app.MainLoop()

但是,似乎有一些问题,我 认为 可能是由于我对 sizer 还是非 sizer 应该拥有被控制的资源感到困惑,但我无法得到它的行为。目前的代码给了我:

如您所见,第一个控件周围的静态框似乎不见了,大小调整也出现问题。我原以为尺寸会在布局上计算,这样它至少足以容纳内部控件和边框。

谁能告诉我这段代码做错了什么?

It's also crashing on exit, which may be related. If not, I can handle that as a separate issue.

The static box may be either created independently or the sizer may create it itself as a convenience. In any case, the sizer owns the wx.StaticBox control and will delete it in the wx.StaticBoxSizer destructor.

Note that since wxWidgets 2.9.1 you are encouraged to create the windows which are added to wx.StaticBoxSizer as children of wx.StaticBox

所以像这样:

import wx

class MyFrame(wx.Frame):
    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, pos=(150,50), size=(500,400))
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.SetMinSize((500,400))
        self.topPanel = wx.Panel(self, wx.ID_ANY)

        box1 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win1")
        box1.SetForegroundColour('#000000')

        self.textCtrl1 = wx.TextCtrl(box1, wx.ID_ANY,
            "This is the first line\nXYZZY\nPLUGH",
            wx.DefaultPosition, size = (200,100), style = wx.TE_MULTILINE | wx.TE_READONLY)
        self.dummy4 = wx.StaticText(box1, wx.ID_ANY, "Text below textctrl 1")

        boxSizer1 = wx.StaticBoxSizer(box1, wx.VERTICAL)
        boxSizer1.Add(self.textCtrl1, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)
        boxSizer1.Add(self.dummy4, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        box2 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win2")
        box2.SetForegroundColour('#000000')

        self.spacer = wx.StaticText(box2, wx.ID_ANY, "A spacer")

        boxSizer2 = wx.StaticBoxSizer(box2, wx.VERTICAL)
        boxSizer2.Add(self.spacer, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        box3 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win3")
        box3.SetForegroundColour('#000000')

        self.dummy1 = wx.StaticText(box3, wx.ID_ANY, "dummy text 1")

        boxSizer3 = wx.StaticBoxSizer(box3, wx.VERTICAL)
        boxSizer3.Add(self.dummy1, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        box4 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win4")
        box4.SetForegroundColour('#000000')

        self.textCtrl2 = wx.TextCtrl(box4, wx.ID_ANY,
            "This is the second line\nXYZZY\nPLUGH",
            wx.DefaultPosition, size = (200,100), style = wx.TE_MULTILINE | wx.TE_READONLY)

        boxSizer4 = wx.StaticBoxSizer(box4, wx.VERTICAL)
        boxSizer4.Add(self.textCtrl2, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        box5 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win5")
        box5.SetForegroundColour('#000000')

        self.dummy2 = wx.StaticText(box5, wx.ID_ANY, "dummy text 2")

        boxSizer5 = wx.StaticBoxSizer(box5, wx.VERTICAL)
        boxSizer5.Add(self.dummy2, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        box6 = wx.StaticBox(self.topPanel, wx.ID_ANY, "Win6")
        box6.SetForegroundColour('#000000')

        self.dummy3 = wx.StaticText(box6, wx.ID_ANY, "dummy text 3")

        boxSizer6 = wx.StaticBoxSizer(box6, wx.VERTICAL)
        boxSizer6.Add(self.dummy3, proportion = 0, flag=wx.ALIGN_CENTER|wx.EXPAND)

        self.topSizer = wx.BoxSizer(wx.VERTICAL)
        self.row1Sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.row2Sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.row3Sizer = wx.BoxSizer(wx.HORIZONTAL)


        self.row1Sizer.Add(boxSizer1, 0, wx.ALL, 5)
        self.row1Sizer.Add(boxSizer2, 1, wx.ALL|wx.EXPAND, 5) #Matches size of box1
        self.row1Sizer.Add(boxSizer3, 0, wx.ALL|wx.EXPAND, 5) #Matches size of box1

        self.row2Sizer.Add(boxSizer4, 0, wx.ALL, 5)
        self.row2Sizer.Add(boxSizer5, 1, wx.ALL, 5) # Does not match size of box4

        self.row3Sizer.Add(boxSizer6, 1, wx.ALL, 5)

        self.topSizer.Add(self.row1Sizer, 0, wx.ALL | wx.EXPAND, 5)
        self.topSizer.Add(self.row2Sizer, 0, wx.ALL | wx.EXPAND, 5)
        self.topSizer.Add(self.row3Sizer, 0, wx.ALL | wx.EXPAND, 5)

        self.topPanel.SetSizer(self.topSizer)
        self.topPanel.Layout()

    def OnClose(self, event):
        self.Destroy()

app = wx.App()
top = MyFrame("My Window Layout")
top.Show()
app.MainLoop()

但是,请注意,有时您 OS 桌面上的主题无法处理框,所以它不是给定的!
具体来说,Linux Mint 上的 Mint-X 惨遭失败,主题为 Mint-X 的相同代码,看起来像这样。

您的原始代码只需稍作修改即可使用。
我仍然无法通过将 screenSizer 添加到 row1Sizer 来解决 screenPanel 的问题,除了 screen 永远不会添加到 sizer 并且不会扩展.
您修改后的代码(已注明修改):

import wx

class MyFrame(wx.Frame):
    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title, pos=(150,50), size=(420,230))
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self.topPanel = wx.Panel(self, wx.ID_ANY)

        ##self.screenPanel = wx.Panel(self.topPanel, wx.ID_ANY)
        self.spacer0 = wx.StaticText(self.topPanel, wx.ID_ANY, "")
        self.dummy1 = wx.StaticText(self.topPanel, wx.ID_ANY, "dummy1")
        self.dummy2 = wx.StaticText(self.topPanel, wx.ID_ANY, "dummy2")

        self.topSizer = wx.BoxSizer(wx.VERTICAL)
        self.row1Sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.row2Sizer = wx.BoxSizer(wx.HORIZONTAL)

        ##self.screenSizer = wx.StaticBoxSizer(wx.HORIZONTAL,
        ##    self.screenPanel, "Screen")
        self.screenSizer = wx.StaticBoxSizer(wx.HORIZONTAL,
            self.topPanel, "Screen")

        ##self.screen = wx.TextCtrl(self.screenPanel, wx.ID_ANY,
        self.screen = wx.TextCtrl(self.topPanel, wx.ID_ANY,
            "This is the first line\nXYZZY\nPLUGH",
            wx.DefaultPosition, wx.DefaultSize,
            wx.TE_MULTILINE | wx.TE_READONLY)

        ##Additional line
        self.screenSizer.Add(self.screen, 0, wx.ALL|wx.EXPAND, 5)
        ##
        self.row1Sizer.Add(self.screenSizer, 0, wx.ALL|wx.EXPAND, 5)
        self.row1Sizer.Add(self.spacer0, 1, wx.ALL, 5)
        self.row1Sizer.Add(self.dummy1, 0, wx.ALL, 5)

        self.row2Sizer.Add(self.dummy2, 0, wx.ALL, 5)

        self.topSizer.Add(self.row1Sizer, 0, wx.ALL | wx.EXPAND, 5)
        self.topSizer.Add(self.row2Sizer, 0, wx.ALL | wx.EXPAND, 5)

        ##self.screenPanel.SetSizer(self.screenSizer)
        self.topPanel.SetSizer(self.topSizer)
        self.topPanel.Layout()

    def OnClose(self, event):
        self.Destroy()

app = wx.App()
top = MyFrame("My")
top.Show()
app.MainLoop()

结果: