约束wxPython MultiSplitterWindow窗格 [英] Constrain wxPython MultiSplitterWindow panes
问题描述
编辑:我将这个问题保持原样,因为它仍然是一个好问题,答案可能对其他人有用.但是,我会注意到,通过对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_CHANGED
和EVT_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 theEVT_SPLITTER_SASH_POS_CHANGED
ANDEVT_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 theRootPanel
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
(orSashLayoutWindow
combinations, etc.) is the Advanced User Interface kit'sAuiManager
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 theMultiSplitterWindow
as a way of controlling collapsible and resizable panels for the UI in question, so theAuiManager
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 theAuiManager
.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屋!
- Using an
- 使用