简体   繁体   中英

wxPython: Handling drag-and-drop in a parent object - problem with event propagation

I have a wxPython program where I want to be able to drag groups of controls around to reorder them. Each group of controls is on a panel, and I want the panel object to handle the drag-and-drop.

Currently it works if you click and drag on the panel itself, but it doesn't work if you click on any control inside the panel. This is because the wx.EVT_LEFT_DOWN event that I am using to trigger the drag is not a command event, so is not propagated up to the parent panel.

The only way I can think of to get round this is to bind that event to the panel's handler for every control on the panel.

This does not seem very elegant to me - either I have to explicitly do it when I create each child event, which breaks encapsulation, or the panel recurses through the child controls and does the binding - this seems dangerous, since the individual controls may already be using that event for other purposes. Ideally I would like the controls on the panel to not need to know anything about the DnD.

Does anyone know of any alternative solutions? Are there any command events that I could use to initiate dragging? Or anything else I haven't thought of?

I realize this is rather late, but in case it's still helpful to someone:

I've done this in the code in my (related) question :

import wx

app = wx.App(False)
d = {}

def wMouseDown(e):
    print "!!!", e.GetEventObject()

def MouseDown(e):   
    o           = e.GetEventObject()
    sx,sy       = panel.ScreenToClient(o.GetPositionTuple())
    dx,dy       = panel.ScreenToClient(wx.GetMousePosition())
    o._x,o._y   = (sx-dx, sy-dy)
    d['d'] = o

def MouseMove(e):
    try:
        if 'd' in d:
            o = d['d']
            x, y = wx.GetMousePosition()
            o.SetPosition(wx.Point(x+o._x,y+o._y))
    except: pass

def MouseUp(e):
    try:
        if 'd' in d: del d['d']
    except: pass

frame = wx.Frame(None, -1, 'simple.py')
panel = wx.Panel(frame)
box = wx.BoxSizer(wx.VERTICAL)
button1 = wx.Button(panel, -1, "foo")
box.Add(button1, 0, wx.ALL, 10)
button2 = wx.Button(panel, -1, "bar")
box.Add(button2, 0, wx.ALL, 10)

button1.Bind(wx.EVT_LEFT_DOWN, MouseDown)
button2.Bind(wx.EVT_LEFT_DOWN, MouseDown)

button1.Bind(wx.EVT_MOTION, MouseMove)
button2.Bind(wx.EVT_MOTION, MouseMove)

button1.Bind(wx.EVT_LEFT_UP, MouseUp)
button2.Bind(wx.EVT_LEFT_UP, MouseUp)

panel.Bind(wx.EVT_MOTION, MouseMove)
panel.Bind(wx.EVT_LEFT_UP, MouseUp)

panel.SetSizer(box)
panel.Layout()
frame.Show()

app.MainLoop()

IMO the best way is, Panel should bind to control's wx.EVT_LEFT_DOWN and drag only when special key combination eg cntrl-alt-d are pressed

Panel can do it recursively or have a function in Panel, addControl and only such control will be hooked.

Your point that "individual controls may already be using that event for other purposes" is not valid because either you can use that event for dragging or not, you can't have both way.

If you want drag on control to be used as drag of whole group, then you MUST override such event, but with doing dragging only inspecial key combination or modes you can let child control have their behaviour too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM