在wxPython中拖放的OLE方式

我有在MS Windows上运行的wxPython应用程序,我希望它支持在其实例之间拖放(所以用户打开我的应用程序3次,并将数据从一个实例拖到另一个实例)。

wxPython中的简单拖放工作方式如下:

  1. 用户启动拖动 :源窗口在wx.DataObject()中打包必要的数据,创build新的wx.DropSource,设置其数据并调用dropSource.DoDragDrop()
  2. 用户将数据拖放到目标窗口上 :拖放目标调用库函数GetData(),它将实际数据传输到其wx.DataObject实例,最后 – dataObject.GetData()将实际数据解包。

我想有一些更复杂的拖放,这将允许用户select什么数据被拖动后,他下降。
我的梦想情景:

  1. 用户启动拖动 :只有一些指向源窗口的指针被打包(某些函数或对象)。
  2. 用户将数据拖放到目标窗口上 :显示尼斯对话框,询问用户select了哪种拖放模式(如拖动歌曲名称,歌曲名称和拖动的艺术家的艺术家名称或整个专辑)。
  3. 用户select拖放模式 :拖放目标在被拖动的数据对象上调用一些函数,然后从拖动源中检索数据并将其传送到放置目标。

我梦想中的情景在MS Windows中似乎是可行的,但是wxWidgets和wxPython的文档是相当复杂和令人怀疑的。 并不是所有的wx.DataObject类都在wxPython中可用(只有wx.PySimpleDataObject),所以我希望有人分享他的经验。 这样的行为可以在wxPython中实现,而不必直接在winAPI中编写它?

编辑:ToniRuža给出了一个工作拖放示例的答案,但这不完全是我的梦想的场景。 他的代码在数据丢失时处理数据( HandleDrop()显示popup式菜单),但在启动拖动时(在On_ElementDrag() )中准备数据。 在我的应用程序中,应该有三种不同的拖放模式,其中一些需要耗时的数据准备。 这就是为什么我想推迟数据检索到用户丢弃数据和select(潜在成本高昂)D&D模式的时刻。

而对于内存保护问题 – 我想使用OLE机制进行进程间通信,就像MS Office一样。 您可以复制Excel图表并将其粘贴到MS-Word,其行为就像一个图像(好,有点)。 因为它的工作原理,我相信它可以在winAPI中完成。 我只是不知道我是否可以在wxPython中编写它。

Solutions Collecting From Web of "在wxPython中拖放的OLE方式"

由于不能使用标准数据格式之一来存储对python对象的引用,我建议您使用文本数据格式来存储您的方法调用所需的参数,而不是创建新的数据格式。 无论如何,将一个对象的引用从一个应用程序传递到另一个应用程序是不好的,因为所讨论的对象将无法访问(记住内存保护?)。

以下是您的要求的一个简单示例:

import wx class TestDropTarget(wx.TextDropTarget): def OnDropText(self, x, y, text): wx.GetApp().TopWindow.HandleDrop(text) def OnDragOver(self, x, y, d): return wx.DragCopy class Test(wx.Frame): def __init__(self): wx.Frame.__init__(self, None) self.numbers = wx.ListCtrl(self, style = wx.LC_ICON | wx.LC_AUTOARRANGE) self.field = wx.TextCtrl(self) sizer = wx.FlexGridSizer(2, 2, 5, 5) sizer.AddGrowableCol(1) sizer.AddGrowableRow(0) self.SetSizer(sizer) sizer.Add(wx.StaticText(self, label="Drag from:")) sizer.Add(self.numbers, flag=wx.EXPAND) sizer.Add(wx.StaticText(self, label="Drag to:"), flag=wx.ALIGN_CENTER_VERTICAL) sizer.Add(self.field) for i in range(100): self.numbers.InsertStringItem(self.numbers.GetItemCount(), str(i)) self.numbers.Bind(wx.EVT_LIST_BEGIN_DRAG, self.On_ElementDrag) self.field.SetDropTarget(TestDropTarget()) menu_id1 = wx.NewId() menu_id2 = wx.NewId() self.menu = wx.Menu() self.menu.AppendItem(wx.MenuItem(self.menu, menu_id1, "Simple copy")) self.menu.AppendItem(wx.MenuItem(self.menu, menu_id2, "Mess with it")) self.Bind(wx.EVT_MENU, self.On_SimpleCopy, id=menu_id1) self.Bind(wx.EVT_MENU, self.On_MessWithIt, id=menu_id2) def On_ElementDrag(self, event): data = wx.TextDataObject(self.numbers.GetItemText(event.Index)) source = wx.DropSource(self.numbers) source.SetData(data) source.DoDragDrop() def HandleDrop(self, text): self._text = text self.PopupMenu(self.menu) def On_SimpleCopy(self, event): self.field.Value = self._text def On_MessWithIt(self, event): self.field.Value = "<-%s->" % "".join([int(c)*c for c in self._text]) app = wx.PySimpleApp() app.TopWindow = Test() app.TopWindow.Show() app.MainLoop() 

像On_SimpleCopy和On_MessWithIt这样的方法在下拉之后被执行,所以你可能想要做的任何冗长的操作都可以根据你拖拽的文本或者其他标准类型的数据来实现(self._text,在我的情况下) …没有OLE 🙂

好吧,似乎不能按我想要的方式完成。

可能的解决方案是

  1. 在用户将数据放入目标进程窗口之后,在d&d中传递一些参数,并自行进行一些进程间通信。
  2. 使用DataObjectComposite支持多种拖放格式和键盘修改器来选择当前格式。 场景:
    1. 用户启动拖动。 检查CTRL,ALT和SHIFT的状态,并根据它选择d&d格式。 DataObjectComposite被创建,并以选定的格式设置数据。
    2. 用户在目标窗口中删除数据。 Drop目标询问DataObject是否支持格式并检索数据, 知道它在什么格式。

我选择了解决方案2 ,因为它不需要手工制作进程之间的通信,并且允许我在用户只想拖动最简单的数据时避免不必要的数据检索。

反正 – 托尼,谢谢你的回答! 玩了一下,这让我想起了D&D,并改变了我的方法来解决这个问题。