【问题标题】:Constrain wxPython MultiSplitterWindow panes约束 wxPython MultiSplitterWindow 窗格
【发布时间】:2013-07-23 00:56:42
【问题描述】:

编辑:我将问题保持原样,因为它仍然是一个很好的问题,答案可能对其他人有用。但是,我会注意到,通过使用与AuiManager 完全不同的方法,我找到了my 问题的实际解决方案;请参阅下面的answer

我正在处理MultiSplitterWindow 设置(在花费了大量时间之后 与SashLayoutWindow 布局怪癖作斗争)。不幸的是,当我 创建一个MultiSplitterWindow,拖动时我看到一些意外行为 sashes around:可以将窗扇拖到包含窗口的外部 布局的方向。至少可以说,这是我想避免的行为。

这是基本设置(您可以在 wxPython 中确认以下行为 演示,只需将leftwin 替换为Panel1 等,另请参见下面的示例应用程序)。在我有RootPanel/BoxSizer 的地方,有一个面板 (或Frame,或任何你喜欢的容器元素)和BoxSizer MultiSplitterWindow 添加到其中 - 再次,如在演示中。

+--------------------------------+
|       RootPanel/BoxSizer       |
|+------------------------------+|
||     MultiSplitterWindow      ||
||+--------++--------++--------+||
||| Panel1 || Panel2 || Panel3 |||
|||        ||        ||        |||
||+--------++--------++--------+||
|+------------------------------+|
+--------------------------------+

当你拖动时,你会得到类似这样的结果,~! 表示面板“存在”在那里但没有显示:

+--------------------------------+
|       RootPanel/BoxSizer       |
|+-------------------------------|~~~~~~~~~~~~~+
||           MultiSplitterWindow |             !
||+-----------------++-----------|~~++~~~~~~~~+!
|||      Panel1     ||   Panel2  |  !! Panel3 !!
|||                 ||           |  !!        !!
||+-----------------++-----------|~~++~~~~~~~~+!
|+-------------------------------|~~~~~~~~~~~~~+
+--------------------------------+

如果此时,您将RootPanel 拖到比 整个面板集,您将再次看到所有面板。同样,如果您拖动 Panel1 的宽度向后减小,您可以访问Panel3 的窗扇 再次(当然,假设Panel2 还不太宽)。此外,这 正是检查工具报告的情况:RootPanel 保留其大小,但 MultiSplitterWindow 的大小超出 RootPanel/BoxSizer.

使用检查工具进一步检查显示,虚拟和客户端宽度值都是 0,但实际大小值是 (根据将其拖出窗口的相应像素数)每当超出范围时。同样,这是疯狂的行为。我无法想象为什么有人会曾经想要一个窗口以这种方式运行。

现在,如果按住 Shift 以便 _OnMouse 方法在 MultiSplitterWindow 调整邻居,这不会发生。因此,我的一个 方法是简单地覆盖该方法。它有效,但我更愿意 如果绝对必要,以这种方式覆盖方法。还有其他更好的方法吗 解决这个问题?这似乎不是预期的或不可取的 一般行为,所以我想有一个标准的方法来修复它。

我尝试过的其他事情:

  • 检查MultiWindowSplitter中的值的总和是否超过 包含窗口的宽度,使用每个 EVT_SPLITTER_SASH_POS_CHANGEDEVT_SPLITTER_SASH_POS_CHANGING 事件, 然后尝试通过以下方式解决问题:
    • 使用event.Veto() 调用
    • 在拆分器上使用SetSashPosition() 方法
  • 覆盖_OnMouse() 方法以使用正常的行为 与按住 Shift 键相关。这有效,但最终 给我其他我不喜欢的结果。
  • 通过SetMinimumPaneSize 方法设置最小窗格大小
  • 通过SetMaxSize() 设置MultiSplitterWindow 的最大大小
  • RootPanel 上同时使用SetMaxSize()SetSizeHints() 设置RootPanel/BoxSizer 的最大大小。
    • 我什至在容器上使用wx.EVT_SIZE 的事件处理程序来完成此操作,以便RootPanel 始终具有来自父框架元素的适当最大大小
    • 我已尝试对 MultiSplitterWindow 使用相同的事件处理方法,但也没有效果。

版本信息

我已确认这出现在 Windows 32 位和 OS X 64 位中,并且 wxPython 的最新快照版本,针对 Python 2.7 和 3.3。

工作示例(包括检查工具)

以下内容基本上复制了(并略微简化了)演示源。这是对问题的有效演示。

import wx, wx.adv
import wx.lib.mixins.inspection as wit
from wx.lib.splitter import MultiSplitterWindow


class AppWInspection(wx.App, wit.InspectionMixin):
    def OnInit(self):
        self.Init()  # enable Inspection tool
        return True


class MultiSplitterFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(size=(800, 800), *args, **kwargs)
        self.SetMinSize((600, 600))

        self.top_sizer = wx.BoxSizer(orient=wx.HORIZONTAL)
        self.SetSizer(self.top_sizer)

        self.splitter = MultiSplitterWindow(parent=self, style=wx.SP_LIVE_UPDATE)
        self.top_sizer.Add(self.splitter, wx.SizerFlags().Expand().Proportion(1).Border(wx.ALL, 10))

        inner_panel1 = wx.Panel(parent=self.splitter)
        inner_panel1.SetBackgroundColour('#999980')
        inner_panel1_text = wx.StaticText(inner_panel1, -1, 'Inner Panel 1')
        inner_panel1.SetMinSize((100, -1))

        inner_panel2 = wx.Panel(parent=self.splitter)
        inner_panel2.SetBackgroundColour('#999990')
        inner_panel2_text = wx.StaticText(inner_panel2, -1, 'Inner Panel 2')
        inner_panel2.SetMinSize((100, -1))
        inner_panel2.SetMaxSize((100, -1))

        inner_panel3 = wx.Panel(parent=self.splitter)
        inner_panel3.SetBackgroundColour('#9999A0')
        inner_panel3_text = wx.StaticText(inner_panel3, -1, 'Inner Panel 3')
        inner_panel3.SetMinSize((100, -1))

        self.splitter.AppendWindow(inner_panel1)
        self.splitter.AppendWindow(inner_panel2)
        self.splitter.AppendWindow(inner_panel3)

if __name__ == '__main__':
    app = AppWInspection(0)
    frame = MultiSplitterFrame(parent=None, title='MultiSplitterFrame Test')
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()

【问题讨论】:

  • 贴一个演示问题的小示例代码......解释很好,但看到实现将帮助你得到答案
  • @JoranBeasley 正如解释中所述,任何人都可以查看的最佳位置是wxPython demo。不过,如果您认为它确实有用,我可以复制它。
  • 我明白了...是的,这很奇怪...抱歉:/您可以将 size 事件侦听器绑定到父级并 onsize 检查边界并更新它们...但是有点痛苦
  • 是的,我想过这样做。在这一点上,你并没有比仅仅使用一组SashLayoutWindow 组件获得太多好处(除了一些更简单的初始布局),还有一些可能更奇怪的东西,因为你有默认行为要覆盖。
  • 布局真的没那么糟糕。您只需要提前计划您的应用程序。我通常勾勒出我的草图并画出盒子来了解需要去哪里。然后我可以决定是只需要嵌套的 BoxSizer(通常)还是混合使用嵌套的 BoxSizer 和其他 sizer。

标签: python layout wxpython


【解决方案1】:

根据用户对此的需求,可以使用高级用户界面工具包的 AuiManager 工具(用于预先凤凰版here;凤凰文档here)。 AuiManager 为您自动化了很多此类事情。就我而言,我试图使用MultiSplitterWindow 作为控制相关UI 的可折叠和可调整大小面板的一种方式,因此AuiManager 非常适合:它已经具有我需要内置的所有控件和约束.

在这种情况下,只需创建一个AuiManager 实例

(我将其作为 an 答案留在这里,希望其他可能采用与我相同的幼稚方法的人会发现它很有用,但不选择它作为答案,因为它确实直接回答原问题。)

Phoenix下AUI使用示例

此代码示例完全符合我对MultiSplitterWindow 的要求,但由AuiManager 自动管理。

import wx, wx.adv
import wx.lib.mixins.inspection as wit
from wx.lib.agw import aui


class AppWInspection(wx.App, wit.InspectionMixin):
    def OnInit(self):
        self.Init()  # enable Inspection tool
        return True


class AuiFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(size=(800, 800), *args, **kwargs)
        self.SetMinSize((600, 600))

        # Create an AUI Manager and tell it to manage this Frame
        self._manager = aui.AuiManager()
        self._manager.SetManagedWindow(self)

        inner_panel1 = wx.Panel(parent=self)
        inner_panel1.SetBackgroundColour('#999980')
        inner_panel1.SetMinSize((100, 100))
        inner_panel1_info = aui.AuiPaneInfo().Name('inner_panel1').Caption('Inner Panel 1').Left().\
            CloseButton(True).MaximizeButton(True).MinimizeButton(True).Show().Floatable(True)

        inner_panel2 = wx.Panel(parent=self)
        inner_panel2.SetBackgroundColour('#999990')
        inner_panel2_info = aui.AuiPaneInfo().Name('inner_panel2').Caption('Inner Panel 2').Left().Row(1).\
            Show().Floatable(False)

        inner_panel3 = wx.Panel(parent=self)
        inner_panel3.SetBackgroundColour('#9999A0')
        inner_panel3.SetMinSize((100, 100))
        inner_panel3_info = aui.AuiPaneInfo().Name('inner_panel3').Caption('Inner Panel 3').CenterPane()

        self._manager.AddPane(inner_panel1, inner_panel1_info)
        self._manager.AddPane(inner_panel2, inner_panel2_info)
        self._manager.AddPane(inner_panel3, inner_panel3_info)
        self._manager.Update()

    def __OnQuit(self, event):
        self.manager.UnInit()
        del self.manager
        self.Destroy()

if __name__ == '__main__':
    app = AppWInspection(0)
    frame = AuiFrame(parent=None, title='AUI Manager Test')
    app.SetTopWindow(frame)
    frame.Show()
    app.MainLoop()

【讨论】:

    【解决方案2】:

    我会尝试设置面板的 MaxSize 甚至求助​​于 SetSizeHints()。这两者都允许您对小部件的大小设置一些限制。

    【讨论】:

    • 我实际上以为我已经尝试过了,但我会试一试。
    • 好的,所以,经过进一步测试:(1)SetMaxSize()SetSizeHints() 都没有任何效果。此外,使用检查工具进行的进一步调查表明,屏幕外面板的虚拟或客户端宽度为零,但 实际 宽度具有 值。 got 有办法禁止这种行为;我想不出你为什么会想要它。请注意,我也将此信息添加到问题中。
    • 我从 wxPython 邮件列表链接到您的问题,因为我不确定这里发生了什么。
    • 谢谢。我已经订阅了那个主题,所以我应该会看到那里的任何更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 2010-10-06
    • 2021-11-17
    相关资源
    最近更新 更多