当前位置: 首页 > news >正文

Qt饼状图在图例上追踪鼠标落点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、饼状图的关键接口
  • 二、关键代码
    • 1.鼠标移动事件
    • 2.核心判断逻辑
  • 总结


前言

最近做了一个项目,需要当鼠标在饼状图上移动的时候展示Slice的内容,现有的饼状图接口不能满足我的需求,所以我想到了手动实现追踪鼠标移动并判断落点是不是在图例内部。

主要难点在于将x,y点转变成极坐标并判断鼠标落在哪一个Slice上,从而实现定制化效果。


一、饼状图的关键接口

	setMouseTracking(true); // 鼠标追踪,必须打开
    _chart->layout()->setContentsMargins(0, 0, 0, 0);  // 设置图表外边距,0无边距
    _chart->setMargins(QMargins(0, 0, 0, 0));  // 设置图表内边距,0无边距
    _series->setPieSize(pPieSize); //这里pPieSize是0.6

二、关键代码

1.鼠标移动事件

先打开上面的鼠标追踪,一定要打开鼠标追踪,否则鼠标在Widget上的时候只会触发一次Move。

void XPieChart::mouseMoveEvent(QMouseEvent *event) {
    calculateInSlice(event->pos());
    QChartView::mouseMoveEvent(event);
}

2.核心判断逻辑

核心要点不复杂,先判断距离是不是小于半径(注意场景坐标转换)。其次xy坐标转换成极坐标,判断是不是在角度范围内即可。

void XPieChart::calculateInSlice(const QPoint &point) {
    // 坐标转换
    QPointF scenePos = mapToScene(point);
    QPointF chartPos = chart()->mapFromScene(scenePos);
    QRectF plotArea = chart()->plotArea();
    QPointF center = plotArea.center();
    qreal radius = qMin(plotArea.width(), plotArea.height()) / 2 * pPieSize;

// 计算距离和角度
    qreal dx = chartPos.x() - center.x();
    qreal dy = chartPos.y() - center.y();
    qreal distance = sqrt(dx * dx + dy * dy);
    if (distance > radius) {  // 饼图之外
        updatePopupState(false);
        return;
    }
qDebug() << "chartPos: " << chartPos << " center: " << center;
    qreal angle = qRadiansToDegrees(qAtan2(dy, dx));
    qDebug() << "angle: " << angle;
    qreal pieAngle = 90 + angle;  // 转换为饼图角度系统
    if (pieAngle < 0) pieAngle += 360;

// 遍历series查找slice
    QPieSeries *series = nullptr;
    foreach (QAbstractSeries *s, chart()->series()) {
        series = qobject_cast<QPieSeries *>(s);
        if (series) break;
    }

if (!series) {
        updatePopupState(false);
        return;
    }

foreach (QPieSlice *slice, series->slices()) {
        qreal start = slice->startAngle();
        qreal span = slice->angleSpan();
        qreal end = start + span;
        bool inSlice = false;
if (end > 360) {
            if ((pieAngle >= start && pieAngle <= 360) || (pieAngle >= 0 && pieAngle <= end - 360)) {
                inSlice = true;
            }
        }else {
            if (pieAngle >= start && pieAngle <= end) {
                inSlice = true;
            }
        }
if (inSlice) {
            qDebug() << "pieAngle: " << pieAngle;
            qDebug() << "slice: " << slice->label() << " start: " << start << " span: " << span;
            _popupLabel->setText(slice->label());
            _popupValue->setText(QString::number(slice->value()));
            updatePopupState(true, point);
            break;
} else {
            updatePopupState(false);
        }
}

注意:如果Slice展开可能影响判断结果,需要计算Slice展开的距离差。


总结

1、思路比较透彻,没什么难度,适合定制化需求

相关文章:

  • 人脸表情识别数据集分享(AffectNet、RAF-DB、FERPlus、FER2013、ck+)
  • NVIDIA Jetson 环境安装指导 PyTorch | Conda | cudnn | docker
  • 【qiankun】简易前端微应用搭建
  • 企业工厂生产线马达保护装置 功能参数介绍
  • 4.6学习总结
  • 网络中级(HCIP)项目实践一MGRE的两种架构的私有网段 OSPF 动态路由协议的互联实验(手把手教您,包学会的)
  • 使用 STM32F103C8 连接 ESP8266:创建 Web 服务器
  • 数据结构与算法-数学-基础数学2(扩展欧几里得算法,组合数问题)
  • C++中的类和对象(上)
  • CSS 锚点定位
  • spring-ai-openai调用Xinference1.4.1报错
  • 【ZYNQ Linux移植】1-前期准备
  • 【C++初阶】--- string类模拟实现
  • Springboot JPA ShardingSphere 根据年分表
  • CentOS 7无法上网问题解决
  • 由小到大的数列,寻找是否存在一个数的耗时最小的算法
  • Linux红帽:RHCSA认证知识讲解(十 二)调试 SELinux,如何管理 SELinux 的运行模式、安全策略、端口和上下文策略
  • WEB安全--内网渗透--捕获NET-NTLMv2 Hash
  • 【Android Audio】Parameter Framework - pfw
  • 解锁轨道交通 UI 界面设计的奥秘,打造出行新体验
  • 湖北工程建设信息网站/最新消息
  • 迷你主机做网站/广州做seo的公司
  • 建设银行网站注册/产品营销推广策略
  • pc网站建设的三大条件/营销咨询公司排名前十
  • 广西大兴建设有限公司网站/网站展示型推广
  • 真人真做网站/广东全网推广