QTGraphics-View拖拽以及鼠标指针操做

由于QGraphicsView继承自QWidget,它也提供了像QWidget那样的拖拽功能。html

另外,为了方便,Graphics View框架也为场景以及每一个item提供拖拽支持。当视图接收到拖拽事件,它可转化为QGraphicsSceneDragDropEvent,再发送到场景。场景接管这个事件,把它发送到光标下接受拖拽的第一个item。 从一个item开始拖拽时,建立一个QDrag对象,传递开始拖拽的那个widget的指针。Items能够同时被多个视图观察,但只有一个视图能够开始拖拽。框架

拖拽在多数状况下是从按下鼠标或是移动鼠标开始的,所以,在 mousePressEvent()或mouseMoveEvent()中,你能够从事件中获得那个原始的widget指针,例如:dom

 C++ Code 
1
2
3
4
5
6
7
8
 
void  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()。ide

像QWidget同样,QGraphicsItem也支持光标(QgraphicsItem::setCursor)与工具提示(QGraphicsItem::setToolTip())。当光标进入到item的区域,光标与工具提示被QGraphicsView激活(经过调用QGraphicsItem::contains()检测)。你也能够直接在视图上设置一个缺省光标(QGraphicsView::setCursor)。函数

Qt自带例程Drag and Drop Robot介绍了这两方面的内容。工具

 

在这个demo中,能够把机器人四周的颜色拖动到机器人的各个部位,好比说头,臂,身躯等,而后这个部位就会变成相应的颜色,相似于换装小游戏。学习

下图是通过个人一番操做后的机器人模样:动画

如下是我学习这个Demo的一些知识总结,仅供交流学习,若有错误,欢迎指正,一块儿进步:this

圆形颜色图元ColorItemspa

随机颜色值: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);

最后,让咱们继续摇摆:

相关文章
相关标签/搜索