views:

374

answers:

2

I'm trying to understand how data gets passed around when using drag and drop in Qt. From what I understood from the examples I've been studying, you first define a widget as draggable by overriding methods inherited through QWidget.

In the implementation of the overridden method, the examples I've been looking at instantiate a pointer to a QMimeData object, and store information in it by calling setText(QString object) and setData(QByteArray object). They store information in the QByteArray object with the "<<" operator:

QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);

dataStream << labelText << QPoint(ev->pos() - rect().topLeft());

QMimeData *mimeData = new QMimeData;
mimeData->setData("application/x-fridgemagnet", itemData);
mimeData->setText(labelText);

On the definition of the dropEvent() method in the widget that accepts the drops, both of those variables were retrieved with the ">>" operator:

QString text;
QPoint offset;
dataStream >> text >> offset;

In the setData() method, application/x-fridgemagnet was passed as a MIME type argument. Was that defined somewhere else or its just something you can make up?

How can I store and retrieve a custom object inside the QMimeData object? I tried this:

dataStream << labelText << QPoint(ev->pos() - rect().topLeft()) << myObject;

and tried to retrieve it like this:

myClass myObject;
dataStream >> text >> offset >> myObject;

But it didn't work, says theres "no match for 'operator >>'". Any tips on what should I do?

+2  A: 

Yes, you can make up your own MIME type for use in your own application. Obviously no external applications will have a clue what it is so you won't be able to drag outside your own application.

As regards storing your own object you need to define the stream operator as Qt doesn't know anything about your object. QDataStream only defines stream operators for simple built-in types. You'll need to define something like

QDataStream& operator<<( QDataStream& ds, const myClass& myObject )
{
    // Use existing QDataStream stream operators or other methods to serialise your object
    // ...
    // ...

    return ds;
}

Similarly for de-serialising you'll need to define the appropriate operator>>.

Troubadour
+2  A: 

In the setData() method, application/x-fridgemagnet was passed as a MIME type argument. Was that defined somewhere else or its just something you can make up?

If the data is in your own proprietary format, then you can make it up. If, however, it's something standardized, like images, you'll probably want to use a known mime-type.

If you already support serialization to XML, then it would be easy to create your own mime-type, serialize to XML, and then de-serialize on the receiving end.

How can I store and retrieve a custom object inside the QMimeData object?

You'll need to create non-member operators (<< and >>) that write out MyObject's member data in a way supported by QDataStream. See the QDataStream documentation under the heading "Reading and Writing other Qt Class."

That will involve creating the following two methods:

QDataStream &operator<<(QDataStream &, const MyObject &);
QDataStream &operator>>(QDataStream &, MyObject &);

Since these are non-member operators, they will be defined outside your class:

class MyObject { /* ... */ };

QDataStream &operator<<(QDataStream &stream, const MyObject &obj) {
    /* as long as first_member and second_member are types supported
       by QDataStream, I can serialize them directly.  If they're not
       supported, I'd need an operator for them as well unless I can
       convert them to a QString or something else supported by Qt /
       QDataStream */
    stream << obj.first_member;
    stream << obj.second_member;
    /* and so on and so forth */
    return stream;
}
/* and similarly for operator>> */
Kaleb Pederson
So I'll have to create a class that inherits QDataStream?
David McDavidson
I justed did an edit which describes how to do non-member operators.
Kaleb Pederson
So I can do that with any class, it doesn't have to inherit QDataStream? Seems like i got the mechanism backwards them, its not that I have to create a class inheriting QDataStream to enable using the operator on my custom class, i gotta make my class usable with that operator in a QDataStream... is that it?
David McDavidson
You don't want to inherit QDataStream because you're not trying to change the data stream's behavior, rather, you're providing an output and input operator that the compiler can use in conjunction with your MyObject class.
Kaleb Pederson