PDA

View Full Version : QMimeData: setting and getting the right MIME types for arbitrary widgets



neuronet
5th July 2014, 05:14
Using PySide/PyQt, I construct a draggable label that works exactly how I want:

class DraggableLabel(QtGui.QLabel):
def __init__(self, txt, parent):
QtGui.QLabel.__init__(self, txt, parent)
self.setStyleSheet("QLabel { background-color: rgb(255, 255, 0)}")
def mouseMoveEvent(self, event):
drag=QtGui.QDrag(self)
dragLabMimeData=QtCore.QMimeData()
drag.setMimeData(dragLabMimeData)
drag.exec_(QtCore.Qt.MoveAction)
Unfortunately, I do not understand what is going on with QMimeData, and fear I am going to run into big problems when I use similar code in real-world examples.

In particular, I am worried that my reimplementation of mouseMoveEvent creates an instance of QMimeData without any argument passed: QtCore.QMimeData(). Is this normal? Within more complex widgets will I be OK if I keep doing that within the relevant event handler: will the program automatically create the right type of MIME data for dragging and dropping?

The reason I fear I am missing something is because at the Qt Drag and Drop documentation, it has lines of code like:

mimeData -> setText(commentEdit->toPlainText());
which seems decidedly not like just letting the program take care of things within a reimplementation of an event handler.

Also, the QMimeData documentation (http://qt-project.org/doc/qt-4.8/qmimedata.html) discusses convenience functions to test, get, and set data, but those are for standard data types (e.g., text, urls). I have found no clear way to define such convenience functions for widgets like my draggable QLabel. Am I missing it? Is there a simple way to find out if I am dragging around a widget of type X?

Note I posted this also at Stack Overflow:
http://stackoverflow.com/questions/24582383/qmimedata-setting-and-getting-the-right-mime-types-for-arbitrary-widgets

anda_skoa
5th July 2014, 11:28
What kind of data does the label hold that you want to drag to another widget or application?

Your current code creates a drag without any content.

Cheers,
_

neuronet
5th July 2014, 13:13
Just some arbitrary text on the QLabel. Here is the full code:

# -*- coding: utf-8 -*-
from PySide import QtGui, QtCore

class LabelDrag(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.initUI()
def initUI(self):
self.lbl=DraggableLabel("Drag me", self)
self.setAcceptDrops(True)
self.setGeometry(40,50,200,200)
self.show()
def dragEnterEvent(self,event):
event.accept()
def dropEvent(self, event):
self.lbl.move(event.pos()) #moves label to position once the movement finishes (dropped)
event.accept()

class DraggableLabel(QtGui.QLabel):
def __init__(self, txt, parent):
QtGui.QLabel.__init__(self, txt, parent)
self.setStyleSheet("QLabel { background-color: rgb(255, 255, 0)}")
def mouseMoveEvent(self, event):
drag=QtGui.QDrag(self)
dragLabMimeData=QtCore.QMimeData()
print dragLabMimeData.hasText()
drag.setMimeData(dragLabMimeData)
drag.exec_(QtCore.Qt.MoveAction)

def main():
import sys
qt_app=QtGui.QApplication(sys.argv)
myMover=LabelDrag()
sys.exit(qt_app.exec_())

if __name__=="__main__":
main()

But note I have now done the same with much more complicated wigets (e.g., QGroupBox) and it seems to work (though it is not seamless: I am presently tinkering with it).

anda_skoa
5th July 2014, 14:53
You don't drag any data.

I get the impression you want to move widgets around instead.

Cheers,
_

neuronet
5th July 2014, 15:20
You don't drag any data.

I get the impression you want to move widgets around instead.


Yes, I am dragging widgets around: that is precisely my goal. Am i doing it wrong or am I generally confused? I thought there would be a custom mime type implemented dynamically, but I have no idea what's going on. :D

neuronet
5th July 2014, 20:06
Perhaps I should be using QGraphicsView?

anda_skoa
6th July 2014, 11:58
If you want widgets that can be moved using the mouse, you can implement the movement directly in the mouse event handler methods.
The Drag&Drop classes are for transferring data, often across different applications (e.g. from a file manager to a program that should open these files).

In the most usual cases widget locations and sizes are managed by layouts, which position and resize child widgets within their parent's boundaries.
But you can manage that yourself of course.

I guess it depends on what you are trying to achieve, i.e. whether QGraphicsView is a better approach or not.

Cheers,
_

neuronet
6th July 2014, 13:09
If you want widgets that can be moved using the mouse, you can implement the movement directly in the mouse event handler methods.
The Drag&Drop classes are for transferring data, often across different applications (e.g. from a file manager to a program that should open these files).

In the most usual cases widget locations and sizes are managed by layouts, which position and resize child widgets within their parent's boundaries.
But you can manage that yourself of course.

I guess it depends on what you are trying to achieve, i.e. whether QGraphicsView is a better approach or not.

Cheers,
_


My goal is to make a desktop application in which I have multiple widgets open that the user can move around with drag/drop. Basically a to do list app (yes, I know, that is trite :)). Something like the following markup:
10502

Given that goal, do you think QGraphicsView would be better? (Note someone has responded at Stack Overflow as well and I have yet to implement their suggestions). Or more accurately, do you think it would stupid to try to do it without using QGraphicsView?

anda_skoa
6th July 2014, 14:17
So the only movable objects are the Todo items? Not things like the Save button or the Notes box?

I would say it is bascially a trade-off. QGraphicsView would have item moving built-in, while Widgets would have things like the tree view built-in.

If you have comfortable knowledge about widgets and no or only little know-how about graphics view I would go with widgets.

Cheers,
_

neuronet
6th July 2014, 18:21
So the only movable objects are the Todo items? Not things like the Save button or the Notes box?

I would say it is bascially a trade-off. QGraphicsView would have item moving built-in, while Widgets would have things like the tree view built-in.

If you have comfortable knowledge about widgets and no or only little know-how about graphics view I would go with widgets.

Cheers,
_

Yes, just todo items can be moved around, not the command buttons. Based on your suggestion, I will stick with Widgets ;)

neuronet
6th July 2014, 21:21
While my simple example worked, it seems i do need to define a new MIME type for more complex examples. The following works, but I don't really understand it:

itemData = QtCore.QByteArray()
dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.WriteOnly)
dataStream << QtCore.QPoint(event.pos() - self.rect().topLeft())
mimeData = QtCore.QMimeData()
mimeData.setData('x-QLabel', itemData)
It looks more like C than Python in places :)

anda_skoa
7th July 2014, 09:09
I am confused.
I thought you wanted to move the Todo objects, not drag some data?

For a data drag this sounds about right, though the MIME type is usually in the form of "major/minor", e.g. "application/x-vnd.vendorname.vendorspecifictype"

Cheers,
_

neuronet
7th July 2014, 17:32
I am confused.
I thought you wanted to move the Todo objects, not drag some data?

For a data drag this sounds about right, though the MIME type is usually in the form of "major/minor", e.g. "application/x-vnd.vendorname.vendorspecifictype"


I want to drag widgets around, you are not confused. I was unaware of the naming conventions for newly created MIME types, it is something I should look into, am open to suggestions.

anda_skoa
7th July 2014, 18:30
If you want to move widgets around using the mouse, then you can ignore anything related to MIME type, QMimeData or QDrag.

You just move the widget, see QWidget::move()

Cheers,
_

neuronet
7th July 2014, 21:08
If you want to move widgets around using the mouse, then you can ignore anything related to MIME type, QMimeData or QDrag.

You just move the widget, see QWidget::move()

Cheers,
_

Wait really? :o I knew I could move it around programatically using move. But it is possible to enable user to move it around with the mouse too? That sounds pretty awesome!!! Is this a good example of what youa re talking about?
http://stackoverflow.com/questions/11314429/select-moving-qwidget-in-the-screen

If so, then wow I really do belong in the noob forum.

If anyone has a full worked out example of moving a widget around (without all this mime nonsense) that would be very helpful...The example I linked to is really a snippet, and in C++. Anything in pyside? If not c++ is fine.

Edit: it seems this is a point of confusion among many noobs, and luckily a pyqt example (which is basically pyside):
http://stackoverflow.com/questions/12219727/dragging-moving-a-qpushbutton-in-pyqt

This is actually really important. Noobs like me take the phrase 'drag and drop' in a colloquial sense to mean 'move something with the mouse', while in *qt, these two things are not the same at all. At this point I'm surprised the doc for drag 'n' drop doesn't have a huge yellow sign before starting, saying "If you want to just move something with your mouse, this is not what you want! Drag and drop is much more than that!"

I have seen so much confusion on the web about this, and generated it myself. Thanks for helping to point me int he right direction. I really wish there was a good book on this for Python users! Summerfield is good, but dated, and I am using that.

anda_skoa
7th July 2014, 21:41
Yes, like that.

Mouse down initializes a base line position, mouse move then calculates relative movement, moves the widget and resets the base line position for the next calculation,

Cheers,
_