La forma OLE de arrastrar y soltar en wxPython
windows drag-and-drop (2)
Como no puede usar uno de los formatos de datos estándar para almacenar referencias a objetos Python, le recomendaría que use un formato de datos de texto para almacenar los parámetros que necesita para sus llamadas a métodos en lugar de crear un nuevo formato de datos. Y de todos modos, no sería bueno pasar una referencia a un objeto de una aplicación a otra ya que el objeto en cuestión no sería accesible (¿recuerdas la protección de memoria?).
Aquí hay un ejemplo simple para sus requisitos:
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()
Métodos como On_SimpleCopy y On_MessWithSe ejecutan después de la caída, por lo que cualquier operación prolongada que desee hacer puede realizarse en función del tipo de texto o algún otro tipo de datos estándar que transfirió con el arrastre (self._text en mi caso) y mirar ... no OLE :)
Tengo la aplicación wxPython que se ejecuta en MS Windows y me gustaría que sea compatible con arrastrar y soltar entre sus instancias (por lo que el usuario abre mi aplicación 3 veces y arrastra los datos de una instancia a otra).
El simple arrastrar y soltar en wxPython funciona de esa manera:
- El usuario inicia el arrastre : la ventana de origen contiene los datos necesarios en wx.DataObject (), crea un nuevo wx.DropSource, establece sus datos y llama a dropSource.DoDragDrop ()
- El usuario descarta los datos en la ventana de destino : el objetivo de descarte llama a la función de biblioteca GetData () que transfiere datos reales a su instancia wx.DataObject y finalmente - dataObject.GetData () descomprime los datos reales.
Me gustaría tener un sistema de arrastrar y soltar más sofisticado que permita al usuario elegir qué datos se arrastran después de caer.
Escenario de mis sueños :
- El usuario inicia el arrastre : solo se empaqueta un puntero a la ventana de origen (alguna función u objeto).
- El usuario suelta datos en la ventana de destino : se muestra un bonito cuadro de diálogo que le pregunta al usuario qué modo de arrastrar y soltar elige (como - arrastrando solo el título de la canción, título de la canción y nombre del artista o álbum completo del artista arrastrado).
- Los usuarios eligen el modo arrastrar y soltar : soltar el destino llama a alguna función en el objeto de datos arrastrado, que luego recupera los datos del origen de arrastre y los transfiere al destino de colocación.
El escenario de mis sueños parece factible en MS Windows, pero los documentos para wxWidgets y wxPython son bastante complejos y ambiguos. No todas las clases de wx.DataObject están disponibles en wxPython (solo wx.PySimpleDataObject), por lo que me gustaría que alguien compartiera su experiencia con dicho enfoque. ¿Se puede implementar dicho comportamiento en wxPython sin tener que codificarlo directamente en winAPI?
EDITAR: Toni Ruža dio una respuesta con el ejemplo de arrastrar y soltar, pero ese no es exactamente el escenario de mis sueños . Su código manipula los datos cuando se descartan ( HandleDrop () muestra el menú emergente), pero los datos se preparan cuando se inicia el arrastre (en On_ElementDrag () ). En mi aplicación, debe haber tres modos distintos de arrastrar y soltar, y algunos de ellos requieren una preparación de datos que consume mucho tiempo. Es por eso que quiero posponer la recuperación de datos hasta el momento en que el usuario suelta datos y elige el modo de d & d (potencialmente costoso).
Y para el problema de la protección de la memoria, deseo usar mecanismos OLE para la comunicación entre procesos, como lo hace MS Office. Puede copiar el diagrama de Excel y pegarlo en MS-Word, donde se comportará como una imagen (bueno, más o menos). Como funciona, creo que se puede hacer en winAPI. Simplemente no sé si puedo codificarlo en wxPython.
Ok, parece que no se puede hacer de la manera que yo quería.
Las posibles soluciones son:
- Pase algunos parámetros en d & d y realice alguna comunicación entre procesos usted mismo, después de que el usuario suelte datos en la ventana de procesos de destino.
- Use DataObjectComposite para admitir múltiples formatos de arrastrar y soltar y modificadores de teclado para elegir el formato actual. Guión:
- El usuario inicia el arrastre. Se comprueba el estado de las teclas CTRL, ALT y SHIFT y, dependiendo de él, se selecciona el formato d & d. DataObjectComposite se crea y ha establecido los datos en el formato elegido.
- El usuario descarta datos en la ventana de destino. El destino Drop pide DataObject descartado para el formato compatible y recupera datos, sabiendo en qué formato está.
Estoy eligiendo la solución 2. , porque no requiere una comunicación artesanal entre procesos y me permite evitar la recuperación innecesaria de datos cuando el usuario quiere arrastrar solo los datos más simples.
De todos modos, Toni, ¡gracias por tu respuesta! Jugué un poco con eso y me hizo pensar en la ciencia y la tecnología y en cambiar mi enfoque del problema.