【问题标题】:Multiple panels with BoxSizer使用 BoxSizer 的多个面板
【发布时间】:2019-04-19 12:33:39
【问题描述】:

我正在尝试将单个面板分成两个面板。 所以 Button1 应该在一个面板中 abd Button 2 , 3, 4 应该在另一个面板上。

这是我无法正确显示面板的可运行代码。

import wx
from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure


class Frame1(wx.Frame):

    def __init__(self, parent):

        wx.Frame.__init__(self, None,
                          pos=wx.Point(0, 0),size=wx.Size(800, 200),
                          style=wx.DEFAULT_FRAME_STYLE | wx.MAXIMIZE )

        self.panel1 = wx.Panel(self)
        self.panel2 = wx.Panel(self)
        #self.panel1.SetBackgroundColour('blue')
        self.panel3 = wx.Panel(self)
        self.panel4 = wx.Panel(self)
        self.panel3.SetBackgroundColour('red')


        sizer1 = wx.BoxSizer(wx.VERTICAL)
        sizer1.Add(self.panel4, 1, wx.EXPAND)
        sizer1.Add(self.panel1, 1, wx.EXPAND)
        self.SetSizer(sizer1)
        sizer1.Fit(self)

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(sizer1, 1, wx.EXPAND)
        sizer.Add(self.panel2, 1, wx.EXPAND)
        sizer.Add(self.panel3, 1, wx.EXPAND)
        self.SetSizer(sizer)
        #sizer.Fit(self)


        self.log = wx.TextCtrl(self.panel3, style=wx.TE_RICH|wx.TE_MULTILINE)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.log, 1, wx.EXPAND|wx.ALL, 15)
        self.panel3.SetSizer(sizer)

        emptycell = (0,0)
        self.button1 = wx.Button(self.panel4, -1, "Button1", size=wx.Size(150, 70))
        self.button2 = wx.Button(self.panel1, -1, "Button2")
        self.button3 = wx.Button(self.panel1, -1, "Button3")
        self.button4 = wx.Button(self.panel1, -1, "Button4")

        sizer = wx.GridSizer(8,3,0,0)

        sizer.Add(emptycell, 0, wx.EXPAND)
        sizer.Add(self.button1, 0, wx.ALIGN_CENTER|wx.LEFT, 10)
        sizer.Add(emptycell, 0, wx.EXPAND)
        sizer.Add(self.button2, 0, wx.ALIGN_CENTER)
        sizer.Add(self.button3, 0, wx.ALIGN_CENTER)
        sizer.Add(self.button4, 0, wx.ALIGN_CENTER)
        self.panel1.SetSizer(sizer)



        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.panel2, -1, self.figure)

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.canvas, 0, wx.EXPAND)
        self.panel2.SetSizer(sizer)
        #self.panel2.Fit()


        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)

        #self.Center()


#Every wxWidgets application must have a class derived from wxApp
class MyApp(wx.App):
    # wxWidgets calls this method to initialize the application
    def OnInit(self):

        # Create an instance of our customized Frame class
        self.frame = Frame1(None)
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == '__main__':
    application = MyApp(0)
    application.MainLoop()

想要的结果

实际结果

【问题讨论】:

  • 这看起来像是一个“错误的父母”问题。确保您使用正确的父级创建按钮,并且不会破坏 sizer 层次结构。我会研究 RAD 工具(wxGlade、wxFormBuilder 等)。安装它,运行它,让它生成代码,然后看看它生成了什么。这将是一个很好的训练练习。您将更好地了解如何使用 sizer,并且将来能够更轻松地手动完成。

标签: python wxpython wxwidgets


【解决方案1】:

我不得不稍微修改一下,但尝试为每个面板设置一个自己的大小,并在最后将它们组合在一起。另外,请使用描述性名称,否则很快就会变成泥潭,难以理解。

import wx
from numpy import arange, sin, pi
import matplotlib
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure


class Frame1(wx.Frame):

    def __init__(self, parent):

        wx.Frame.__init__(self, None,
                          pos=wx.Point(0, 0),size=wx.Size(800, 200),
                          style=wx.DEFAULT_FRAME_STYLE | wx.MAXIMIZE )

        self.panel1_1 = wx.Panel(self)
        self.panel1_2 = wx.Panel(self)
        self.panel2 = wx.Panel(self)
        self.panel3 = wx.Panel(self)
        self.panel3.SetBackgroundColour('red')
        self.panel1_1.SetBackgroundColour('green')
        self.panel1_2.SetBackgroundColour('blue')


        self.log = wx.TextCtrl(self.panel3, style=wx.TE_RICH|wx.TE_MULTILINE)
        log_sizer = wx.BoxSizer(wx.HORIZONTAL)
        log_sizer.Add(self.log, 1, wx.EXPAND|wx.ALL, 15)
        self.panel3.SetSizer(log_sizer)

        self.button1 = wx.Button(self.panel1_1, -1, "Button1", size=wx.Size(150, 70))

        button_sizer1 = wx.GridSizer(1,3,0,0)
        button_sizer1.Add((0,0), 0, wx.ALL, 10)
        button_sizer1.Add(self.button1, 0, wx.ALL, 10)
        button_sizer1.Add((0,0), 0, wx.ALL, 10)
        self.panel1_1.SetSizer(button_sizer1)

        self.button2 = wx.Button(self.panel1_2, -1, "Button2")
        self.button3 = wx.Button(self.panel1_2, -1, "Button3")
        self.button4 = wx.Button(self.panel1_2, -1, "Button4")

        button_sizer2 = wx.GridSizer(1,3,0,0)
        button_sizer2.Add(self.button2, 0, wx.ALL|wx.ALIGN_LEFT, 10)
        button_sizer2.Add(self.button3, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 10)
        button_sizer2.Add(self.button4, 0, wx.ALL|wx.ALIGN_RIGHT, 10)
        self.panel1_2.SetSizer(button_sizer2)

        main_button_sizer = wx.BoxSizer(wx.VERTICAL)
        main_button_sizer.Add(self.panel1_1)
        main_button_sizer.Add(self.panel1_2, 1, wx.EXPAND)

        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.panel2, -1, self.figure)

        fig_sizer = wx.BoxSizer(wx.HORIZONTAL)
        fig_sizer.Add(self.canvas, 0, wx.EXPAND)
        self.panel2.SetSizer(fig_sizer)

        main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(main_button_sizer, 1, wx.EXPAND)
        main_sizer.Add(self.panel2, 1, wx.EXPAND)
        main_sizer.Add(self.panel3, 1, wx.EXPAND)
        self.SetSizer(main_sizer)
        self.Layout()

        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)


#Every wxWidgets application must have a class derived from wxApp
class MyApp(wx.App):
    # wxWidgets calls this method to initialize the application
    def OnInit(self):

        # Create an instance of our customized Frame class
        self.frame = Frame1(None)
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == '__main__':
    application = MyApp(0)
    application.MainLoop()

【讨论】:

  • 正如问题中所写,我正在尝试将按钮 1 和其余按钮分开。因此,只需要面板 4 中的 1 个按钮(按钮 1)和(面板 1)中的其余按钮。面板 2 是图形,面板 3 是红色背景面板。您提供的解决方案正是我目前在我的系统上运行的。但这不是我想要的。
  • 天哪!我再次入侵了第四个面板,但具体到什么程度尚不清楚。希望它现在接近您想要实现的目标。为什么是第四个面板?
  • 第四个面板是 gui 启动时唯一的活动面板。一旦用户按下第四个面板中的按钮,其他面板就会激活。
  • 如果你给面板上色,你会看到 panel1_2 直到底部才展开。
【解决方案2】:

哎呀,其中一些 panel 和 sizer 变量名称很难理解。

在处理 wx 时,保持对哪些窗口(因此,面板、按钮等)将位于其他窗口内的良好跟踪可能会有所帮助,并注意您如何声明父级每一个。

例如,如果您有一个包含多个元素的面板(例如,panel1),那么当您实例化这些元素时,将它们的父级全部设置为 panel1。例如,当您创建self.button1 时,将其父级设置为panel1(与您的其他按钮相同),因为您将所有这些都放入panel1

这是因为 wx 会自然而然地尝试将 windows 放入其父对象内部。当一个窗口有一个父元素是一个元素,但一个 sizer 试图将它放在另一个元素中时,事情会变得非常棘手。很难完全理解,但我想这就是你的问题所在。

另一件事将使您的代码 (a) 更易于阅读/遵循/调试,并且 (b) 工作得更好,是:不要害怕实例化多个 sizer 变量。更好的是,给他们起与他们正在组织的小组相匹配的名字!

我发现将__init__ 函数分为三个部分很有帮助(这也可能对您有用):(1) 从“顶层”向下实例化您需要的所有窗口/对象,为它们分配正确的父窗口; (2) 实例化所有的sizer,每个包含其他元素的窗口一个; (3) 从“底层”向上,将窗口添加到它们的父尺寸器,在每个父面板上调用SetSizer,并一直工作直到您为顶级窗口设置主尺寸器。

如果这不适合你,请随时给我发消息,我们会看看我们是否可以解析为什么 wx 不能正常工作。

【讨论】:

  • 感谢您的提示。最好是一个答案。该代码非常简单,并且是一个示例。复制并粘贴到您的系统中,它应该会运行
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多