python - Constrain wxPython MultiSplitterWindow panes -
edit: i'm leaving question open is, it's still question , answer may useful others. however, i'll note found actual solution my issue using different approach auimanager
; see answer below.
i'm working on multisplitterwindow
setup (after spending deal of time struggling against sashlayoutwindow
layout quirks). unfortunately, when create multisplitterwindow
, see unexpected behavior when dragging sashes around: sashes can dragged outside containing window in direction of layout. least, behavior i'd avoid.
here basic setup (you can confirm behavior below in wxpython demo, substituting leftwin
panel1
, etc., see below example app). have rootpanel/boxsizer
, there panel (or frame
, or whatever kind of container element like) boxsizer
multisplitterwindow
added – again, in demo.
+--------------------------------+ | rootpanel/boxsizer | |+------------------------------+| || multisplitterwindow || ||+--------++--------++--------+|| ||| panel1 || panel2 || panel3 ||| ||| || || ||| ||+--------++--------++--------+|| |+------------------------------+| +--------------------------------+
when drag, can end this, ~
, !
indicate panel "exists" there isn't being displayed:
+--------------------------------+ | rootpanel/boxsizer | |+-------------------------------|~~~~~~~~~~~~~+ || multisplitterwindow | ! ||+-----------------++-----------|~~++~~~~~~~~+! ||| panel1 || panel2 | !! panel3 !! ||| || | !! !! ||+-----------------++-----------|~~++~~~~~~~~+! |+-------------------------------|~~~~~~~~~~~~~+ +--------------------------------+
if @ point, drag rootpanel
wider overall set of panels, see panels again. likewise, if drag width down on panel1
, can access sash panel3
again (assuming panel2
isn't wide, of course). moreover, precisely situation reported inspection tool: rootpanel
retains size, multisplitterwindow
grows beyond size of rootpanel/boxsizer
.
further examination inspection tool reveals virtual , client width values both 0, actual size value negative (by corresponding number of pixels dragged out of window) whenever it's out of range. again, nutty behavior; can't imagine why 1 ever want window behave way.
now, if 1 holds down shift
_onmouse
method in multisplitterwindow
adjusts neighbors, doesn't happen. thus, 1 of approaches override method. works, i'd prefer override methods way if absolutely necessary. there another, better way solve problem? doesn't seem expected or desirable behavior in general, imagine there standard way of fixing it.
other things i've tried:
- checking whether sum of values in
multiwindowsplitter
exceeds width of containing window, using each ofevt_splitter_sash_pos_changed
,evt_splitter_sash_pos_changing
events, , trying fix issue by:- using
event.veto()
call - using
setsashposition()
method on splitter
- using
- overriding
_onmouse()
method use behavior associated holding downshift
key. works, ends giving me other results don't like. - setting minimum pane sizes via
setminimumpanesize
method - setting maximum size on
multisplitterwindow
viasetmaxsize()
- setting maximum size on
rootpanel/boxsizer
using bothsetmaxsize()
,setsizehints()
onrootpanel
.- i've done event handler
wx.evt_size
on containerrootpanel
always has appropriate maximum size parent frame element - i've attempted same event handling approach
multisplitterwindow
, no effect.
- i've done event handler
version info
i have confirmed appears in windows 32-bit , os x 64-bit, latest snapshot build of wxpython, against both python 2.7 , 3.3.
working example (with inspection tool included)
the following duplicates (and simplifies) demo source. it's working demonstration of problem.
import wx, wx.adv import wx.lib.mixins.inspection wit 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()
depending on 1 needs for, 1 possible option use instead of custom-managed multisplitterwindow
(or sashlayoutwindow
combinations, etc.) advanced user interface kit's auimanager
tool (documentation pre-phoenix version here; phoenix docs here). auimanager
automates lot of these kinds of things you. in case, attempting use multisplitterwindow
way of controlling collapsible , resizable panels ui in question, auimanager
perfect fit: has controls , constraints need built in.
in case, 1 needs create auimanager
instance
(i'm leaving here an answer in hopes others may taking same naive approach taking find useful, not selecting answer because not directly answer original question.)
sample use of aui under phoenix
this code sample trying multisplitterwindow
, managed automatically auimanager
.
import wx, wx.adv import wx.lib.mixins.inspection wit 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 aui manager , tell manage 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()
Comments
Post a Comment