在 Qt 拖放中使用 QMimeData 传递数据

Posted

技术标签:

【中文标题】在 Qt 拖放中使用 QMimeData 传递数据【英文标题】:Passing data around with QMimeData in Qt drag and drop 【发布时间】:2011-01-19 19:43:26 【问题描述】:

我试图了解在 Qt 中使用拖放时数据是如何传递的。从我一直在研究的示例中了解到,您首先通过覆盖通过QWidget 继承的方法将小部件定义为可拖动的。

在重写方法的实现中,我一直在查看的示例实例化了一个指向QMimeData 对象的指针,并通过调用setText(const QString &text)setData(const QByteArray &data) 在其中存储信息。它们使用<< 运算符将信息存储在QByteArray 对象中:

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);

在接受drop的小部件中dropEvent()方法的定义中,这两个变量都是用&gt;&gt;运算符检索的:

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

setData() 方法中,application/x-fridgemagnet 作为 MIME 类型参数传递。这是在其他地方定义的,还是只是你可以编造的?

如何在QMimeData 对象中存储和检索自定义对象?我试过这个:

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

并尝试像这样检索它:

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

但它不起作用,说“与'operator >>'不匹配”。关于我应该怎么做的任何提示?

【问题讨论】:

【参考方案1】:

在 setData() 方法中,application/x-fridgemagnet 作为 MIME 类型参数传递。这是在其他地方定义的,还是只是你可以编造的?

如果数据是您自己的专有格式,那么您可以进行编造。但是,如果它是标准化的东西,例如图像,您可能希望使用已知的 mime 类型。

如果您已经支持序列化为 XML,那么很容易创建自己的 mime-type,序列化为 XML,然后在接收端反序列化。

如何在 QMimeData 对象中存储和检索自定义对象?

您需要创建以 QDataStream 支持的方式写出MyObject 的成员数据的非成员运算符(>)。请参阅“读写其他 Qt 类”标题下的 QDataStream documentation。

这将涉及创建以下两个方法:

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

由于这些是非成员运算符,它们将在您的类之外定义:

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>> */

【讨论】:

所以我必须创建一个继承 QDataStream 的类? 我刚刚做了一个编辑,描述了如何做非会员操作员。 所以我可以用任何类做到这一点,它不必继承QDataStream?似乎我得到了向后的机制,并不是说我必须创建一个继承 QDataStream 的类才能在我的自定义类上使用运算符,我必须让我的类在 QDataStream 中与该运算符一起使用......是吗? 您不想继承 QDataStream ,因为您没有尝试更改数据流的行为,而是提供了一个输出和输入运算符,编译器可以将其与您的 MyObject 一起使用类。【参考方案2】:

是的,您可以创建自己的 MIME 类型以在您自己的应用程序中使用。显然没有外部应用程序会知道它是什么,因此您将无法将其拖到您自己的应用程序之外。

关于存储您自己的对象,您需要定义流操作符,因为 Qt 对您的对象一无所知。 QDataStream 只为简单的内置类型定义流操作符。您需要定义类似

QDataStream& operator<<( QDataStream& ds, const myClass& myObject )

    // Use existing QDataStream stream operators or other methods to serialise your object
    // ...
    // ...

    return ds;

类似地,对于反序列化,您需要定义适当的operator&gt;&gt;

【讨论】:

以上是关于在 Qt 拖放中使用 QMimeData 传递数据的主要内容,如果未能解决你的问题,请参考以下文章

第40课 拖放事件深度剖析

Qt学习之路(54): 自定义拖放数据对象

在 ember 中,如何将视图数据从拖放中传递?

Qt拖放中的热点是啥意思?

Qt拖放功能

在 Angular Material CDK 拖放中,如何防止项目随着元素移动而自动重新排列?