QDrag(event->widget());
drag->setMimeData(data);
drag->start();
为了在场景中获取拖拽事件,你应重新实现QGraphicsScene::dragEnterEvent()和在QGraphicsItem的子类里任何与你特定场景需要的事件处理器。items也可以通过调用QGraphicsItem::setAcceptDrops()获得拖拽支持,为了处理将要进行的拖拽,你需要重新实现QGraphicsItem::dragEnterEvent(),QGraphicsItem::dragMoveEvent(),QGraphicsItem::dragLeaveEvent()和QGraphicsItem::dropEvent()。
像QWidget一样,QGraphicsItem也支持光标(QgraphicsItem::setCursor)与工具提示(QGraphicsItem::setToolTip())。当光标进入到item的区域,光标与工具提示被QGraphicsView激活(通过调用QGraphicsItem::contains()检测)。你也可以直接在视图上设置一个缺省光标(QGraphicsView::setCursor)。
Qt自带例程
Drag and Drop Robot
介绍了这两方面的内容。
在这个demo中,可以把机器人四周的颜色拖动到机器人的各个部位,比如说头,臂,身躯等,然后这个部位就会变成相应的颜色,类似于换装小游戏。
下图是经过我的一番操作后的机器人模样:
以下是我学习这个Demo的一些知识总结,仅供交流学习,如有错误,欢迎指正,一起进步:
圆形颜色图元ColorItem
随机颜色值:
QColor
(
QRandomGenerator
::
global
()->
bounded
(
256
),
QRandomGenerator
::
global
()->
bounded
(
256
),
QRandomGenerator
::
global
()->
bounded
(
256
));
Tooltips:
setToolTip
(
QString
(
"QColor(%1,
%2,
%3)\n%4"
)
.
arg
(
color
.
red
()).
arg
(
color
.
green
()).
arg
(
color
.
blue
())
.
arg
(
"Click
and
drag
this
color
onto
the
robot!"
));
鼠标移入图元手势 (展开的小手):
setCursor
(
Qt
::
OpenHandCursor
);
绘制(两个组合圆):
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::darkGray);
painter->drawEllipse(-12,-12, 30, 30);
painter->setPen(QPen(Qt::black, 1));
painter->setBrush(QBrush(color));
painter->drawEllipse(-15,-15, 30, 30);
鼠标左键按下:
setCursor
(
Qt
::
ClosedHandCursor
);
鼠标左键释放:
setCursor
(
Qt
::
OpenHandCursor
);
鼠标左键移动过程(主要逻辑):
// 需要有一个最小移动距离限制(10px)
if(QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton))
.length()< QApplication::startDragDistance()) {
return;
}
// 创建拖动对象,并绑定一个MIME数据
QDrag*drag= new QDrag(event->widget());
QMimeData*mime= new QMimeData;
drag->setMimeData(mime);
PS
:QMimeData is used to describe information that can be stored in the
clipboard
, and transferred via the
drag and drop
mechanism.
QMimeData objects are usually created using
new
and supplied to
QDrag
or
QClipboard
objects.
对于从刚初始化后两次以上的拖动,可能会出现人脸的图像,其余情况则是对原始圆形图元的拖动。
设置MIME图像数据:
QMimeData::setImageData
设置MIME纯文本数据:
QMimeData::setText
设置MIME颜色数据:
QMimeData::setColorData
设置拖动热点:
QDrag::setHotSpot
设置拖动过程中的图像:
QDrag::setPixmap
执行拖动:
QDrag::exec();
既然有了拖动(Drag),就得有接收拖动的地方,即释放拖动的地方(Drop)。在本Demo中,执行Drop操作的主体是中间的摇摆机器人Robot。
首先需要使能Drop:
setAcceptDrops
(
true
);
具体需要重载以下三个关于Drag-Drop的虚函数:
void
dragEnterEvent
(
QGraphicsSceneDragDropEvent*
event
)
override
;
void
dragLeaveEvent
(
QGraphicsSceneDragDropEvent*
event
)
override
;
void
dropEvent
(
QGraphicsSceneDragDropEvent*
event
)
override
;
其中
QGraphicsSceneDragDropEvent
类携带了拖动的mime数据信息,通过bool类型成员变量
dragOver
标识拖动是否移动到机器人身体上,移入则响应
dragEnterEvent
(颜色加亮显示),移出则响应
dragLeaveEvent
,并置位
dragOver
。
释放操作则响应
dropEvent
,
将传递过来的颜色值赋给当前QPainter画刷颜色,调用update来调用paint函数重新绘制。
如果头像移入头部则绘制头像图片。
所有机器人的各部件(头、胳膊、躯干)通过Robot类整体组织起来,并加上了动画。
Rebort不进行任何paint操作
:
setFlag
(
ItemHasNoContents
);
PS:The item does not paint anything (i.e., calling
paint()
on the item has no effect). You should set this flag on items that do not need to be painted to ensure that Graphics View avoids unnecessary painting preparations.
Robot各部位Item的排序
:
其中,躯干是Root Item(所有其他Item是children或躯干的后代),因此首先绘制(1)。 接下来,绘制头部(2),因为它是躯干children列表中的第一个项目。 然后绘制左上臂(3), 由于下臂是上臂的孩子,因此下臂被拉动(4),接着是上臂的下一个兄弟,即右上臂(5),依此类推。
头部动画
(旋转和缩放属性):
QPropertyAnimation*
headAnimation=
new
QPropertyAnimation
(
headItem
,
"rotation"
);
QPropertyAnimation*
headScaleAnimation=
new
QPropertyAnimation
(
headItem
,
"scale"
);
其余部位的动画类似…
所有的
QPropertyAnimation
通过
QParallelAnimationGroup
组合在一起并行运行。
QParallelAnimationGroup*
animation=
new
QParallelAnimationGroup
(
this
);
animation
->addAnimation(headAnimation);
animation
->addAnimation(headScaleAnimation);
最后,让我们继续摇摆: