如何混合mouseEnterEvent和mouseMove?

时间:2018-02-25 14:39:16

标签: c++ qt

在我的应用程序中,我尝试用线连接节点。我使用QGraphicsView和QGraphicsScene以及我自己的QGraphicsItems。现在,如果我点击一个项目,我想绘制一条线到另一个节点。为了给出视觉反馈,如果鼠标悬停在目标上,则目标应该改变颜色。到目前为止基础工作,但我的问题是,如果我用鼠标拖动一行(通过mouseMoveEvent),我不再得到任何hoverEvents。我用这段代码复制了行为:

标题文件:

#pragma once

#include <QtWidgets/Qwidget>
#include <QGraphicsItem>
#include <QGraphicsScene>

class HaggiLearnsQt : public QWidget
{
    Q_OBJECT
public:
    HaggiLearnsQt(QWidget *parent = Q_NULLPTR);
};

class MyScene : public QGraphicsScene
{
public:
    MyScene(QObject* parent = 0);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent);
};

class MyItem : public QGraphicsItem
{
public:
    MyItem(QGraphicsItem* parent = Q_NULLPTR);
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
    bool mouseOverItem;
};

实现:

#include "HaggiLearnsQt.h"

#include <QMessageBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QGraphicsView>

MyScene::MyScene(QObject* parent)
{}

void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    QGraphicsScene::mouseMoveEvent(mouseEvent);
}

MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
    setAcceptHoverEvents(true);
}

QRectF MyItem::boundingRect() const
{
    return QRectF(-50, -50, 50, 50);
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QBrush b = QBrush(Qt::black);
    if(mouseOverItem)
        b = QBrush(Qt::yellow);
    painter->setBrush(b);
    painter->drawRect(boundingRect());
}

void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    mouseOverItem = true;
    QGraphicsItem::hoverEnterEvent(event);
}

void MyItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    mouseOverItem = false;
    QGraphicsItem::hoverLeaveEvent(event);
}

HaggiLearnsQt::HaggiLearnsQt(QWidget *parent)
    : QWidget(parent)
{
    QHBoxLayout* layout = new QHBoxLayout(this);
    MyScene* graphicsScene = new MyScene();
    QGraphicsView* graphicsView = new QGraphicsView();
    graphicsView->setRenderHint(QPainter::RenderHint::Antialiasing, true);
    graphicsView->setScene(graphicsScene);
    layout->addWidget(graphicsView);
    graphicsView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    graphicsView->setMinimumHeight(200);
    graphicsView->setMinimumWidth(200);
    graphicsView->setStyleSheet("background-color : gray");
    MyItem* myitem = new MyItem();
    myitem->setPos(50, 50);
    graphicsScene->addItem(myitem);
}

默认的main.cpp:

#include "HaggiLearnsQt.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    HaggiLearnsQt w;
    w.show();
    return a.exec();
}

如果您运行代码,窗口中间会出现一个框。如果将鼠标悬停在框上,则会改变颜色。现在尝试在框外滑动并按下按钮进入框中。该框不会收到悬停,也不会改变颜色。

所以我的问题是:当我用按下的按钮移动鼠标时,我可以以某种方式更改项目吗?

1 个答案:

答案 0 :(得分:1)

您可以通过mouseEvent->scenePos()将hovered项目传递给场景鼠标移动事件处理程序中的QGraphicsScene::itemAt方法。

MyItem中有指向MyScene实例的指针:

class MyScene : public QGraphicsScene
{
  MyItem * hovered;
  //...

在MyScene构造函数中将其初始化为零:

MyScene::MyScene(QObject* parent)
{
  hovered = 0;
}

然后用它来跟踪当前突出显示的项目(如果有的话):

void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
  if(mouseEvent->buttons())
  {
    QGraphicsItem * item = itemAt(mouseEvent->scenePos(), QTransform());
    MyItem * my = dynamic_cast<MyItem*>(item);
    if(my != 0)
    {
      qDebug() << mouseEvent->scenePos();
      if(!my->mouseOverItem)
      {
        my->mouseOverItem = true;
        my->update();
        hovered = my;
      }
    }
    else
    {
      if(hovered != 0)
      {
        hovered->mouseOverItem = false;
        hovered->update();
        hovered = 0;
      }
    }
  }
  QGraphicsScene::mouseMoveEvent(mouseEvent);
}

如果没有按住鼠标按钮,则开头的行if(mouseEvent->buttons())会阻止执行检查。

不要忘记在MyItem构造函数中将mouseOverItem初始化为false:

MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
  setAcceptHoverEvents(true);
  mouseOverItem = false;
}