我有在MS Windows上运行的wxPython应用程序,我希望它支持在其实例之间拖放(因此用户打开我的应用程序3次并将数据从一个实例拖到另一个实例)。
wxPython中的简单拖放工作就是这样:
我想要一些更复杂的拖放功能,这样用户就可以选择在之后拖动拖动的数据。
我的梦想的情景:
我梦想的场景似乎在MS Windows中可行,但是wxWidgets和wxPython的文档非常复杂和暧昧。并非所有的wx.DataObject类都可以在wxPython中使用(只有wx.PySimpleDataObject),所以我希望有人分享他使用这种方法的经验。这种行为可以在wxPython中实现,而不必直接在winAPI中编码吗?
编辑: ToniRuža给出了一个工作拖放示例的答案,但这并不完全是 my dreams 的情景。他的代码在删除时操纵数据( HandleDrop()显示弹出菜单),但是在启动拖动时准备数据(在 On_ElementDrag()中)。在我的应用程序中,应该有三种不同的拖放模式,其中一些需要耗时的数据准备。这就是为什么我想推迟数据检索到用户丢弃数据并选择(可能代价高昂)d& d模式的时刻。
对于内存保护问题 - 我想使用OLE机制进行进程间通信,就像MS Office一样。您可以复制Excel图表并将其粘贴到MS-Word中,它将表现得像一个图像(好吧,那种)。既然它有效,我相信它可以在winAPI中完成。我只是不知道我是否可以在wxPython中编写代码。
答案 0 :(得分:3)
由于您不能使用standard数据格式之一来存储对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 :(得分:0)
好吧,似乎无法以我想要的方式完成。
可能的解决方案是:
我正在选择解决方案 2。,因为它不需要在流程之间进行手工制作通信,它允许我在用户只想拖动最简单的数据时避免不必要的数据检索。 / p>
无论如何 - 托尼,谢谢你的回答!玩了一下它让我想到了d&amp; d并改变了我对问题的处理方法。