5

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

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

这是基本设置(您可以在 wxPython 演示中确认以下行为,只需替换leftwinPanel1,另请参见下面的示例应用程序)。在我有的地方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_CHANGEDANDEVT_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()
4

2 回答 2

4

根据用户的需要,可以使用高级用户界面工具包工具(此处为凤凰之前版本的文档;此处为凤凰文档)来代替自定义管理组合MultiSplitterWindowSashLayoutWindow)。为您自动化了许多此类事情。在我的例子中,我试图使用来控制相关 UI 的可折叠和可调整大小的面板,所以它是一个完美的选择:它已经拥有我需要内置的所有控件和约束。AuiManagerAuiManagerMultiSplitterWindowAuiManager

在这种情况下,只需创建一个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()
于 2013-07-24T14:31:50.047 回答
0

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

于 2013-07-23T20:25:17.447 回答