Search code examples
pythondrag-and-droppyqtqtreeview

Python object in QMimeData


I'm implementing drag and drop QTreeView based on my custom model. All works fine, my tree displays data, drag and drop is enabled and now the last step lies ahead of me - to drop and trasfer dragged data. To do this I need to implement mimeTypes, mimeData and dropMimeData methods in my model. And now my question: Is there any easy standard way how to pass an arbitrary Python object through QMimeData? I'm doing just an internal move within QTreeView which displays hierarchy of my Python classes Person. And I want to reorder them. No drag and drop outside the application, not even outside of control. I have found only single one tutorial: link text. But is it the only way? Cannot it be done without encoding the Python object into ByteArray. I need really simple solution for my only one class Person. Thank you.


Solution

  • Do not try to implement drag and drop by reparenting the underlying python object. This won't work if the drag comes from outside your process; nor will it work for a copy operation (your node objects probably cannot exist in multiple places in the tree).

    Think of a drag and drop "move" as three operations:

    1. serialize the data to some byte string
    2. deserialize into a new index (or new indexes)
    3. (optional: if "move" rather than "copy") remove the old index(es)

    mineData() and dropMimeData() are the serialize and deserialize operations that you provide. Python provides some easy ways to implement them -- check the documentation for the pickle module. If you're lucky, pickle.dumps() and pickle.loads() will work out-of-the-box for you.

    Edit: I couldn't figure out how to paste code in comments, so here's the solution my comment refers to. This is safe, in the sense that it will fail by throwing a KeyError instead of causing crashes if you happen to break your rules.

    # drag: store off the data in a safe place, and serialize a cooky
    # that the drop target can use to retrieve the data.
    self.__tmp_storage_dct = { self.__tmp_storage_cooky: stuff }
    m.setData(self.rowlistptr_mime_type, QByteArray(pickle.dumps(self.__tmp_storage_cooky)))
    self.__tmp_storage_cooky += 1
    
    # drop:
    if mime.hasFormat(self.rowlistptr_mime_type):
      print "got tmpstorage"
      cooky = pickle.loads(mime.data(self.rowlistptr_mime_type).data())
      nodes = self.__tmp_storage_dct.pop(cooky)