wxPython: Trying to make a docking window, binding parent EVT_ACTIVATE prevents parent resizing

StackOverflow https://stackoverflow.com/questions/15487759

Pregunta

I'm trying to make a simple docking frame that will dock to a parent window and follow it around. So far I have the following:

class DockingFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, style=wx.CAPTION)

        parent.Bind(wx.EVT_MOVE, self.OnParentMove)
        parent.Bind(wx.EVT_ACTIVATE, self.OnParentActivate)
        parent.Bind(wx.EVT_SHOW, self.OnParentShow)

    def OnParentMove(self, moveEvent):
        print "Docked frame parent moved"
        pr = positioning.position(
            self.Rect,
            my='right_top', at='left_top', of=self.Parent.Rect)
        self.Move(pr.top_left)
        moveEvent.Skip()

    def OnParentActivate(self, event):
        print "Docked frame parent activated"
        self.Raise()
        event.Skip()

    def OnParentShow(self, event):
        print "Docked frame parent showed"
        self.Show(event.GetShow())
        event.Skip()

class MainFrame(wx.Frame):
    def __init__(self, title):
        wx.Frame.__init__(self, None, title=title)

        self.info_frame = DockingFrame(self)

        self.Show(True)

This works in that if I move the parent window, the docked window moves with it, and if I click on the parent window, the docked window raises itself. However, it severely interferes with the parent window's functionality. I can't close or re-size the parent window anymore, and I get tons of "Docked frame parent activated" messages whenever I click the parent. It seems I don't understand some fundamental wxPython concept, here. What is going on and how do I fix it?

I've seen that aui seems to support docking, but documentation has been sparse so I haven't attempted it. If someone could supply a minimal working code sample as to how to make a Frame dock to another Frame with aui, I could also take that approach.

Note that I'm also using pygame and twisted in this app, which may or may not be interfering here...

¿Fue útil?

Solución

And, of course, the simple approach is to simply use the wx.FRAME_FLOAT_ON_PARENT style...

class DockingFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title="Last Hand",
                          style=wx.CAPTION  | wx.FRAME_FLOAT_ON_PARENT)

        parent.Bind(wx.EVT_MOVE, self.OnParentMove)
        parent.Bind(wx.EVT_SHOW, self.OnParentShow)

    def SnapToParent(self):
        print "*Snapping to parent"
        pr = positioning.position(
            self.Rect,
            my='right_top', at='left_top', of=self.Parent.Rect)
        self.Move(pr.top_left)

    def OnParentMove(self, moveEvent):
        moveEvent.Skip()
        self.SnapToParent()

    def OnParentShow(self, event):
        event.Skip()
        print "Parent %s" % ("Hide", "Show")[event.GetShow()]
        self.Show(event.GetShow())

Otros consejos

The trick was that EVT_ACTIVATE fires both for activating and for de-activating. The following code worked. If the parent gets activated, then the dock raises itself & immediately raises the parent after.

class DockingFrame(wx.Frame):
    def __init__(self, parent):
        self.handleParentActiveState = 'noTriggers'

        wx.Frame.__init__(self, parent, title="Last Hand", style=wx.CAPTION)

        parent.Bind(wx.EVT_MOVE, self.OnParentMove)
        parent.Bind(wx.EVT_ACTIVATE, self.OnParentActivate)
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
        parent.Bind(wx.EVT_SHOW, self.OnParentShow)        

    def OnActivate(self, event):
        event.Skip()
        if not event.GetActive():
            return

        if self.handleParentActiveState == 'activateParentNext':
            self.handleParentActiveState = 'resetTriggers'
            self.Parent.Raise()

    def OnParentActivate(self, event):
        event.Skip()
        if not event.GetActive():
            return

        if self.handleParentActiveState == 'noTriggers':
            self.handleParentActiveState = 'activateParentNext'
            self.Raise()
        elif self.handleParentActiveState == 'resetTriggers':
            self.handleParentActiveState = 'noTriggers'

    def OnParentMove(self, moveEvent):
        pr = positioning.position(
            self.Rect,
            my='right_top', at='left_top', of=self.Parent.Rect)
        self.Move(pr.top_left)
        moveEvent.Skip()

    def OnParentShow(self, event):
        event.Skip()
        self.Show(event.GetShow())
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top