QTreeView drag/drop handling
-
I think that my problem comes from the fact, that I am following (the only available AFAIK) examples made in PyQt4 (and Python 2.6 I guess, looking at print syntaxe).
Here's one taken from QTreeView with drag and drop support in PyQt
, which I converted (or attemted, at least) to PyQt5 and Python 3.6:import sys from PyQt5 import QtGui, QtCore from PyQt5.QtWidgets import QMainWindow, QApplication, QTreeView, QAbstractItemView class TreeModel(QtCore.QAbstractItemModel): def __init__(self): QtCore.QAbstractItemModel.__init__(self) self.nodes = ['node0', 'node1', 'node2'] def index(self, row, column, parent): return self.createIndex(row, column, self.nodes[row]) def parent(self, index): return QtCore.QModelIndex() def rowCount(self, index): if index.internalPointer() in self.nodes: return 0 return len(self.nodes) def columnCount(self, index): return 1 def data(self, index, role): if role == 0: return index.internalPointer() else: return None def supportedDropActions(self): return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction def flags(self, index): if not index.isValid(): return QtCore.Qt.ItemIsEnabled return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \ QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled def mimeTypes(self): return ['text/xml'] def mimeData(self, indexes): mimedata = QtCore.QMimeData() mimedata.setData('text/xml', 'mimeData') return mimedata def dropMimeData(self, data, action, row, column, parent): print('dropMimeData %s %s %s %s' % (data.data('text/xml'), action, row, parent)) return True class MainForm(QMainWindow): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.treeModel = TreeModel() self.view = QTreeView() self.view.setModel(self.treeModel) self.view.setDragDropMode(QAbstractItemView.InternalMove) self.setCentralWidget(self.view) def main(): app = QApplication(sys.argv) form = MainForm() form.show() app.exec_() if __name__ == '__main__': main()
It doesn't work either, with error:
Traceback (most recent call last): File "tree_sample9.py", line 44, in mimeData mimedata.setData('text/xml', 'mimeData') TypeError: setData(self, str, Union[QByteArray, bytes, bytearray]): argument 2 has unexpected type 'str'
I tried couple of different examples and got a result like that in all cases. I know it might be me messing something up the conversion, but I have no idea what's wrong.
Could anyone advice please, what could be wrong? And/or perhaps someone knows a good working example for Drag&Drop support in PyQt5? -
@Oak77 said in QTreeView drag/drop handling:
mimedata.setData('text/xml', 'mimeData') TypeError: setData(self, str, Union[QByteArray, bytes, bytearray]): argument 2 has unexpected type 'str'
One of (something like) the following:
mimedata.setData('text/xml', QtCore.QByteArray('mimeData')) mimedata.setData('text/xml', QtCore.QString('mimeData').toUtf8()) mimedata.setData('text/xml', 'mimeData'.encode())
-
@JonB said in QTreeView drag/drop handling:
One of (something like) the following:
mimedata.setData('text/xml', QtCore.QByteArray('mimeData')) mimedata.setData('text/xml', QtCore.QString('mimeData').toUtf8()) mimedata.setData('text/xml', 'mimeData'.encode())
Thank you very much! The very last option worked. I'm guessing I'm encoding the string into default UTF-8, but have no idea why it doesn't work without it, however now I can progress a bit and study this stuff...
Thank you again, that helped a lot! -
'This is a string' b'This is not a string'
Python3 makes a strict distinction between bytes and string.
-
@SGaist said in QTreeView drag/drop handling:
'This is a string' b'This is not a string'
Python3 makes a strict distinction between bytes and string.
Right, but...:
'mimeData is a string'.encode()
...is a string in UTF-8, correct? What I was confused about is, that string (which I'd assume is UTF-8 by default) wouldn't work until it's encoded by
encode()
method, which with no argument, turns the string into UTF-8 string. I don't get why it crashed before and it's fine after encoding, especially because apparently it would work in PyQt4 (I don't have PyQt4 installed, didn't check, but all the references are with plain string). Not a big deal though, just my curiosity why. -
@Oak77 said in QTreeView drag/drop handling:
I don't get why it crashed before and it's fine after encoding,
The error message told you that you were passing a
str
/QString
and the method expects aQByteArray
/bytes
, as per the documentation. They are not the same. I can't comment about PyQt4 --- you'd have to look up changes, and Qt4/PyQt4 has changed at 5, and also Python from 2.x to 3.x if relevant --- but it's just a parameter type mismatch here, no mystery. (BTW, yes,encode()
is UTF-8 default.) -
The encode method returns a bytes object.
-
Thank you for your explanation, both thanks to your comments and my 2 hours over docs and testing yesterday helped me. You might hate me though, through all that time I was unable to convert that QByteArray back to string :-). It makes me feel stupid, but looking into tons of confused threads, at least I'm not alone...
b = b'MyString'
...is a QByteArray, if I'm not completely lost. Then...
print(b.decode("utf-8"))
...should output (and does):
MyString
Then, when the same
MyString
string is set todata
, we get:print(" 1 ---- " + str(data.data('text/xml')))
outputs a string:
1 ---- b'MyString'
And I would expect decoding it would give me a string:
print(" 2 ---- " + str(data.data('text/xml').decode("utf-8")))
...but, I get an error:
Traceback (most recent call last): File "test4.py", line 35, in dropMimeData print(" 2 ---- " + str(data.data('text/xml').decode("utf-8")))
OK, there's a brute, ugly way, but I don't anyone expect to embrace it:
print(str(data.data('text/xml'))[2:-1])
Output is correct:
MyString
I did google related threads, but none related to mimeData and it works with byte arrays as shown above. Maybe I'm getting old for this stuff :-)
-
@Oak77 said in QTreeView drag/drop handling:
b = b'MyString'
...is a QByteArray, if I'm not completely lost.
Do not use single letter variable. It's a easy way to break all kinds of stuff like the interaction in the debugger.
That said, sorry, you are a bit lost. It's a Python bytes. The method you are calling accepts it as well as QByteArray that you would have to explicitly build. You cannot convert a bytes to a string by calling str() on it, you have to use the encode method. If you call str(your_bytes) you will get "b'MyString'".