代码之家  ›  专栏  ›  技术社区  ›  Abgan

在wxpython中执行拖放的OLE方法

  •  2
  • Abgan  · 技术社区  · 16 年前

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

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

    1. 用户启动拖动 :源窗口在wx.dataobject()中打包必要的数据,创建新的wx.dropsource,设置其数据并调用dropsource.doDragDrop()。
    2. 用户将数据放到目标窗口中 :drop target调用库函数getdata(),该函数将实际数据传输到其wx.dataobject实例,最后-dataobject.getdata()解包实际数据。

    我想要一些更复杂的拖放功能,允许用户选择要拖动的数据 之后 他掉了下来。
    情景 我的梦想 :

    1. 用户启动拖动 :只有指向源窗口的一些指针被打包(一些函数或对象)。
    2. 用户将数据放到目标窗口中 :显示“不错”对话框,询问用户选择的拖放模式(例如-仅拖动歌曲标题,或歌曲标题和拖动艺术家的艺术家姓名或整个专辑)。
    3. 用户选择拖放模式 :Drop Target对拖动的数据对象调用某个函数,然后从拖动源中检索数据并将其传输到Drop Target。

    我的梦想在微软Windows中似乎可行,但是WxWidgets和Wxpython的文档非常复杂和含糊不清。并非所有wx.dataobject类都在wxpython中可用(仅wx.pysimpledataobject),因此我希望有人与您分享他的经验。这种行为是否可以在wxpython中实现而不必直接在winapi中进行编码?

    编辑: Toni Ru_¾A给出了一个关于工作拖放示例的答案,但这并不是 我的梦想 . 他的代码在数据丢失时处理数据 把手() 显示弹出菜单),但数据是在启动拖动时准备的(在 在元素拖动()上 )在我的应用程序中,应该有三种不同的拖放模式,其中一些模式需要耗时的数据准备。这就是为什么我要将数据检索推迟到用户删除数据并选择(可能代价高昂)D&D模式的时候。

    对于内存保护问题,我希望像MS Office一样,使用OLE机制进行进程间通信。您可以复制Excel图表并将其粘贴到MS Word中,在那里它的行为将类似于图像(好吧,有点像)。既然它起作用了,我相信它可以在winapi中完成。我只是不知道我是否能用wxpython编码。

    2 回复  |  直到 16 年前
        1
  •  3
  •   Matt Razza    16 年前

    因为你不能使用 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-meshwithit这样的方法会在放置后执行,所以您可能希望执行的任何冗长操作都可以基于您通过拖动传输的文本或其他标准类型的数据(在我的例子中是self.\u文本),并查看…没有奥尔:

        2
  •  0
  •   Abgan    16 年前

    好吧,看来做不到我想要的。

    可能的解决方案是:

    1. 在用户将数据放入目标进程窗口后,在D&D中传递一些参数,并自行进行进程间通信。
    2. 使用 DataObjectComposite 要支持多种拖放格式和键盘修改器,请选择当前格式。脚本:
      1. 用户启动拖动。将选中“ctrl”、“alt”和“shift”的状态,并根据该状态选择“d&d”格式。创建了DataObjectComposite,并以所选格式设置了数据。
      2. 用户在目标窗口中删除数据。Drop Target请求Dropped DataObject获取支持的格式并检索数据, 知道 它的格式是什么?

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

    总之-托尼,谢谢你的回答!稍微玩弄一下,它让我想到了D&D,并改变了我解决问题的方法。