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
multiwindowsplitterexceeds width of containing window, using each ofevt_splitter_sash_pos_changed,evt_splitter_sash_pos_changingevents, , trying fix issue by:- using
event.veto()call - using
setsashposition()method on splitter
- using
- overriding
_onmouse()method use behavior associated holding downshiftkey. works, ends giving me other results don't like. - setting minimum pane sizes via
setminimumpanesizemethod - setting maximum size on
multisplitterwindowviasetmaxsize() - setting maximum size on
rootpanel/boxsizerusing bothsetmaxsize(),setsizehints()onrootpanel.- i've done event handler
wx.evt_sizeon containerrootpanelalways 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