约束wxPython MultiSplitterWindow窗格

时间:2013-07-23 19:07:04

标签: python layout wxpython

编辑:我将问题保持原样,因为它仍然是一个很好的问题,答案可能对其他人有用。但是,我会注意到,通过使用与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方法
  • 设置最小窗格大小
  • 通过MultiSplitterWindow
  • SetMaxSize()上设置最大尺寸
  • 使用RootPanel/BoxSizer上的SetMaxSize()SetSizeHints()设置RootPanel的最大尺寸。
    • 我甚至在容器上使用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()

2 个答案:

答案 0 :(得分:3)

根据用户的需要,使用一种可能的选项而不是自定义管理的MultiSplitterWindow(或SashLayoutWindow组合等)是高级用户界面工具包的AuiManager工具(凤凰城前版本here的文档;凤凰文档here)。 AuiManager为您自动完成了很多这类事情。就我而言,我试图使用MultiSplitterWindow作为控制相关UI的可折叠和可调整大小的面板的方法,因此AuiManager非常适合:它已经具有所有控件和约束我需要内置。

在这种情况下,所有人需要做的是创建一个AuiManager实例

(我将此作为 答案留在此处,希望其他可能采取相同天真方法的人会发现它很有用,但不会选择它作为答案,因为它确实如此直接回答原始问题。)

在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()

答案 1 :(得分:0)

我会尝试设置面板的MaxSize,甚至尝试使用SetSizeHints()。这两个都允许您对窗口小部件的大小设置一些约束。