首页 > 解决方案 > wx python BoxSizer没有扩展到窗口加上GUI顶部的奇怪空白

问题描述

我在正确扩展我的尺寸器时遇到了一些问题。我添加了两个子面板,我希望它们能解决我的问题,但它似乎让情况变得更糟。我希望做的是top_panel扩大到 main 的宽度范围panelvbox_top_right应该扩大以填充其余部分hbox_top。然后bottom_panel应该水平和垂直扩展以填充 main 的其余空间panel。这一切都没有发生。

一旦我将所有内容分成两个子面板,我现在遇到了一个问题,我在顶部有一个很大的空白空间。另外,我的bottom_panel似乎没有在任何地方扩展。我也不确定我SetSizerAndFit是否正确使用,因为我没有看到任何地方提到在多个面板上使用它。我只应该将它应用于 mainpanel吗?

请注意,我强制使用 wx 3.0。我安装了 2.8 和 3.0,并且在使用 2.8 时遇到了 wx.StaticBoxSizer 的问题。我知道这可能与我的问题无关,只是如果您在 2.8 中尝试该代码将无法正常工作。

代码:

import wxversion
wxversion.select('3.0')
import wx
import os
import sys


VERSION = '1.0.0'


class GUI(wx.Frame):

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title=title, pos=wx.DefaultPosition,
                          size=wx.Size(1280, 768), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
        menu_bar = wx.MenuBar()
        file_menu = wx.Menu()
        self.cwd = os.getcwd()

        # Quit code
        file_item = file_menu.Append(wx.ID_EXIT, 'Quit', 'Quit Application')
        menu_bar.Append(file_menu, '&File')
        self.SetMenuBar(menu_bar)

        # Add Main panel
        self.panel = wx.Panel(self)

        # Add Top and Bottom Panels
        self.top_panel = wx.Panel(self.panel)
        self.bottom_panel = wx.Panel(self.panel)


        # Create horizontal and vertical boxes
        self.hbox_main = wx.BoxSizer(wx.HORIZONTAL)
        self.vbox_main = wx.BoxSizer(wx.VERTICAL)
        self.hbox_top = wx.BoxSizer(wx.HORIZONTAL)
        self.vbox_top_left = wx.BoxSizer(wx.VERTICAL)
        self.vbox_top_right = wx.BoxSizer(wx.VERTICAL)

        ####################################################
        # TOP
        ####################################################

        ##########################
        # TOP LEFT
        ##########################
        # List box text
        self.lbl_filter = wx.StaticText(self.top_panel, wx.ID_ANY,
                                        u"Select all cases to apply file to",
                                        wx.DefaultPosition, wx.DefaultSize, 0)
        self.lbl_filter.Wrap(-1)
        self.vbox_top_left.Add(self.lbl_filter, 0, wx.EXPAND)

        # The list box that all the file names are in
        self.list_box = wx.CheckListBox(self.top_panel, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(300, 300),
                                        choices=[], style=wx.LB_HSCROLL|wx.LB_MULTIPLE|wx.LB_NEEDED_SB|wx.LB_SORT)
        self.vbox_top_left.Add(self.list_box, 0, wx.EXPAND, 5)

        # List box filter text
        self.lbl_filter = wx.StaticText(self.top_panel, wx.ID_ANY,
                                        u"Case filter (separate wildcards with a comma and choose filter logic (AND or OR)\n(i.e. HS, 2022 with AND selected will modify all 2022 HS cases)",
                                        wx.DefaultPosition, wx.DefaultSize, 0)
        self.lbl_filter.Wrap(-1)
        self.vbox_top_left.Add(self.lbl_filter, 0, wx.EXPAND)

        # List box filter
        self.hbox_filter = wx.BoxSizer(wx.HORIZONTAL)
        self.txt_filter = wx.TextCtrl(self.top_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
        self.txt_filter.SetMinSize(wx.Size(300, -1))
        self.hbox_filter.Add(self.txt_filter, 0, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5)

        # List box radio buttons
        logic_choices = [u"AND", u"OR"]
        self.rdo_logic = wx.RadioBox(self.top_panel, wx.ID_ANY, u"Filter Logic", wx.DefaultPosition, wx.DefaultSize,
                                     logic_choices, 1, wx.RA_SPECIFY_ROWS)
        self.rdo_logic.SetSelection(0)
        self.hbox_filter.Add(self.rdo_logic, 0, wx.EXPAND, 5)

        # Add filter stuff to vbox_top
        self.vbox_top_left.Add(self.hbox_filter, 0, wx.EXPAND)

        # Add top components to hbox
        self.hbox_top.Add(self.vbox_top_left, 0, wx.EXPAND)


        ##########################
        # TOP RIGHT
        ##########################
        # Add warning text
        self.lbl_warning = wx.StaticText(self.top_panel, wx.ID_ANY,
                                         u"*** WARNING *** HELLO WORLD ",
                                         wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTER_HORIZONTAL)
        self.lbl_warning.Wrap(-1)
        self.vbox_top_right.Add(self.lbl_warning, 0, wx.EXPAND, 5)

        # Radio buttons for software choice
        rdo_choices = [u"App 1", u"App 2", u"App 3"]
        self.rdo_software = wx.RadioBox(self.top_panel, wx.ID_ANY, u"Select Software", wx.DefaultPosition,
                                        wx.DefaultSize, rdo_choices, 1, wx.RA_SPECIFY_COLS)
        self.rdo_software.SetSelection(0)
        self.vbox_top_right.Add(self.rdo_software, 0, wx.EXPAND, 5)

        # Checkbox for archive
        self.cb_archive = wx.CheckBox(self.top_panel, wx.ID_ANY, u"Archive files before running", wx.DefaultPosition,
                                      wx.DefaultSize, 0)
        self.vbox_top_right.Add(self.cb_archive, 0, wx.EXPAND, 5)

        # Checkbox for saving
        self.cb_save = wx.CheckBox(self.top_panel, wx.ID_ANY, u"Save files after running", wx.DefaultPosition,
                                   wx.DefaultSize, 0)
        self.vbox_top_right.Add(self.cb_save, 0, wx.EXPAND, 5)

        # Folder selection label
        self.lbl_cases = wx.StaticText(self.top_panel, wx.ID_ANY, u"Select Folder With Cases", wx.DefaultPosition,
                                       wx.DefaultSize, 0)
        self.lbl_cases.Wrap(-1)
        self.vbox_top_right.Add(self.lbl_cases, 0, wx.EXPAND, 5)

        # Add Folder selection
        self.hbox_folder = wx.BoxSizer(wx.HORIZONTAL)
        self.txt_cases = wx.TextCtrl(self.top_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
        self.txt_cases.SetMinSize(wx.Size(400, -1))
        self.hbox_folder.Add(self.txt_cases, 0, wx.EXPAND, 5)

        # Folder select button
        self.btn_cases = wx.Button(self.top_panel, wx.ID_ANY, u"Case Folder", wx.DefaultPosition, wx.DefaultSize, 0)
        self.hbox_folder.Add(self.btn_cases, 0, wx.EXPAND, 5)

        # Add to sizer
        self.vbox_top_right.Add(self.hbox_folder, 1, wx.SHAPED, 5)
        self.hbox_top.Add(self.vbox_top_right, 0, wx.EXPAND, 5)
        self.vbox_main.Add(self.hbox_top, 0, wx.EXPAND)

        ####################################################
        # BOTTOM
        ####################################################

        self.bottom_box = wx.StaticBox(self.bottom_panel, label='Progress Output')
        self.hbox_output = wx.StaticBoxSizer(self.bottom_box, wx.HORIZONTAL)
        self.txt_output = wx.TextCtrl(self.bottom_box, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize,
                                      wx.TE_MULTILINE | wx.TE_READONLY)


        # Put it all together
        self.vbox_main.Add(self.top_panel, 1, wx.EXPAND)
        self.vbox_main.Add(self.bottom_panel, 1, wx.EXPAND)
        self.top_panel.SetSizerAndFit(self.hbox_top)
        self.bottom_panel.SetSizerAndFit(self.hbox_output)
        self.panel.SetSizerAndFit(self.vbox_main)
        self.Centre()
        self.Layout()


if __name__ == '__main__':
    app = wx.App(0)
    MainFrame = GUI(None, title='Batch Apply %s' % VERSION)
    app.SetTopWindow(MainFrame)
    MainFrame.Show()
    app.MainLoop()

这是GUI的粗略图 GUI的粗图

这是我得到的: 输出

标签: pythonwxwidgetsboxsizer

解决方案


主框架只有一个名为 的子框架panel。因此,当调整大小时,框架的唯一子级(不是另一种窗口)将适合其父级的客户区。好的。如果有多个孩子,情况就不是这样了。

您还有两个面板,作为panel. 例如,如果您想要不同的背景颜色,这会很好。如果没有,那就没有必要了,但是这些多余的面板并没有错。

有两个不同的区域:顶部(垂直方向不可调整大小)和底部(可调整大小)。这将需要“主尺寸器”的两个子尺寸器来处理panel. 但是您为这些区域使用了两个面板,所以最好让我们使用一个主尺寸器(我将使用vbox_main)来panel进行这两个面板内部的布局。子面板内容的布局将由 sizer 处理。

在“顶部”区域也有两个不同的区域;所以另外两个子尺寸。你的设计是正确的。

vbox_top_left希望它管理的控件( 的子级top_panel)适合可用空间。因为这是一个垂直大小,我们需要:
1)一个孩子可以改变垂直大小:使用proportion=1
2)一个孩子可以改变水平大小:使用wx.EXPAND标志。
3)如果在某些控件之间添加垂直可调整大小的间隔会很好。

vbox_top_right对由(with children of top_paneltoo)处理大小的控件应用类似的标准。

底部区域很特殊,因为您希望在标签和文本控件周围绘制一个矩形。为此,我们需要一个特殊的 sizer:StaticBoxSizer。从某种意义上说,它处理的控件不是面板的子项,而是底层wx.StaticBox. 有关示例和更多说明,请参见上面的文档链接。

self.hbox_output = wx.StaticBoxSizer(wx.HORIZONTAL, self.bottom_panel)
self.hbox_output.Add(wx.StaticText(self.hbox_output.GetStaticBox(), ....), ...)
self.hbox_output.Add(wx.TextCtrl(self.hbox_output.GetStaticBox(), ....), 1, wx.EXPAND, 5)


要将子级添加到此 sizer,请遵循与“顶部”区域相同的标准。这里没有什么特别之处。

现在,sizers 的行为(我跳过你使用的其他 sub-sizers):

# No vertical nor horizontal expanding
# self.hbox_top.Add(self.vbox_top_left, 0, wx.EXPAND) <<== not what expected
self.hbox_top.Add(self.vbox_top_left, 0)

# Only horizontal expanding
# self.hbox_top.Add(self.vbox_top_right, 0, wx.EXPAND, 5)  <<== not what expected
self.hbox_top.Add(self.vbox_top_right, 1, 0, 5)

最后一项工作是绑定面板和尺寸器:

self.top_panel.SetSizer(self.hbox_top)
self.bottom_panel.SetSizer(self.hbox_output)

# Top panel expands only in horizontal
self.vbox_main.Add(self.top_panel, 0, wx.EXPAND)
# Bottom part expands in both directions
self.vbox_main.Add(self.bottom_panel, 1, wx.EXPAND)

self.panel.SetSizerAndFit(self.vbox_main)
self.Centre()
self.Layout()

使用单个面板更容易。我使用你的两个子面板来演示它是如何工作的:主尺寸器处理子面板,每个面板都使用一个尺寸器来处理它的尺寸器来处理子面板。


推荐阅读