【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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/510184

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Qt中实现多线程导出数据功能的四种方式小结

《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方... 目录前言导出文件的示例工具类QThreadQObject的moveToThread方法实现多线程QC

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到