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.
Curr开发者_如何学JAVAently 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 e.g. 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.
精彩评论