Hello friends,
I am trying to implement the equivalent of Dock windows in my application, but I got stuck right at the beginning:
I tried to make a derivative of wxSashWindow (SashSubPanel) for use as Dock panes, but unfortunately the children that I associate with it arent getting rendered to screen. I tried to add a Sizer to the wxSashWindow, but again no luck I also tried additionally deriving from wxPyPanel, but that too does no good.
I am including the source for my program along with this email. In advance, I apologize if this email bothers someone due to its size.
I would also like some information regarding how best to handle the resizes caused by pressing the SubPanel show/hide button. How can I make this class behave better with the other controls on the frame ? Is it necessary to make changes for this if SubPanels always exist within Dock windows (Dock yet to be coded) ?
from wxPython.wx import *
from wxPython.lib.buttons import wxGenBitmapTextToggleButton, wxGenToggleButton
class SubPanelButton(wxGenToggleButton):
def OnPaint(self, event):
(width, height) = self.GetClientSizeTuple()
x1 = y1 = 0
x2 = width-1
y2 = height-1
dc = wxBufferedPaintDC(self)
if self.up:
dc.SetBackground(wxBrush(self.GetBackgroundColour(), wxSOLID))
else:
dc.SetBackground(wxBrush(self.faceDnClr, wxSOLID))
dc.Clear()
self.DrawBezel(dc, x1, y1, x2, y2)
self.DrawLabel(dc, width, height)
if self.hasFocus and self.useFocusInd:
self.DrawFocusIndicator(dc, width, height)
def DrawFocusIndicator(self, dc, w, h):
self.DrawLabel(dc, w, h)
def DrawBezel(self, dc, x1, y1, x2, y2):
self.bezelWidth = 1
# draw the upper left sides
dc.SetBrush(wxBLACK_BRUSH)
if self.up:
dc.SetPen(self.highlightPen)
else:
dc.SetPen(self.shadowPen)
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y1, x1+i, y2-i)
dc.DrawLine(x1, y1+i, x2-i, y1+i)
# draw the lower right sides
if self.up:
dc.SetPen(self.shadowPen)
else:
dc.SetPen(self.highlightPen)
for i in range(self.bezelWidth):
dc.DrawLine(x1+i, y2-i, x2+1, y2-i)
dc.DrawLine(x2-i, y1+i, x2-i, y2)
dc.SetBrush(wxNullBrush)
def DrawLabel(self, dc, width, height, dw=0, dy=0):
bw = bh = 16 # arrow size
dc.SetFont(self.GetFont())
if self.IsEnabled():
dc.SetTextForeground(self.GetForegroundColour())
else:
dc.SetTextForeground(wxSystemSettings_GetSystemColour(wxSYS_COLOUR_GRAYTEXT))
label = self.GetLabel()
tw, th = dc.GetTextExtent(label) # size of text
if not self.up:
dw = dy = self.labelDelta
pos_x = bw/4
pos_y = (height-bh)/2
if self.hasFocus and self.useFocusInd:
dc.SetBrush(wxBLACK_BRUSH)
dc.SetPen(self.shadowPen) if self.up:
dc.DrawPolygon([(pos_x,pos_y),(pos_x+5, pos_y+5),(pos_x,pos_y+10)], pos_x, pos_y )
else:
dc.DrawPolygon([(pos_x-2,pos_y+2),(pos_x+8, pos_y+2),(pos_x+3,pos_y+7)], pos_x, pos_y )
else:
dc.SetBrush(wxWHITE_BRUSH)
dc.SetPen(self.highlightPen)
if self.up:
dc.DrawPolygon([(pos_x,pos_y),(pos_x+5, pos_y+5),(pos_x,pos_y+10)], pos_x, pos_y )
else:
dc.DrawPolygon([(pos_x-2,pos_y+2),(pos_x+8, pos_y+2),(pos_x+3,pos_y+7)], pos_x, pos_y )
pos_x = pos_x + 2 # extra spacing from arrow
dc.DrawText(label, pos_x + dw+bw, (height-th)/2+dy) # draw the text
class SubPanel(wxPyPanel):
def __init__(self, parent, id, text, panel, isOpen = False, *args, **kwds):
kwds["style"] = wxTAB_TRAVERSAL|wxSIMPLE_BORDER
wxPyPanel.__init__(self, parent, id, *args, **kwds)
self.panel_2 = panel
global ID_B; ID_B = wxNewId()
self.panel_2.Reparent(self)
self.button_1 = SubPanelButton(self, ID_B , text)
if isOpen:
self.button_1.SetToggle(True)
self.shown = True
else:
self.button_1.SetToggle(False)
self.shown = False
self.__set_properties()
self.__do_layout()
EVT_BUTTON(self, ID_B, self.OnButton)
def OnButton(self, event):
if self.shown == True:
self.sizer_1.Show( self.panel_2, False )
self.panel_2.Show(False)
self.shown = False
w, h = self.button_1.GetSizeTuple()
w = w+10
self.sizer_1.Layout()
else:
self.sizer_1.Show( self.panel_2, True )
self.panel_2.Show(True)
self.shown = True
w, h = self.button_1.GetSizeTuple()
sz = self.panel_2.GetAdjustedBestSize()
pw,ph = sz.width, sz.height
w = w+10
h = ph+h+10 #includes borders
self.sizer_1.Layout()
self.GetContainingSizer().SetItemMinSize(self,w,h)
self.GetContainingSizer().Layout()
self.GetParent().Layout()
def __set_properties(self):
pass
def __do_layout(self):
self.sizer_1 = wxBoxSizer(wxVERTICAL)
self.sizer_1.Add(self.button_1, 0, wxEXPAND, 0)
self.panel_2.SetAutoLayout(1)
self.panel_2.Show(False)
self.sizer_1.Add(self.panel_2, 1, wxALL|wxEXPAND, 4)
if self.shown:
self.sizer_1.Show(self.panel_2, True )
else:
self.sizer_1.Show(self.panel_2, False )
self.SetAutoLayout(1)
self.SetSizer(self.sizer_1)
self.sizer_1.Fit(self)
self.sizer_1.Layout()
self.sizer_1.SetSizeHints(self)
class SashSubPanel( wxSashWindow ):
def __init__(self, parent, id, text, panel, isOpen = False, *args, **kwds):
kwds["style"] = wxTAB_TRAVERSAL|wxSIMPLE_BORDER
## wxPyPanel.__init__(self, parent, id, *args, **kwds)
wxSashWindow.__init__(self, parent, id, style=wxSW_3DSASH|wxCLIP_CHILDREN)
self.panel_2 = panel
global ID_B; ID_B = wxNewId()
## self.mainPanel = wxPyPanel( self, -1)
## self.panel_2.Reparent(self)
self.button_1 = SubPanelButton(self, ID_B , text)
if isOpen:
self.button_1.SetToggle(True)
self.shown = True
else:
self.button_1.SetToggle(False)
self.shown = False
self.__set_properties()
self.__do_layout()
EVT_BUTTON(self, ID_B, self.OnButton)
def OnButton(self, event):
if self.shown == True:
self.sizer_1.Show( self.panel_2, False )
self.panel_2.Show(False)
self.shown = False
w, h = self.button_1.GetSizeTuple()
w = w+10
self.sizer_1.Layout()
else:
self.sizer_1.Show( self.panel_2, True )
self.panel_2.Show(True)
self.shown = True
w, h = self.button_1.GetSizeTuple()
sz = self.panel_2.GetAdjustedBestSize()
pw,ph = sz.width, sz.height
w = w+10
h = ph+h+10 #includes borders
self.sizer_1.Layout()
self.GetContainingSizer().SetItemMinSize(self,w,h)
self.GetContainingSizer().Layout()
self.GetParent().Layout()
def __set_properties(self):
wxSashWindow.SetSashVisible(self, wxSASH_BOTTOM, True)
def __do_layout(self):
self.sizer_1 = wxBoxSizer(wxVERTICAL)
self.sizer_1.Add(self.button_1, 0, wxEXPAND, 0)
self.panel_2.SetAutoLayout(1)
self.panel_2.Show(False)
self.sizer_1.Add(self.panel_2, 1, wxALL|wxEXPAND, 4)
if self.shown:
self.sizer_1.Show(self.panel_2, True )
else:
self.sizer_1.Show(self.panel_2, False )
self.SetAutoLayout(1)
self.SetSizer(self.sizer_1)
self.SetAutoLayout(True)
self.sizer_1.Fit(self)
self.sizer_1.Layout()
self.sizer_1.SetSizeHints(self)
class TheFrame(wxFrame):
def __init__(self, *args, **kwds):
kwds["style"] = wxDEFAULT_FRAME_STYLE
wxFrame.__init__(self, *args, **kwds)
p = wxPanel(self, -1)
szz = wxBoxSizer(wxVERTICAL)
b = wxButton(p, -1, "Hello")
szz.Add(b, 0, wxEXPAND, 0)
p.SetSizer(szz)
szz.Fit(p)
szz.Layout()
szz.SetSizeHints(p)
sp = SubPanel(self, -1, "Hello", p, True)
sp.Show(True)
p = wxPanel(self, -1)
szz = wxBoxSizer(wxVERTICAL)
b = wxButton(p, -1, "Hello")
szz.Add(b, 0, wxEXPAND, 0)
p.SetSizer(szz)
szz.Fit(p)
szz.Layout()
szz.SetSizeHints(p)
ssp = SashSubPanel(self, -1, "Hello", p, True)
p.Reparent(ssp)
ssp.Show(True)
sz = wxBoxSizer(wxVERTICAL)
sz.Add(sp, 1, wxEXPAND|wxALL, 4)
sz.Add(ssp, 1, wxEXPAND|wxALL, 4)
self.SetSizer(sz)
sz.Fit(self)
sz.Layout()
sz.SetSizeHints(self)
class ProjectrolApp(wxApp):
def OnInit(self):
wxInitAllImageHandlers()
mainFrame = TheFrame(None, -1, "Hello")
self.SetTopWindow(mainFrame)
mainFrame.Show(True)
return True
if __name__ == "__main__":
app = ProjectrolApp(0)
app.MainLoop()