简体   繁体   English

wxPython:处理父对象中的拖放-事件传播问题

[英]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. 我有一个wxPython程序,希望在其中拖动控件组以对其重新排序。 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. 这是因为我用来触发拖动的wx.EVT_LEFT_DOWN事件不是命令事件,因此不会传播到父面板。

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. 理想情况下,我希望面板上的控件不需要了解有关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 IMO最好的方法是,面板应绑定到控件的wx.EVT_LEFT_DOWN并仅在按下特殊的组合键(例如cntrl-alt-d)时拖动

Panel can do it recursively or have a function in Panel, addControl and only such control will be hooked. Panel可以递归执行此操作,也可以在Panel中使用函数addControl,只有这样的控件才会被挂接。

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. 如果希望将控件上的拖动用作整个组的拖动,则必须覆盖此类事件,但是通过仅拖动特殊键组合或模式,您也可以让子控件具有其行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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