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

Qt/C++开源控件 自定义雷达控件

使用Qt框架创建一个简单的雷达图,包含动态扫描、目标点生成、刻度和方向标识。代码实现使用C++编写,适合用作学习和扩展的基础。
在这里插入图片描述

1. 头文件与基本设置
#include "RadarWidget.h"
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <cmath>
#include <cstdlib>
#include <ctime>
  • 头文件包含:包含必要的Qt模块和C++标准库,如 QPainter 用于绘制图形,cmath 用于数学计算,cstdlibctime 用于随机数生成。
  • 自定义类RadarWidget 继承自 QWidget,表示一个自定义的绘制控件。
2. 构造函数
RadarWidget::RadarWidget(QWidget *parent): QWidget(parent), angle(0), maxTargets(5) {// 初始化随机数种子std::srand(std::time(nullptr));// 创建定时器来更新角度timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &RadarWidget::updateAngle);timer->start(50);  // 设置定时器间隔为50ms// 每隔一段时间生成随机目标点QTimer *targetTimer = new QTimer(this);connect(targetTimer, &QTimer::timeout, this, &RadarWidget::generateRandomTargets);targetTimer->start(2000);  // 每2秒生成一次新的随机目标点
}
  • 初始化:构造函数设置初始的角度为0和最大目标数为5。
  • 随机数种子:使用当前时间初始化随机数生成器,以便每次运行时产生不同的目标点。
  • 定时器
    • 扫描角度更新:每50毫秒调用 updateAngle 方法,更新雷达的扫描角度。
    • 目标点生成:每2秒调用 generateRandomTargets 方法,生成新的目标点。
3. 画图事件
void RadarWidget::paintEvent(QPaintEvent *) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);painter.fillRect(rect(), Qt::black);
  • 画图事件:重载 paintEvent 方法是自定义绘制的核心。
  • 画笔设置:使用 QPainter 来进行绘制,开启抗锯齿以改善绘图质量。
  • 背景填充:将控件背景填充为黑色。
4. 获取控件的中心和半径
    int w = width();int h = height();int radius = qMin(w, h) / 2 * 0.9;  // 设置半径,防止绘制到最边缘QPoint center(w / 2, h / 2);
  • 尺寸计算:获取控件的宽度和高度。
  • 半径设置:计算半径为控件最小边长的一半,乘以0.9以避免绘制到边缘。
  • 中心点:确定雷达图的中心位置。
5. 绘制背景网格和圆形网格
    // 绘制背景网格painter.setPen(QPen(QColor(0, 255, 0, 50), 1));  // 绿色网格线int gridSize = 20;for (int i = 0; i <= w; i += gridSize) {painter.drawLine(i, 0, i, h);  // 垂直网格线painter.drawLine(0, i, w, i);  // 水平网格线}// 绘制雷达的圆形网格painter.setPen(QPen(QColor(0, 255, 0), 1));for (int i = 1; i <= 5; ++i) {painter.drawEllipse(center, radius * i / 5, radius * i / 5);}
  • 背景网格:绘制绿色背景网格线,以每20像素为间隔,增强视觉效果。
  • 圆形网格:绘制5个同心圆,帮助标识距离。
6. 绘制中心十字线和方向线
    // 绘制十字网格线painter.drawLine(center.x() - radius, center.y(), center.x() + radius, center.y());painter.drawLine(center.x(), center.y() - radius, center.x(), center.y() + radius);// 绘制八条方向线static const int directions[8] = {0, 45, 90, 135, 180, 225, 270, 315};painter.setPen(QPen(QColor(0, 255, 0), 1));  // 方向线颜色for (int i = 0; i < 8; ++i) {double angle = directions[i] * PI / 180.0;  // 将角度转换为弧度int x = center.x() + radius * std::cos(angle);int y = center.y() + radius * std::sin(angle);painter.drawLine(center, QPoint(x, y));  // 绘制从中心到边缘的线}
  • 中心十字线:绘制水平和垂直的十字线,进一步增强雷达图的视觉引导。
  • 方向线:绘制八条方向线(0°, 45°, 90°, 135°, 180°, 225°, 270°, 315°),指示各个方位。
7. 绘制刻度线和标注
    // 绘制刻度线和方向标注painter.setPen(QPen(Qt::white, 1));for (int i = 0; i < 360; i += 10) {// 计算刻度线的起点和终点int tickLength = (i % 30 == 0) ? 10 : 5;  // 每30度一个长刻度,其他是短刻度double radian = i * PI / 180.0;int x1 = center.x() + (radius - tickLength) * std::cos(radian);int y1 = center.y() + (radius - tickLength) * std::sin(radian);int x2 = center.x() + radius * std::cos(radian);int y2 = center.y() + radius * std::sin(radian);painter.drawLine(x1, y1, x2, y2);// 每30度绘制数字标注if (i % 30 == 0) {QString angleText = QString::number(i) + "°";int textX = center.x() + (radius + 15) * std::cos(radian) - 10;int textY = center.y() + (radius + 15) * std::sin(radian) + 5;painter.drawText(textX, textY, angleText);}}
  • 刻度线:每10度绘制一条刻度线,每30度绘制较长的刻度线。通过简单的三角函数计算线条的起止点。
  • 数字标注:在每30度的刻度线上添加数字标注,表示当前角度。
8. 绘制方向标注
    // 绘制八个方向标注QFont font = painter.font();font.setBold(true);painter.setFont(font);painter.drawText(center.x() + radius + 5, center.y(), "E");     // Eastpainter.drawText(center.x() - radius - 25, center.y(), "W");     // Westpainter.drawText(center.x(), center.y() - radius - 20, "N");     // Northpainter.drawText(center.x(), center.y() + radius + 10, "S");     // Southpainter.drawText(center.x() + radius * 0.707 + 10, center.y() - radius * 0.707 - 10, "NE");  // Northeastpainter.drawText(center.x() + radius * 0.707 + 10, center.y() + radius * 0.707 + 10, "SE");  // Southeastpainter.drawText(center.x() - radius * 0.707 - 25, center.y() + radius * 0.707 + 10, "SW");  // Southwestpainter.drawText(center.x() - radius * 0.707 - 25, center.y() - radius * 0.707 - 10, "NW"); // Northwest
  • 方向文字标注:绘制东、南、西、北及四个对角的方向文字标注。通过调整文本位置以确保其位于相应的方位。
9. 绘制雷达扫描区域
    // 绘制雷达扫描的渐变区域(顺时针扫描,范围为圆的1/6)QConicalGradient gradient(center, -angle * 180.0 / PI);  // 使用负角度实现顺时针渐变效果gradient.setColorAt(0.0, QColor(0, 255, 0, 180));  // 扫描的前端亮绿色gradient.setColorAt(0.1, QColor(0, 255, 0, 2));  // 中间部分逐渐变淡gradient.setColorAt(1.0, Qt::transparent);         // 扫描尾部完全透明painter.setBrush(gradient);painter.setPen(Qt::NoPen);// 调整扫描区域的角度范围painter.drawPie(center.x() - radius, center.y() - radius, radius * 2, radius * 2,int(-angle * 180.0 / PI * 16), 30 * 16);  // 控制为30度的扫描区域
  • 渐变区域:使用 QConicalGradient 创建一个顺时针的渐变区域,表现雷达扫描效果。
  • 绘制扫描区域:通过 drawPie 方法绘制出当前扫描的区域,以视觉上表现雷达的动态扫描。
10. 绘制动态目标点
    // 动态绘制目标点painter.setBrush(QColor(255, 0, 0, 180));  // 目标点使用红色半透明painter.setPen(Qt::NoPen);for (const QPoint &target : targets) {painter.drawEllipse(target, 6, 6);  // 绘制随机生成的红色目标点}
  • 目标点设置:以红色半透明的方式绘制动态生成的目标点,使其在雷达图上更加突出。
11. 绘制当前扫描线
    // 绘制当前扫描线painter.setPen(QPen(QColor(0, 255, 0), 2));painter.drawLine(center, QPoint(center.x() + radius * std::cos(angle), center.y() + radius * std::sin(angle)));
}
  • 扫描线绘制:绘制一条从中心到当前扫描位置的绿色线条,直观地展示当前雷达的扫描方向。
12. 更新扫描角度
void RadarWidget::updateAngle() {// 以一定的步伐增加扫描角度,使扫描线顺时针旋转angle += 0.05;if (angle >= 2 * PI)angle = 0;update();  // 调用重绘
}
  • 更新扫描角度:在每次定时器触发时,增加扫描角度,使其顺时针旋转。
  • 重绘:调用 update() 方法触发控件重绘,确保绘制的内容保持最新。
13. 生成随机目标点
void RadarWidget::generateRandomTargets() {targets.clear();  // 清空现有目标点int w = width();int h = height();int radius = qMin(w, h) / 2 * 0.9;  // 半径也需要保持一致QPoint center(w / 2, h / 2);// 随机生成目标点(最多maxTargets个)for (int i = 0; i < maxTargets; ++i) {// 随机生成目标点位置,限制在雷达半径范围内int randRadius = std::rand() % (radius - 10);  // 防止目标点超出边界double randAngle = (std::rand() % 360) * PI / 180.0;int x = center.x() + randRadius * std::cos(randAngle);int y = center.y() + randRadius * std::sin(randAngle);  // 顺时针方向targets.push_back(QPoint(x, y));}update();  // 更新界面显示
}
  • 目标点生成:清空现有目标点,并随机生成指定数量(最多 maxTargets)的新目标点,确保其位置在雷达半径范围内。
  • 随机化:使用随机半径和角度来生成目标点,确保每次生成的目标点位置不相同。

总结

这个开源Demo提供了一个简单易用的雷达图控件,涵盖了Qt绘图的基本用法和动态内容更新的实现。用户可以在此基础上进行扩展,例如:

  • 添加用户交互功能,例如点击目标点获取信息。
  • 实现更复杂的目标点生成逻辑,或者根据外部数据动态更新目标位置。
  • 改进UI界面,使其更符合现代应用的设计规范。

通过深入了解和分析这个Demo,你将能够掌握Qt绘图机制和动态控件的设计,适合用于学习和实际项目中。希望这对你有帮助!

相关文章:

Qt/C++开源控件 自定义雷达控件

使用Qt框架创建一个简单的雷达图&#xff0c;包含动态扫描、目标点生成、刻度和方向标识。代码实现使用C编写&#xff0c;适合用作学习和扩展的基础。 1. 头文件与基本设置 #include "RadarWidget.h" #include <QPainter> #include <QPen> #include &…...

什么是IDE(集成开发环境)?

集成开发环境(IDE)详解 在软件开发的世界中,集成开发环境(IDE,Integrated Development Environment)扮演着至关重要的角色。它是一个综合性的软件应用程序,旨在为软件开发者提供一整套的、易于使用的工具集,以便他们能够更高效地编写、调试、测试和部署代码。简而言之…...

【Linux】用虚拟机配置Ubuntu 24.04.1 LTS环境

目录 1.虚拟机安装Ubuntu系统 2.Ubuntu系统的网络配置 3.特别声明 首先我们先要下载VMware软件&#xff0c;大家自己去下啊&#xff01; 1.虚拟机安装Ubuntu系统 我们进去之后点击创建新的虚拟机&#xff0c;然后选择自定义 接着点下一步 再点下一步 进入这个界面之后&…...

MacOS升级Ruby版本详解:步骤、挑战与解决方案

MacOS升级Ruby版本详解&#xff1a;步骤、挑战与解决方案 在MacOS上升级Ruby版本是一个涉及多个步骤和考虑因素的过程。Ruby作为一种广泛使用的编程语言&#xff0c;其新版本通常会引入一系列改进&#xff0c;包括性能优化、安全修复和新特性。因此&#xff0c;升级Ruby版本不…...

Log4j的配置与使用详解

Log4j的配置与使用详解 Log4j介绍 Log4j是Apache的一个开源项目&#xff0c;通过使用Log4j&#xff0c;我们可以控制日志信息输送的目的地是控制台、文件、GUI组件&#xff0c;我们可以控制每条日志的输出格式&#xff1b;只需要通过一个配置文件就可以灵活的配置&#xff0c…...

docker 的目录有那些,分别存放什么东西

Docker 的目录结构和文件存放位置取决于你所使用的操作系统和Docker的版本。以下是一些常见的目录和它们通常存放的内容&#xff1a; 通用目录 /var/lib/docker (Linux) 这是Docker在Linux系统上的主要数据目录。存放了镜像、容器、数据卷、网络等的元数据和状态信息。具体结构…...

开源模型应用落地-模型微调-语料采集-数据格式化(四)

一、前言 在自然语言处理(NLP)的快速发展中,语料采集作为基础性的步骤显得尤为重要。它不仅为机器学习模型提供了所需的训练数据,还直接影响模型的性能和泛化能力。随着数据驱动技术的不断进步,如何有效并高效地收集、清洗和整理丰富多样的语料,已成为研究者和工程师们亟…...

C语言+单片机

今天内容有点水哈哈&#xff08;忙着练焊铁技术了嘻嘻&#xff09; C语言 简单学习了while语言以及其与for语言的区别和适用方法 .循环结构&#xff1a; 初始化语句条件判断句条件控制句 for语句 for(int1;i<100;i){执行条件} for (int i 1; i < 100; i) {printf(&quo…...

vmvare虚拟机centos 忘记超级管理员密码怎么办?

vmvare虚拟机centos 忘记超级管理员密码怎么办?如何重置密码呢? 一、前置操作 重启vmvare虚拟机的过程中,长按住Shift键 选择第一个的时候,按下按键 e 进入编辑状态。 然后就会进入到类似这个界面中。 在下方界面 添加 init=/bin/sh,然后按下Ctrl+x进行保存退出。 init=/bi…...

使用 Vue3 和 Axios 实现 CRUD 操作

文章目录 1、准备工作2、创建 Vue 3 项目3、项目结构4、实现 CRUD 操作5、运行项目6、小结在当今的前端开发中,Vue.js 作为一款流行的 JavaScript 框架,正在被越来越多的开发者所青睐。尤其是 Vue 3 引入了 Composition API 和更优雅的响应式处理,使得模板编写和状态管理变得…...

.NET MAUI(.NET Multi-platform App UI)下拉选框控件

MAUI下拉选框控件详解&#xff1a; 在开发跨平台应用程序时&#xff0c;下拉选框&#xff08;ComboBox&#xff09;是一个极为常见且实用的控件&#xff0c;它允许用户从一组预定义的选项中选择一个。在.NET MAUI&#xff08;.NET Multi-platform App UI&#xff09;框架中&am…...

C++平台跳跃游戏

目录 开头程序Game.cpp源文件Player.h头文件Player.cpp源文件 程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 Game.cpp源文件 #include <iostream> #include "Player.h" using namespace std; void printma…...

多系统萎缩患者必看!这些维生素助你对抗病魔

亲爱的朋友们&#xff0c;今天我们来聊聊一个相对陌生但重要的健康话题——多系统萎缩&#xff08;MSA&#xff09;。这是一种罕见的神经系统疾病&#xff0c;影响着患者的自主神经系统、运动系统和平衡功能。面对这样的挑战&#xff0c;科学合理的饮食和营养补充显得尤为重要。…...

深度学习模型性能优化实战之从评估到提升的全流程解析

1. 概述 在构建和使用机器学习模型的过程中&#xff0c;模型的效果评估和优化是两个至关重要的环节。无论模型是用于分类、回归还是其他任务&#xff0c;评估其表现以及持续优化模型性能&#xff0c;都是确保模型在实际应用中取得成功的关键。本节将重点介绍模型效果评估的定义…...

C++ | Leetcode C++题解之第446题等差数列划分II-子序列

题目&#xff1a; 题解&#xff1a; class Solution { public:int numberOfArithmeticSlices(vector<int> &nums) {int ans 0;int n nums.size();vector<unordered_map<long long, int>> f(n);for (int i 0; i < n; i) {for (int j 0; j < i;…...

【解密 Kotlin 扩展函数】扩展属性与扩展函数类似(十九)

导读大纲 1.1.1 扩展属性的创建和使用 1.1.1 扩展属性的创建和使用 之前, 我们已经了解声明 Kotlin 属性的语法 Kotlin中的顶级属性–传送门就像扩展函数一样,我们也可以指定扩展属性就像之前所说&#xff0c;属性和函数的区别在于前者是特征&#xff0c;后者是行为 相比扩展函…...

【Spring Boot 入门二】Spring Boot中的配置文件 - 掌控你的应用设置

一、引言 在上一篇文章中&#xff0c;我们开启了Spring Boot的入门之旅&#xff0c;成功构建了第一个Spring Boot应用。我们从环境搭建开始&#xff0c;详细介绍了JDK的安装以及IDE的选择与配置&#xff0c;然后利用Spring Initializr创建了项目&#xff0c;分析了项目结构&am…...

OpenCV第十二章——人脸识别

1.人脸跟踪 1.1 级联分类器 OpenCV中的级联分类器是一种基于AdaBoost算法的多级分类器&#xff0c;主要用于在图像中检测目标对象。以下是对其简单而全面的解释&#xff1a; 一、基本概念 级联分类器&#xff1a;是一种由多个简单分类器&#xff08;弱分类器&#xff09;级联组…...

深入Volatile

深入Volatile 1、变量不可见性&#xff1a; 1.1多线程下变量的不可见性 直接上代码 /*** author yourkin666* date 2024/08/12/16:12* description*/ public class h1 {public static void main(String[] args) {MyClass myClass new MyClass();myClass.start();while (tr…...

数据结构 ——— 顺序表oj题:编写函数,合并两个有序数组

目录 题目要求 代码实现 题目要求 nums1 和 nums2 是两个升序的整型数组&#xff0c;另外有两个整数 m 和 n 分别代表 nums1 和 nums2 中的元素个数 要求合并 nusm2 到nums1 中&#xff0c;使合并后的 nums1 同样按升序顺序排列 最终&#xff0c;合并后的数组不应由函数返…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...