首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >QGraphicsItem子类仅从边界矩形接收边框上的悬停事件。

QGraphicsItem子类仅从边界矩形接收边框上的悬停事件。
EN

Stack Overflow用户
提问于 2021-09-20 08:49:06
回答 2查看 251关注 0票数 0

我正在开发Qt-5.15.1。我想自定义QGraphicsItem,并在这个定制项目中添加了一个矩形和一些周围的圆圈。当鼠标在那个矩形上盘旋时,小圆圈会显示出来。所以我重新实现了hoverEnterEventhoverLeaveEvent函数来接收鼠标悬停事件,请参考minimal example

然后,在paint事件中,我可以确定是否基于_mouseEnter绘制圆圈。

问题来了,我发现只要鼠标进入那个矩形的边界,hoverEnterEvent就会被触发,但是当鼠标穿过边框时,hoverLeaveEvent也会很快被触发,靠近矩形的中心。似乎边框是鼠标悬停事件的实体,而不是填充的矩形。所以我只能在鼠标在那个矩形的边框上盘旋时才能显示圆圈。

我不知道我是不是错过了什么?在我看来,当事件发生时,shape()boundingRect()会影响上的鼠标事件?我想让shape()返回一个填充的QPainterPath矩形,但不知道如何返回。

更新:最小示例

customizeitem.cpp

代码语言:javascript
运行
复制
#include "customizeitem.h"
#include <QDebug>

CustomizeItem::CustomizeItem(QGraphicsItem *parent):
  QGraphicsItem(parent),
  _bbox(0,0,120, 120),_radius(7),
  _mouseEnter(false)
{
  setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
  setAcceptHoverEvents(true);

  _rectRect = QRect(QPoint(_radius*4, _radius*4), QPoint(_bbox.width() - _radius*4, _bbox.height() - _radius*4));

  QPointF upCenter(_bbox.width()/2, _radius);
  QPointF rCenter(_bbox.width() - _radius, _bbox.height() / 2);
  QPointF downCenter(_bbox.width()/2, _bbox.height() - _radius);
  QPoint lCenter(_radius, _bbox.height() / 2);
  _anchorRects.push_back(QRectF(upCenter, QSizeF(_radius, _radius)));
  _anchorRects.push_back(QRectF(rCenter, QSizeF(_radius, _radius)));
  _anchorRects.push_back(QRectF(downCenter, QSizeF(_radius, _radius)));
  _anchorRects.push_back(QRectF(lCenter, QSizeF(_radius, _radius)));
}

void CustomizeItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
  qInfo() << "mouse enter";
  _mouseEnter = true;

  update();
  QGraphicsItem::hoverEnterEvent(event);
}

void CustomizeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
  qInfo() << "mouse leave";
  _mouseEnter = false;

  update();
  QGraphicsItem::hoverLeaveEvent(event);
}

QRectF CustomizeItem::boundingRect() const
{
  return shape().boundingRect();
}

void CustomizeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
  painter->setRenderHint(QPainter::Antialiasing);
  drawAnchors(painter);
  painter->fillRect(_rectRect, QColor(255, 0, 0));
}

QPainterPath CustomizeItem::shape() const
{
  QPainterPath path;
  path.moveTo(_bbox.topLeft());
  path.addRect(_bbox);
  QPainterPathStroker stroker;
  stroker.setWidth(10);
  return stroker.createStroke(path);
}

void CustomizeItem::drawAnchors(QPainter *painter)
{
  if(_mouseEnter)
  {
    for(int i = 0; i < _anchorRects.size(); i++)
    {
      QPainterPath path;
      path.moveTo(_anchorRects[0].center());
      path.addEllipse(_anchorRects[i].center(), _radius, _radius);

      painter->drawPath(path);
    }
  }
}

customizeitem.h

代码语言:javascript
运行
复制
#ifndef CUSTOMIZEITEM_H
#define CUSTOMIZEITEM_H

#include <QGraphicsItem>
#include <QObject>
#include <QPainter>

class CustomizeItem : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
  enum { Type = UserType + 1 };

  explicit CustomizeItem(QGraphicsItem *parent = nullptr);
  ~CustomizeItem() = default;

protected:
  void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
  void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
  QRectF boundingRect() const;
  void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
  QPainterPath shape() const;
private:
  void drawAnchors(QPainter *painter);

  QRect _bbox;

  float _radius; // radius for circle anchor
  QVector<QRectF> _anchorRects;

  QRect _rectRect;
  bool _mouseEnter;
};

#endif // CUSTOMIZEITEM_H

maiwindow.cpp

代码语言:javascript
运行
复制
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "customizeitem.h"
#include <QGraphicsView>
#include <QVBoxLayout>

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)
  , ui(new Ui::MainWindow)
{
  ui->setupUi(this);

  QVBoxLayout *layout = new QVBoxLayout(centralWidget());
  layout->setContentsMargins(0,0,0,0);

  QGraphicsView *view = new QGraphicsView(this);
  view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  QGraphicsScene *scene = new QGraphicsScene;

  CustomizeItem *item = new CustomizeItem;
  scene->addItem(item);

  view->setScene(scene);
  layout->addWidget(view);
}

MainWindow::~MainWindow()
{
  delete ui;
}

mainwindow.h

代码语言:javascript
运行
复制
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = nullptr);
  ~MainWindow();

private:
  Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

main.cpp

代码语言:javascript
运行
复制
#include "mainwindow.h"

#include <QApplication>

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

Stack Overflow用户

发布于 2021-09-21 20:00:53

或者调整边框矩形以适应额外的大小。

代码语言:javascript
运行
复制
QPainterPath CustomizeItem::shape() const
{
    QPainterPath path;
    path.addRect(_bbox.adjusted(-5, -5, 5, 5));
    return path;
}

由于您的“命中”形状是矩形的,您可能只需重新实现boundingRect(),因为默认的QGraphicsItem::shape()实际上使用boundingRect()结果(根据文档)。

代码语言:javascript
运行
复制
QRectF CustomizeItem::boundingRect() const
{
    return QRectF(_bbox.adjusted(-5, -5, 5, 5));
}
票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69251544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档