QTGraphics-View拖拽以及⿏标指针操作
因为QGraphicsView继承⾃QWidget,它也提供了像QWidget那样的拖拽功能。
另外,为了⽅便,Graphics View框架也为场景以及每个item提供拖拽⽀持。当视图接收到拖拽事件,它可转化为QGraphicsSceneDragDropEvent,再发送到场景。场景接管这个事件,把它发送到光标下接受拖拽的第⼀个item。从⼀个item开始拖拽时,创建⼀个QDrag对象,传递开始拖拽的那个widget的指针。Items可以同时被多个视图观察,但只有⼀个视图可以开始拖拽。
拖拽在多数情况下是从按下⿏标或是移动⿏标开始的,因此,在 mousePressEvent()或mouseMoveEvent()中,你可以从事件中得到那个原始的widget指针,例如:
C++ Code
1 2 3 4 5 6 7 8void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
QMimeData *data = new QMimeData;
data->setColor(Qt::green);
QDrag *drag = new 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⾃带例程介绍了这两⽅⾯的内容。
在这个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").d()).()).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));
html animation属性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);
最后,让我们继续摇摆: