最近使用到Qt的Drag Drop功能,结合自己的例子写下来给大家分享一下。实现从QTreeView拖动Node到QGraphicsView上,以及QGraphicsView上item之间的拖动。
先来说Model/View中的实现
1.Model/View要实现Drag Drop操作,首先需要为View设置DragDropMode属性。
1
2
|
enum DragDropMode {
NoDragDrop, DragOnly, DropOnly, DragDrop, InternalMove } |
以上是View支持的所有Mode Type,View默认是NoDragDrop,即默认不支持拖拽。
m_treeView->setDragDropMode(QAbstractItemView::DragOnly);
我只需要TreeView的Drag操作,所以设置成DragOnly,可以依据自己需要实现的功能来设置。
2.Drag and Drop是两个操作,独立分开的。
Drag 实现需要的步骤:第一步,在对应的Model的flags函数中,允许drag的item返回Qt::ItemIsDragEnabled。
1
2
3
4
5
6
|
Qt::ItemFlags
NetlistModel::flags( const QModelIndex
&index) const { Qt::ItemFlags
flags = QAbstractItemModel::flags(index); flags
= flags | Qt::ItemIsDragEnabled; return flags; } |
第二步,Model中需要实现mimeData函数,该函数是封装Drag数据,数据由Drop方接收处理。该步是处理传递的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
QMimeData
*NetlistModel::mimeData( const QModelIndexList
&indexes) const { if (indexes.count()
<= 0) { //If
the list of indexes is empty, or there are no supported MIME types, //0
is returned rather than a serialized empty list. return 0; } //QMap<int,
QStringList> nodeData; //QStringList
listName; //
foreach(QModelIndex index, indexes) //
{ //
TreeNode* node = nodeFromIndex(index); //
} QByteArray
itemData; QDataStream
dataStream(&itemData, QIODevice::WriteOnly); TreeNode*
node = nodeFromIndex(indexes.at(0)); NlsData::ConItem*
conItem = static_cast <NlsData::ConItem*>(node->data()); if (conItem) { dataStream
<< node->type() << conItem->name(); } QMimeData
*data = new QMimeData; data->setData( "nlsdata/items" ,
itemData); //key值需要与Drop中一致 return data; } |
QTreeView我只需要单个拖拽,所以数据处理是单个index,如果多个拖拽,可以将数据封装成List or Map,注意QDataStream只可以放Qt的基本数据类型,自定义的struct其中也只能是基本数据类型,不能放指针。
3.对于Drop操作,步骤也相似,第一步flags函数中返回Qt::ItemIsDropEnabled;第二步需要实现mimeTypes函数,这个函数要返回当前数据模型允许接收的数据类型列表,它会在Drag操作过程中被调用,如果Drag操作所包含的对象(mimeData方法返回的数据对象)没有相关类型的数据,就不允许执行Drop操作;第三步实现dropMimeData方法。这个方法主要在drop操作后解析数据并添加到当前模型的合适位置。因为我在QTreeView不允许Drop操作,所以就不贴代码了。
接下来是QGraphicsView中的实现。
1.设置QGraphicsView的DragMode。关于DragMode,This property holds the behavior for dragging the mouse over the scene while the left mouse button is pressed.
在View的构造函数中添加
1
|
setDragMode(ScrollHandDrag); |
不过该函数似乎只设置了Drag时的鼠标样式,因为我的Drag Drop都是在QGraphicsItem中实现的。
2.在QGraphicsItem的构造函数中设置setAcceptDrops(true),允许接收Drop。
1
2
3
4
5
6
|
if (!border) { setFlags(ItemIsSelectable); setAcceptsHoverEvents( true ); setAcceptDrops( true ); } |
当然,为需要的Item设置需要的。
3.实现Item的一下事件
1
2
3
4
|
void dragEnterEvent(QGraphicsSceneDragDropEvent
*event); void dragLeaveEvent(QGraphicsSceneDragDropEvent
*event); void dropEvent(QGraphicsSceneDragDropEvent
*event); //处理drop void mouseMoveEvent(QGraphicsSceneMouseEvent
*event); //添加QDrag |
dragEnterEvent中,如果有需要的数据,event->setAccepted(true),接收drag事件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
void GPkgCellItem::dragEnterEvent(QGraphicsSceneDragDropEvent
*event) { if (event->mimeData()->hasFormat( "nlsdata/items" )) { event->setAccepted( true ); m_bOnDrag
= true ; //painter函数中使用,绘制不同的样式 update(); } else { event->setAccepted( false ); } } |
dragLeaveEvent
1
2
3
4
5
6
|
void GPkgCellItem::dragLeaveEvent(QGraphicsSceneDragDropEvent
*event) { Q_UNUSED(event); m_bOnDrag
= false ; update(); } |
dropEvent中需要处理mimeData,获得drag传过来的数据。
1
2
3
4
5
6
7
8
9
10
11
12
|
void GPkgCellItem::dropEvent(QGraphicsSceneDragDropEvent
*event) { m_bOnDrag
= false ; if (event->mimeData()->hasFormat( "nlsdata/items" )) { QByteArray
itemData = event->mimeData()->data( "nlsdata/items" ); QDataStream
dataStream(&itemData, QIODevice::ReadOnly); dataStream
>> m_dragType >> m_dragName; setAcceptDrops( false ); } update(); } |
实现QGraphicsItem之间的Drag,需要在mouseMoveEvent中添加QDrag动作,该Drag也在dropEvent中接收。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
void GPkgCellItem::mouseMoveEvent(QGraphicsSceneMouseEvent
*event) { if (QLineF(event->screenPos(),
event->buttonDownScreenPos(Qt::LeftButton)) .length()
< QApplication::startDragDistance()) { //触发需满足move事件最小距离(The
default value is 4 pixels.) return ; } if (m_dragName.isEmpty()) { return ; } QMimeData
*mimeData = new QMimeData; QByteArray
exData; QDataStream
dataStream (&exData, QIODevice::WriteOnly); dataStream
<< m_dragType << m_dragName; mimeData->setData( "nlsdata/items" ,
exData); QDrag
*drag = new QDrag
(event->widget()); drag->setMimeData(mimeData); if (drag->exec(Qt::MoveAction)
== Qt::MoveAction) { //drag动作完成、Drop处理之后的动作,在dropEvent调用之后被调用,相当于回调函数,可以把数据清理之类的放在此处处理。 m_dragName
= "" ; m_dragType
= 0; setAcceptDrops( true ); //随时更新状态,是否允许drop update(); } } |
Drag-Drop的机制就是在开始拖动鼠标时启动QDrag并封装数据,然后drag到某个位置松开鼠标触发Drop,然后获取数据并处理。
添加一张程序的截图
记录,成长过程的每一步。。
原文地址:http://www.cnblogs.com/helloworldhao/p/4365688.html?utm_source=tuicool