约束wxPython MultiSplitterWindow窗格 [英] Constrain wxPython MultiSplitterWindow panes

查看:173
本文介绍了约束wxPython MultiSplitterWindow窗格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm leaving the question open as is, as it's still a good question and the answer may be useful to others. However, I'll note that I found an actual solution to my issue by using a completely different approach with AuiManager; see the answer below.

我正在进行MultiSplitterWindow设置(花了很多时间之后 与SashLayoutWindow布局怪癖作斗争).不幸的是,当我 创建MultiSplitterWindow时,拖动时看到一些意外行为 窗框:窗框可以拖动到包含窗框的外部 布局方向.至少可以说,这是我要避免的行为.

I'm working on a MultiSplitterWindow setup (after spending a good deal of time struggling against SashLayoutWindow layout quirks). Unfortunately, when I create a MultiSplitterWindow, I see some unexpected behavior when dragging the sashes around: the sashes can be dragged outside the containing window in the direction of the layout. To say the least, this is behavior I'd like to avoid.

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

Here is the basic setup (you can confirm the behavior below in the wxPython demo, just substituting leftwin for Panel1, etc., also see below for an example app). Where I have RootPanel/BoxSizer, there is a panel (or Frame, or whatever kind of container element you like) with a BoxSizer to which the MultiSplitterWindow is added – again, as in demo.

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

拖动时,您可以得到如下所示的内容,其中~! 表示该面板存在"但没有显示:

When you drag, you can end up with something like this, where ~ and ! indicate that the panel "exists" there but isn't being displayed:

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

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

If at this point, you drag the RootPanel to be wider than the overall set of panels, you will see all the panels again. Likewise, if you drag the width back down on Panel1, you can get access to the sash for Panel3 again (assuming the Panel2 isn't already too wide, of course). Moreover, this is precisely the situation reported by the Inspection Tool: the RootPanel retains its size, but the MultiSplitterWindow grows beyond the size of the RootPanel/BoxSizer.

使用检查工具进行的进一步检查显示,虚拟宽度和客户端宽度值均为0,但实际大小值为(按从窗口中拖出的相应像素数)每当它超出范围时.同样,这是坚果行为.我无法想象为什么永远想要一个窗口以这种方式运行.

Further examination with the Inspection Tool reveals that the virtual and client width values are both 0, but the actual size value is negative (by the corresponding number of pixels it was dragged out of the window) whenever it's out of range. Again, this is nutty behavior; I can't imagine why one would ever want a window to behave this way.

现在,如果按住Shift键,则_OnMouse方法 MultiSplitterWindow调整邻居,这不会发生.因此,我的一个 方法就是简单地重写该方法.它有效,但是我更愿意 如果绝对必要,则以这种方式重写方法.还有另一种更好的方法 解决这个问题?看来这不是预期的或不可取的 行为,因此我想有一种解决它的标准方法.

Now, if one holds down Shift so that the _OnMouse method in MultiSplitterWindow adjusts neighbors, this doesn't happen. Thus, one of my approaches was to simply override that method. It works, but I'd prefer to override methods that way if absolutely necessary. Is there another, better way to solve this problem? It doesn't seem like this would be expected or desirable behavior in general, so I imagine there is a standard way of fixing it.

  • 检查MultiWindowSplitter中的值的总和是否超过 包含窗口的宽度,使用每个 EVT_SPLITTER_SASH_POS_CHANGEDEVT_SPLITTER_SASH_POS_CHANGING事件, 然后尝试通过以下方法解决此问题:
    • 使用event.Veto()通话
    • 在拆分器上使用SetSashPosition()方法
    • Checking whether the sum of the values in the MultiWindowSplitter exceeds the width of the containing window, using each of the EVT_SPLITTER_SASH_POS_CHANGED AND EVT_SPLITTER_SASH_POS_CHANGING events, and then trying to fix the issue by:
      • Using an event.Veto() call
      • Using the SetSashPosition() method on the splitter
      • 我甚至使用容器上wx.EVT_SIZE的事件处理程序来完成此操作,以使RootPanel 始终始终具有与父框架元素相称的最大大小
      • 我已经尝试对MultiSplitterWindow使用相同的事件处理方法,但也没有效果.
      • I've even done this with an event handler for wx.EVT_SIZE on the container so that the RootPanel always has the appropriate maximum size from the parent frame element
      • I've attempted the same event handling approach for the MultiSplitterWindow, also to no effect.

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

      I have confirmed that this appears in Windows 32-bit and OS X 64-bit, with the latest snapshot build of wxPython, against both Python 2.7 and 3.3.

      以下本质上是重复(并略微简化了)演示源.这是对该问题的有效演示.

      The following essentially duplicates (and slightly simplifies) the demo source. It's a working demonstration of the problem.

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

      推荐答案

      取决于一个人的需求,可以使用一种可能的选项代替自定义管理的MultiSplitterWindow(或SashLayoutWindow组合等).高级用户界面工具包的AuiManager工具(凤凰城版本此处的文档;凤凰城文档此处). AuiManager为您自动执行许多此类操作.就我而言,我试图使用MultiSplitterWindow作为控制相关UI的可折叠面板和可调整大小面板的一种方式,因此AuiManager非常适合:它已经内置了我需要的所有控件和约束.

      Depending on what one needs this for, one possible option to use instead of a custom-managed MultiSplitterWindow (or SashLayoutWindow combinations, etc.) is the Advanced User Interface kit's AuiManager tool (documentation for pre-Phoenix version here; Phoenix docs here). AuiManager automates a lot of these kinds of things for you. In my case, I was attempting to use the MultiSplitterWindow as a way of controlling collapsible and resizable panels for the UI in question, so the AuiManager is a perfect fit: it already has all the controls and constraints I need built in.

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

      In that case, all one needs to do is create an AuiManager instance

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

      (I'm leaving this here as an answer in hopes that others who may be taking the same naive approach I was taking will find it useful, but not selecting it as the answer because it does not directly answer the original question.)

      此代码示例与我尝试使用MultiSplitterWindow完全相同,但是由AuiManager自动管理.

      This code sample does exactly what I was trying to do with the MultiSplitterWindow, but managed automatically by the 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()
      

      这篇关于约束wxPython MultiSplitterWindow窗格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆