【QT Graphics/View】自定义动态同心圆DyConcentricCircle

2023-12-18 23:40

本文主要是介绍【QT Graphics/View】自定义动态同心圆DyConcentricCircle,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、功能

1、任意平移、改变内圆、外圆大小

2、鼠标中键切换箭头方向

3、获取圆心坐标,获取大小半径

4、鼠标移动到圆的边缘上改变鼠标形状

二、效果图

 

三、实现原理

1、图元组成及对应接口

2个圆圈

    painter->drawEllipse(rect1);painter->drawEllipse(rect2);

2条直线

    painter->drawLine(m_center.x() - m_radius, m_center.y(), m_center.x() - m_another_radius, m_center.y());painter->drawLine(m_center.x() + m_radius, m_center.y(), m_center.x() + m_another_radius, m_center.y());

2个箭头(一个箭头由2条直线组成)

2、判断鼠标在圆上

diff = 鼠标点与圆心的距离 - 圆的半径 

如果diff接近于0则认为鼠标在圆上

bool DyConcentricCircle::judgeInCircle(QPointF pos)
{QLineF line(m_center, pos);if(abs(line.length() - m_radius) < this->pen().widthF()){return true;}return false;
}

3、获取半径

并没有规定哪个半径为外半径,哪个半径为内半径,而是通过最大值、最小值确认的

外圆半径 = max(r1, r2)

内圆半径 = min(r1,r2)

double DyConcentricCircle::radiusInner() const
{return qMin(m_radius, m_another_radius);
}double DyConcentricCircle::radiusOuter() const
{return qMax(m_radius, m_another_radius);
}

四、关键代码

.h

#ifndef DYCONCENTRICCIRCLE_H
#define DYCONCENTRICCIRCLE_H#include "BaseGraphicsItem.h"class DyConcentricCircle : public BaseGraphicsItem
{Q_OBJECT
public:DyConcentricCircle(QPointF center, qreal radius1, qreal radius2,E_ItemType type = BaseGraphicsItem::E_ItemType::Dy_ConcentricCircle);double radiusInner() const;double radiusOuter() const;public:enum E_STATE_FLAG{DEFAULT_FLAG = 0,MOV_RADIUS,            /**< 第一个圆半径 */MOV_ANOTHER_RADIUS,    /**< 第二个圆半径 */};protected:virtual QRectF boundingRect() const override;virtual void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget) override;virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;private:/*** @brief judgeInCircle 是否在第一个圆上* @param pos* @return*/bool judgeInCircle(QPointF pos);/*** @brief judgeInAnotherArc 是否在第二个圆上* @param pos* @return*/bool judgeInAnotherCircle(QPointF pos);protected:qreal m_radius = 0;            /**< 第一个半径 */qreal m_another_radius = 0;    /**< 第二个半径 */E_STATE_FLAG m_stateFlag = DEFAULT_FLAG;
};#endif // DYCONCENTRICCIRCLE_H

.cpp

#include "DyConcentricCircle.h"
#include <QMenu>
#include <QSpinBox>
#include <QWidgetAction>
#include <QDebug>
#include <QComboBox>
#include <QCheckBox>
#include <QtMath>DyConcentricCircle::DyConcentricCircle(QPointF center, qreal radius1, qreal radius2, E_ItemType type): BaseGraphicsItem(center, type), m_radius(radius1),  m_another_radius(radius2)
{m_pointList.append(new DyPointItem(this, m_center, DyPointItem::Center));m_pointList.setRandColor();setAcceptHoverEvents(true);this->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
}double DyConcentricCircle::radiusInner() const
{return qMin(m_radius, m_another_radius);
}double DyConcentricCircle::radiusOuter() const
{return qMax(m_radius, m_another_radius);
}QRectF DyConcentricCircle::boundingRect() const
{qreal maxRadius = qMax(m_radius, m_another_radius);return QRectF(m_center.x() - maxRadius, m_center.y() - maxRadius, maxRadius * 2, maxRadius * 2);
}void DyConcentricCircle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{Q_UNUSED(option);Q_UNUSED(widget);QPen pen = this->pen();double scaleFactor = painter->matrix().m11();pen.setWidthF(pen.widthF() / scaleFactor + 1);  /* 线段保持原来的线宽 */painter->setPen(pen);
//    QBrush brush(pen.color(), Qt::Dense1Pattern);
//    painter->setBrush(brush);painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);/* 画圆 */QRectF rect1(m_center.x() - m_radius, m_center.y() - m_radius,m_radius * 2, m_radius * 2);QRectF rect2(m_center.x() - m_another_radius, m_center.y() - m_another_radius,m_another_radius * 2, m_another_radius * 2);painter->drawEllipse(rect1);painter->drawEllipse(rect2);/* 直线 */pen.setStyle(Qt::SolidLine);painter->setPen(pen);painter->drawLine(m_center.x() - m_radius, m_center.y(), m_center.x() - m_another_radius, m_center.y());painter->drawLine(m_center.x() + m_radius, m_center.y(), m_center.x() + m_another_radius, m_center.y());/* 箭头 */double arrowSize = 10;double arrowAngle = M_PI / 6;if(0 == m_direction){qreal radiusIn = radiusInner();/* 左箭头 */QPointF leftP(m_center.x() - radiusIn,  m_center.y());QPointF leftArrowP1;leftArrowP1.setX(m_center.x() - radiusIn - arrowSize * cos(arrowAngle));leftArrowP1.setY(m_center.y() - arrowSize * sin(arrowAngle));QPointF leftArrowP2;leftArrowP2.setX(m_center.x() - radiusIn - arrowSize * cos(arrowAngle));leftArrowP2.setY(m_center.y() + arrowSize * sin(arrowAngle));painter->drawLine(leftArrowP1, leftP);painter->drawLine(leftArrowP2, leftP);/* 右箭头 */QPointF rightP(m_center.x() + radiusIn,  m_center.y());QPointF rightArrowP1;rightArrowP1.setX(m_center.x() + radiusIn + arrowSize * cos(arrowAngle));rightArrowP1.setY(m_center.y() - arrowSize * sin(arrowAngle));QPointF rightArrowP2;rightArrowP2.setX(m_center.x() + radiusIn + arrowSize * cos(arrowAngle));rightArrowP2.setY(m_center.y() + arrowSize * sin(arrowAngle));painter->drawLine(rightArrowP1, rightP);painter->drawLine(rightArrowP2, rightP);}else{qreal radiusOut = radiusOuter();/* 左箭头 */QPointF leftP(m_center.x() - radiusOut,  m_center.y());QPointF leftArrowP1;leftArrowP1.setX(m_center.x() - radiusOut + arrowSize * cos(arrowAngle));leftArrowP1.setY(m_center.y() - arrowSize * sin(arrowAngle));QPointF leftArrowP2;leftArrowP2.setX(m_center.x() - radiusOut + arrowSize * cos(arrowAngle));leftArrowP2.setY(m_center.y() + arrowSize * sin(arrowAngle));painter->drawLine(leftArrowP1, leftP);painter->drawLine(leftArrowP2, leftP);/* 右箭头 */QPointF rightP(m_center.x() + radiusOut,  m_center.y());QPointF rightArrowP1;rightArrowP1.setX(m_center.x() + radiusOut - arrowSize * cos(arrowAngle));rightArrowP1.setY(m_center.y() - arrowSize * sin(arrowAngle));QPointF rightArrowP2;rightArrowP2.setX(m_center.x() + radiusOut - arrowSize * cos(arrowAngle));rightArrowP2.setY(m_center.y() + arrowSize * sin(arrowAngle));painter->drawLine(rightArrowP1, rightP);painter->drawLine(rightArrowP2, rightP);}
}void DyConcentricCircle::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{if(judgeInCircle(event->pos())){setCursor(Qt::CrossCursor);}else if (judgeInAnotherCircle(event->pos())){setCursor(Qt::CrossCursor);}else{setCursor(Qt::ArrowCursor);}event->accept();
}void DyConcentricCircle::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{if(judgeInCircle(event->pos())){setCursor(Qt::CrossCursor);}else if (judgeInAnotherCircle(event->pos())){setCursor(Qt::CrossCursor);}else{setCursor(Qt::ArrowCursor);}event->accept();
}void DyConcentricCircle::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{setCursor(Qt::ArrowCursor);event->accept();
}void DyConcentricCircle::mousePressEvent(QGraphicsSceneMouseEvent *event)
{if(event->button() == Qt::LeftButton){if(judgeInCircle(event->pos())){m_stateFlag = MOV_RADIUS;}else if(judgeInAnotherCircle(event->pos())){m_stateFlag = MOV_ANOTHER_RADIUS;}}else if(event->button() == Qt::RightButton){}else if(event->button() == Qt::MiddleButton){/* 中键切换方向 */if(0 == m_direction){m_direction = 1;}else{m_direction = 0;}emit stateChanged(this);}QGraphicsItem::mousePressEvent(event);
}void DyConcentricCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{switch (static_cast<int>(m_stateFlag)){case MOV_RADIUS:{/* 必须为pos,非scenePos*/QLineF line(m_center, event->pos());m_radius = line.length();break;}case MOV_ANOTHER_RADIUS:{QLineF line(m_center, event->pos());m_another_radius = line.length();break;}default:{QGraphicsItem::mouseMoveEvent(event);break;}}
}void DyConcentricCircle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{m_stateFlag = DEFAULT_FLAG;if(event->button() == Qt::LeftButton){emit stateChanged(this);}QGraphicsItem::mouseReleaseEvent(event);
}void DyConcentricCircle::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{if(event->button() == Qt::LeftButton){emit selectCompleted(this);}QGraphicsItem::mouseDoubleClickEvent(event);
}bool DyConcentricCircle::judgeInCircle(QPointF pos)
{QLineF line(m_center, pos);if(abs(line.length() - m_radius) < this->pen().widthF()){return true;}return false;
}bool DyConcentricCircle::judgeInAnotherCircle(QPointF pos)
{QLineF line(m_center, pos);if(abs(line.length() - m_another_radius) < this->pen().widthF()){return true;}return false;
}

这篇关于【QT Graphics/View】自定义动态同心圆DyConcentricCircle的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/qq_40602000/article/details/119765484
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/510184

相关文章

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

Qt如何实现文本编辑器光标高亮技术

《Qt如何实现文本编辑器光标高亮技术》这篇文章主要为大家详细介绍了Qt如何实现文本编辑器光标高亮技术,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录实现代码函数作用概述代码详解 + 注释使用 QTextEdit 的高亮技术(重点)总结用到的关键技术点应用场景举例示例优化建议

Qt 设置软件版本信息的实现

《Qt设置软件版本信息的实现》本文介绍了Qt项目中设置版本信息的三种常用方法,包括.pro文件和version.rc配置、CMakeLists.txt与version.h.in结合,具有一定的参考... 目录在运行程序期间设置版本信息可以参考VS在 QT 中设置软件版本信息的几种方法方法一:通过 .pro

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET