- 在 QTreeView 发起拖拽(用 QDrag + QMimeData),把需要传递的标识/数据放到 mime 中(不要直接传裸指针)。
- 播放窗口设置 setAcceptDrops(true),重载 dragEnterEvent/dragMoveEvent/dropEvent,接收 mime 并在拖拽经过时(dragMoveEvent)做感知与临时反馈,dropEvent 做最终处理。
- 在 dragMoveEvent 可通过 event->source() 得到拖拽来源(可 qobject_cast 回 QTreeView)并根据 event->pos() 做高亮/提示/播放变化等。
示例代码(Qt5/6,简化版)
-
自定义 TreeView 发起拖拽(也可重写 startDrag):
class MyTreeView : public QTreeView {
QPoint m_dragStart;
void mousePressEvent(QMouseEvent *e) override {
if (e->button() == Qt::LeftButton) m_dragStart = e->pos();
QTreeView::mousePressEvent(e);
}
void mouseMoveEvent(QMouseEvent *e) override {
if (!(e->buttons() & Qt::LeftButton)) return;
if ((e->pos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) return;
QModelIndex idx = indexAt(m_dragStart);
if (!idx.isValid()) return;// 构造 mime 数据(用自定义格式) QMimeData *mime = new QMimeData; QByteArray ba; QDataStream ds(&ba, QIODevice::WriteOnly); ds << idx.data(Qt::UserRole).toString(); // 或其他标识 mime->setData("application/x-myitem", ba); QDrag drag(this); drag.setMimeData(mime); drag.setPixmap(QPixmap(":/icons/item.png")); drag.setHotSpot(QPoint(10,10)); drag.exec(Qt::CopyAction | Qt::MoveAction); }};
-
播放窗口接收并感知拖拽:
class PlayWidget : public QWidget {
void init() { setAcceptDrops(true); }
void dragEnterEvent(QDragEnterEvent *e) override {
if (e->mimeData()->hasFormat("application/x-myitem")) {
e->acceptProposedAction();
// 可在此做一次入场高亮
showHoverFeedback(e->pos());
} else {
e->ignore();
}
}
void dragMoveEvent(QDragMoveEvent *e) override {
if (e->mimeData()->hasFormat("application/x-myitem")) {
e->acceptProposedAction();
// 实时反馈:例如高亮区域、显示提示、预览等
updateHoverRegion(e->pos());
// 可访问 source(若需读取源控件信息)
const QObject *src = e->source();
if (const QTreeView tv = qobject_cast<const QTreeView>(src)) {
// 需要时与源交互(只读)
}
} else {
e->ignore();
}
}
void dropEvent(QDropEvent *e) override {
if (!e->mimeData()->hasFormat("application/x-myitem")) { e->ignore(); return; }
QByteArray ba = e->mimeData()->data("application/x-myitem");
QDataStream ds(&ba, QIODevice::ReadOnly);
QString id; ds >> id;
// 根据 id 做实际动作(切换视频、拖入标注、播放相关变化等)
handleDropItem(id, e->pos());
e->acceptProposedAction();
}
};
实现细节与建议
- mime 格式用自定义 MIME type(如 application/x-myitem),内容用 QDataStream 序列化标识(避免裸指针)。
- 若希望拖拽过程显示浮动预览,可用 QDrag::setPixmap 或在播放窗口 dragMoveEvent 绘制临时 overlay。
- 如需阻止 QTreeView 的默认拖拽行为,可在 model/view 设置 setDragEnabled(false) 然后用自定义逻辑,或重写 startDrag。
- 若跨进程或安全限制,不应依赖 event->source() 强转换;尽量用 mime 携带必要数据。
- 调试:注意 QApplication::startDragDistance() 与 drag/drop 的接受动作(acceptProposedAction)。