Ok, I got a working example of what I think you're looking for. I probably
went a little overboard on it, but I like to take control of various
aspects of the drag and drop operations, and it's decent reference for if
you want to do so. It's pretty dirty at the moment, so if you have
questions feel free to ask. I basically extended the QTableWidget and
QTreeWidget to get the behavior I was going for, and then used those in my
main window. You can drag from the table widget to the tree widget. I
encoded my mime data using json before passing it through the bitstream.
```python
import json
from PySide import QtCore, QtGui
class SourceWidget(QtGui.QTableWidget):
def __init__(self, parent=None):
super(SourceWidget, self).__init__(parent)
self.setDragEnabled(True)
def startDrag(self, supportedActions):
items = self.selectedItems()
indexes = self.selectedIndexes()
if len(items) > 0:
data = self.mimeData(items)
if not data:
return
pixmap, rect = self.__renderToPixmap(indexes)
drag = QtGui.QDrag(self)
drag.setPixmap(pixmap)
drag.setMimeData(data)
drag.setHotSpot(self.__mouseClickPosition - rect.topLeft())
drag.exec_(supportedActions, QtCore.Qt.CopyAction)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.MouseButton.LeftButton:
self.__mouseClickPosition = event.pos()
super(SourceWidget, self).mousePressEvent(event)
def mimeTypes(self):
return ['application/x-my-custom-mimetype']
def mimeData(self, items):
if len(items) == 0:
return False
mimeData = QtCore.QMimeData()
data = QtCore.QByteArray()
stream = QtCore.QDataStream(data, QtCore.QIODevice.WriteOnly)
for item in items:
firstColData = self.item(item.row(),
0).data(QtCore.Qt.DisplayRole)
secondColData = self.item(item.row(),
1).data(QtCore.Qt.DisplayRole)
output = (firstColData, secondColData)
stream << json.dumps(output)
mimeData.setData('application/x-my-custom-mimetype', data)
return mimeData
def __renderToPixmap(self, indexes):
rect, paintPairs = self.__draggablePaintPairs(indexes)
if len(paintPairs) == 0:
return QtGui.QPixmap()
pixmap = QtGui.QPixmap(rect.width(), rect.height())
pixmap.fill(QtCore.Qt.transparent)
painter = QtGui.QPainter(pixmap)
option = self.viewOptions()
option.state |= QtGui.QStyle.State_Selected
for r, index in paintPairs:
option.rect = r.translated(-r.topLeft())
self.itemDelegate(index).paint(painter, option, index)
return (pixmap, rect)
def __draggablePaintPairs(self, indexes):
rect = QtCore.QRect()
viewportRect = self.viewport().rect()
ret = []
for index in indexes:
current = self.visualRect(index)
if current.intersects(viewportRect):
ret.append((current, index))
rect = rect | current
rect = rect & viewportRect
return (rect, ret)
class DestinationWidget(QtGui.QTreeWidget):
def __init__(self, parent=None):
super(DestinationWidget, self).__init__(parent)
self.setAcceptDrops(True)
self.setDropIndicatorShown(True)
self.setDefaultDropAction(QtCore.Qt.CopyAction)
self.setDragDropMode(QtGui.QAbstractItemView.DropOnly)
def supportedDropActions(self):
return QtCore.Qt.CopyAction
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('application/x-my-custom-mimetype'):
event.acceptProposedAction()
def dragMoveEvent(self, event):
event.accept()
def dropMimeData(self, parent, index, data, action):
if not data.hasFormat('application/x-my-custom-mimetype'):
return False
encodedData = data.data('application/x-my-custom-mimetype')
stream = QtCore.QDataStream(encodedData, QtCore.QIODevice.ReadOnly)
jsonData = stream.readString()
dropData = json.loads(jsonData)
newItem = QtGui.QTreeWidgetItem(parent)
newItem.setText(0, dropData[0])
newItem.setText(1, dropData[1])
parent.addChild(newItem)
return True
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
layout = QtGui.QHBoxLayout()
source = SourceWidget(self)
source.setRowCount(5)
source.setColumnCount(2)
for i in range(5):
source.setItem(i, 0, QtGui.QTableWidgetItem("Item
{0}".format(i+1)))
source.setItem(i, 1, QtGui.QTableWidgetItem("Item {0} Col
2".format(i+1)))
layout.addWidget(source)
dest = DestinationWidget(self)
dest.setColumnCount(2)
top = QtGui.QTreeWidgetItem(dest)
top.setText(0, "Root")
dest.addTopLevelItem(top)
layout.addWidget(dest)
self.setLayout(layout)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
```
On Wed, Apr 22, 2015 at 12:34 PM, Joe Weidenbach <[email protected]> wrote:
> For the simple solution, yes, it's a matter of decoding the mimeData. If
> you want to do something custom though, you're going to need to encode the
> mimeData yourself in the source TableWidget (for example, if you want to
> transfer the whole row). It's a good exercise regardless for when you get
> to using custom QAbstractItemModels.
>
> I should have some sample code for you relatively shortly :)
>
>
> On Wed, Apr 22, 2015 at 10:57 AM, Ben Hearn <[email protected]>
> wrote:
>
>> Ok awesome thanks for the help. I was digging at it earlier and when I
>> printed my mimedata using
>>
>> For format in mimedata.mimeFormats():
>> Print mimedata(format)
>>
>> (From my iPhone so something along those lines)
>>
>> The name of the tablewidget I dragged from was present but it was
>> surrounded by empty spaces. Is this just a matter of decoding it properly?
>>
>> On Wednesday, 22 April 2015, Joe Weidenbach <[email protected]> wrote:
>>
>>> Well, speaking from the perspective of custom QAbstractItemModel with
>>> QTreeViews or QTableViews, that's EXACTLY the path. I'm going to test with
>>> the Convenience widgets though, so I'll keep you posted. The basics are
>>> these: mime data is binary, and you can attach it to an arbitrary label of
>>> datatype. That data type can be whatever you want it to be (although there
>>> are some standard ones such as 'text/html' and whatnot. I personally make
>>> my own, eg 'application/x-hierarchy-block'. Then you just push a stream of
>>> the data you want to encode. In several of my projects, that was the
>>> output of the repr() method for the object being dragged. in others, it
>>> might be a node id, or pretty much anything you want. It just depends on
>>> the use case.
>>>
>>> I keep trying to find a use case for the convenience widgets
>>> (QTreeWidget etc), and at least in my experience, while they're great for
>>> one-time use data, most of my projects use persistance, so I've ended up
>>> going more into the custom models and hooking up views. When you go that
>>> route, though, there's a lot more boilerplate you have to set up, so keep
>>> that in mind.
>>>
>>> As I said, I'll get something coded up today to test it out.
>>>
>>> On Wed, Apr 22, 2015 at 9:08 AM, Benjam901 <[email protected]>
>>> wrote:
>>>
>>>> Hello Joe,
>>>>
>>>> That would be a massive help thank you very much.
>>>>
>>>> I have found something online that has mentioned decoding the mimedata
>>>> using QDataStream which indicates to me that the data is binary. If this is
>>>> the case I would really like to be able to set my mime data myself so that
>>>> decoding it is a little easier. That being said, my current experience in
>>>> encoding/decoding binary data is limited. Would this be a good path to
>>>> wander down?
>>>>
>>>> http://pythonically.blogspot.se/2009/11/drag-and-drop-in-pyqt.html
>>>>
>>>> Cheers,
>>>>
>>>> Ben
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Python Programming for Autodesk Maya" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to [email protected].
>>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/python_inside_maya/8095ee58-77f0-4766-bd75-768b44e903c4%40googlegroups.com
>>>> <https://groups.google.com/d/msgid/python_inside_maya/8095ee58-77f0-4766-bd75-768b44e903c4%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>> --
>>> You received this message because you are subscribed to a topic in the
>>> Google Groups "Python Programming for Autodesk Maya" group.
>>> To unsubscribe from this topic, visit
>>> https://groups.google.com/d/topic/python_inside_maya/_6fvzObx1Ds/unsubscribe
>>> .
>>> To unsubscribe from this group and all its topics, send an email to
>>> [email protected].
>>> To view this discussion on the web visit
>>> https://groups.google.com/d/msgid/python_inside_maya/CAM33%3Da5rW8Dus%2BWgOSb888GHdtrHc7B9Y11WXAkkWbnENNS8RQ%40mail.gmail.com
>>> <https://groups.google.com/d/msgid/python_inside_maya/CAM33%3Da5rW8Dus%2BWgOSb888GHdtrHc7B9Y11WXAkkWbnENNS8RQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>> .
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>
>> --
>>
>> Tel - +46 76245 92 90 (Sweden)
>> LinkedIn: http://www.linkedin.com/pub/ben-hearn/50/a64/33b
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Python Programming for Autodesk Maya" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/python_inside_maya/CAM2ybkWMi3wv6FK5cp06m5u2-Scu2FGkbY8SFKs0uWZ%2BVTE6zQ%40mail.gmail.com
>> <https://groups.google.com/d/msgid/python_inside_maya/CAM2ybkWMi3wv6FK5cp06m5u2-Scu2FGkbY8SFKs0uWZ%2BVTE6zQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
--
You received this message because you are subscribed to the Google Groups
"Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/CAM33%3Da4WHmoMJVQ%2BdB-9upgcYsq26R3mHKYrbdkAQdLg9Cfx6w%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.