【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

相关文章

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

基于Qt实现系统主题感知功能

《基于Qt实现系统主题感知功能》在现代桌面应用程序开发中,系统主题感知是一项重要的功能,它使得应用程序能够根据用户的系统主题设置(如深色模式或浅色模式)自动调整其外观,Qt作为一个跨平台的C++图形用... 目录【正文开始】一、使用效果二、系统主题感知助手类(SystemThemeHelper)三、实现细节

Qt实现文件的压缩和解压缩操作

《Qt实现文件的压缩和解压缩操作》这篇文章主要为大家详细介绍了如何使用Qt库中的QZipReader和QZipWriter实现文件的压缩和解压缩功能,文中的示例代码简洁易懂,需要的可以参考一下... 目录一、实现方式二、具体步骤1、在.pro文件中添加模块gui-private2、通过QObject方式创建

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

Qt QWidget实现图片旋转动画

《QtQWidget实现图片旋转动画》这篇文章主要为大家详细介绍了如何使用了Qt和QWidget实现图片旋转动画效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、效果展示二、源码分享本例程通过QGraphicsView实现svg格式图片旋转。.hpjavascript