QT上位机开发(图形绘制)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        图形绘制是上位机软件开发很重要的一个功能。这个图形绘制,有的是离线的,有的是实时绘制的。就我个人而言,离线绘制的情况可能更多一些,因为可以反复看、反复研究。相信做过控制的同学肯定都学过PID,用上位机调整PID参数就是很好的一种方式。今天呢,我们正好借助于qt的painter机制,来绘制一个简单的正弦图和余弦图,以备将来之用。

1、创建qt示例工程

        因为今天实现的是图形绘制,所以基本上只需要一个空窗口就可以。不需要用designer在上面绘制任何的控件。

2、QtWidgetsApplication.h头文件

        图形绘制中不涉及到任何的变量,目前只涉及到一个函数,那就是paintEvent这个函数。所以,在头文件中也只需要添加这么一个函数即可。

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication.h"

class QtWidgetsApplication : public QMainWindow
{
	Q_OBJECT

public:
	QtWidgetsApplication(QWidget *parent = nullptr);
	~QtWidgetsApplication();

private:
	Ui::QtWidgetsApplicationClass ui;

protected:
	void paintEvent(QPaintEvent *event);

};

3、QtWidgetsApplication.cpp文件

        对于窗口,或者是widget的重绘,在qt上面都是通过paintEvent函数进行的。首先呢,一般先创建一个QPainter变量,入参就是当前的窗口。接着,绘制两条直线,分别是x轴和y轴。有了这两条轴之后,就可以接着绘制正弦和余弦了。

        因为正弦和余弦是非常类似的,所以这里仅分析一下正弦的画法。绘制正弦之前,需要确定一下采样的点数,也就是绘制的精度是多少。当然,因为整个窗口是需要画满的,这个时候总的宽度和点数相除,就产生了步进的长度。

        有了步进长度和总点数之后,就开始计算每个点的位置。此时又因为绘制y轴的时候,窗口的坐标是至上而下的,这和实际的坐标有点差别,所以需要用height/2 - v_sin*height/2处理下。每次绘制的时候,都是绘制的一条短直线,很多短的直线连在一起,构成了我们需要的正弦弧线。这就是整个绘制的过程。

#include <QtWidgets>
#include "QtWidgetsApplication.h"

QtWidgetsApplication::QtWidgetsApplication(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
}

// destructor function
QtWidgetsApplication::~QtWidgetsApplication()
{
}

void QtWidgetsApplication::paintEvent(QPaintEvent *event)  {
	Q_UNUSED(event);

	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	int width = this->width();
	int height = this->height();

	// draw axis
	painter.drawLine(0, height / 2, width, height / 2); // X
	painter.drawLine(width / 2, 0, width / 2, height); // Y

	int samples = 100; // sample number
	double step = static_cast<double>(width) / samples;

	// sin curve
	painter.setPen(Qt::blue);
	QPointF lastPoint(0, height / 2 - sin(0) * height / 2);
	for (int i = 1; i <= samples; ++i) {
		double x = i * step;
		double y = height / 2 - sin(x / width * 4 * M_PI) * height / 2;
		painter.drawLine(lastPoint, QPointF(x, y));
		lastPoint = QPointF(x, y);
	}

	// cos curve
	painter.setPen(Qt::red);
	lastPoint = QPointF(0, height / 2 - cos(0) * height / 2);
	for (int i = 1; i <= samples; ++i) {
		double x = i * step;
		double y = height / 2 - cos(x / width * 4 * M_PI) * height / 2;
		painter.drawLine(lastPoint, QPointF(x, y));
		lastPoint = QPointF(x, y);
	}
}

  

4、编译和测试

        编译和测试就比较简单了,如果显示没有问题,那就代表是正确的;反之,就是有问题了。具体是显示的问题,还是计算的问题,这个就要去单步debug一下才知道了。

5、动态的正弦和余弦

        上面测试的正弦和余弦虽然没有问题,但是不知道大家有没有想过,如何才能让这两组曲线动起来呢。其实,方法就在于定时器和曲线的相位,首先需要在QtWidgetsApplication.h添加变量,即定时器、phase和定时器槽函数,

#pragma once

#include <QtWidgets/QMainWindow>
#include <QTimer>
#include "ui_QtWidgetsApplication.h"

class QtWidgetsApplication : public QMainWindow
{
	Q_OBJECT

public:
	QtWidgetsApplication(QWidget *parent = nullptr);
	~QtWidgetsApplication();

private:
	Ui::QtWidgetsApplicationClass ui;

protected:
	void paintEvent(QPaintEvent *event);

private slots:
	void updateAnimation();

private:
	QTimer *timer;
	double phase;
};

        做好了这一点,QtWidgetsApplication.cpp也做做出修改,相关的动作包括初始化定时器、实现定时器回调函数、根据phase重新绘制曲线。这里面需要注意的就是update函数,它会触发窗口重新绘制。

#include <QtWidgets>
#include "QtWidgetsApplication.h"

QtWidgetsApplication::QtWidgetsApplication(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, &QtWidgetsApplication::updateAnimation);
	timer->start(50); // timer interval is 50ms
	phase = 0.0;
}

// destructor function
QtWidgetsApplication::~QtWidgetsApplication()
{
}

void QtWidgetsApplication::paintEvent(QPaintEvent *event)  {
	Q_UNUSED(event);

	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	int width = this->width();
	int height = this->height();

	// draw axis
	painter.drawLine(0, height / 2, width, height / 2); // X
	painter.drawLine(width / 2, 0, width / 2, height); // Y

	int samples = 100; // sample
	double step = static_cast<double>(width) / samples;

	// draw sin
	painter.setPen(Qt::blue);
	QPointF lastPoint(0, height / 2 - sin(phase) * height / 2);
	for (int i = 1; i <= samples; ++i) {
		double x = i * step;
		double y = height / 2 - sin(x / width * 4 * M_PI + phase) * height / 2;
		painter.drawLine(lastPoint, QPointF(x, y));
		lastPoint = QPointF(x, y);
	}

	// draw cos
	painter.setPen(Qt::red);
	lastPoint = QPointF(0, height / 2 - cos(phase) * height / 2);
	for (int i = 1; i <= samples; ++i) {
		double x = i * step;
		double y = height / 2 - cos(x / width * 4 * M_PI + phase) * height / 2;
		painter.drawLine(lastPoint, QPointF(x, y));
		lastPoint = QPointF(x, y);
	}
}

void QtWidgetsApplication::updateAnimation() {
	phase += 0.1; // update phase
	update();     // trigger painter
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/284653.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取相机当前数据吞吐量(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK里函数来获取相机当前数据吞吐量&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的数据吞吐量的技术背景CameraExplorer如何查看相机吞吐量信息在NEOAPI SDK里通过函数获取相机接口吞吐量 Baumer工业相机通过NEOAPISDK获…

美团到店终端从标准化到数字化的演进之路

总第580篇 | 2023年第032篇 本文整理自美团技术沙龙第76期《大前端研发协同效能提升与实践》。前端团队在产研多角色协同形式上存在不同阶段&#xff0c;而大前端多技术栈在各阶段都有其独特的实践&#xff0c;同时又有类似的演进路线。本文从到店终端团队移动端和前端技术栈持…

用python做猴子摘桃的题目,java猴子爬台阶算法

本篇文章给大家谈谈猴子爬山算法java完整代码&#xff0c;以及用python做猴子摘桃的题目&#xff0c;希望对各位有所帮助&#xff0c;不要忘了收藏本站喔。 """ 一天一只猴子想去从山脚爬到山顶&#xff0c;途中经过一个有N个台阶的阶梯&#xff0c;但是这猴子有…

Embedding模型在大语言模型中的重要性

引言 随着大型语言模型的发展&#xff0c;以ChatGPT为首&#xff0c;涌现了诸如ChatPDF、BingGPT、NotionAI等多种多样的应用。公众大量地将目光聚焦于生成模型的进展之快&#xff0c;却少有关注支撑许多大型语言模型应用落地的必不可少的Embedding模型。本文将主要介绍为什么…

12 HAL库的硬件SPI驱动数码管

引言&#xff1a; 本文将为大家介绍一下SPI&#xff0c; 数码管的知识&#xff0c; 以及HAL库驱动SPI接口的数码的代码示例。 一、SPI的基础知识 1. SPI简介 01 SPI是串行外设接口&#xff08;Serial Peripheral Interface&#xff09;的缩写 02 是美国摩托罗拉公司&#xff08…

5个用于构建Web应用程序的Go Web框架

探索高效Web开发的顶级Go框架 Go&#xff08;或称为Golang&#xff09;以其简洁性、高效性和出色的标准库而闻名。然而&#xff0c;有几个流行的Go Web框架和库为构建Web应用程序提供了额外的功能。以下是五个最值得注意的Go框架&#xff1a; 1. Gin&#xff1a; Gin是一个高…

加法器原理详解

加法器的介绍与原理分析 什么是加法器&#xff1f; 加法器是一种数字电路&#xff0c;用于将两个二进制数相加并输出它们的和。 如何实现加法器 要讨论如何实现加法器就要先从只有一位的数字先进行考虑 一位二进制数相加 不考虑来自低位的进位——半加器 对于一位二进制…

训狗技术从初级到高级,专业有效的训狗训犬教程

一、教程描述 现在大部分人家里都会养些宠物&#xff0c;比如狗狗&#xff0c;虽然狗狗的一些行为习惯跟遗传有关&#xff0c;但是主人后天的影响也会给狗狗带来改变&#xff0c;本套教程教你纠正狗狗的不良行为&#xff0c;可以让你与狗愉快地玩耍。本套训狗教程&#xff0c;…

hugo-theme-kiwi V0.0.2 博客主题上新了时间轴

至此佳节&#xff0c;我在此给正在屏幕前浏览本文的您和您的家人&#xff0c;恭祝元旦快乐&#xff0c;虽然&#xff0c;这声祝福是晚了&#xff0c;但却不妨碍我我由内心深处对您和您的家人的诚挚祝福&#xff01; 新的一年&#xff0c;从这一天逐渐步入我们的生活&#xff0c…

你好2024!

大家好&#xff0c;我是小悟 2024年1月1日&#xff0c;新年的第一天&#xff0c;阳光明媚&#xff0c;空气中弥漫着希望和新的开始的气息。在这个特别的日子里&#xff0c;大家纷纷走出家门&#xff0c;迎接新年的到来。 街道上&#xff0c;熙熙攘攘的人群中&#xff0c;有孩…

个人博客主题 vuepress-hope

文章目录 1. 简介2. 配置2.1 个人博客&#xff0c;社媒链接配置 非常推荐vuepress-hope 1. 简介 下面的我的博客文章的截图 通过md写博客并且可以同步到github-page上 2. 配置 2.1 个人博客&#xff0c;社媒链接配置 配置文件 .vuepress/theme.ts blog: {medias: {BiliB…

B2005 字符三角形(python)

a input() print( a) print( a a a) print(a a a a a)python中默认输入的是字符型&#xff0c;第一句就是输入了一个字符赋给a python中单引号内的也是字符串&#xff0c;用print输出需要连接的字符串时用加号加在后面即可

SELinux 基本原理

本文讲述 SELinux 保护安全的基本原理 首发公号&#xff1a;Rand_cs 安全检查顺序 不废话&#xff0c;直接先来看张图 当我们执行系统调用的时候&#xff0c;会首先对某些错误情况进行检查&#xff0c;如果失败通常会得到一些 error 信息&#xff0c;通过查看全局变量 errno …

Primavera Unifier 项目控制延伸:Phase Gate理论:2/3

阶段Gate的具体内容&#xff1a; 阶段0 根据公司需要和资源现状&#xff0c;决定开展哪些项目。在这个阶段&#xff0c;公司一般需要开展一些脑力风暴或者团队集思广益的活动以获得足够多的点子。一旦团队决定采用某个想法&#xff0c;必须从各个维度去完善它&#xff0c;并使…

软件测试/测试开发丨接口测试之Postman 安装与使用

Postman 安装 官网下载地址 www.postman.com/downloads Postman 使用 发送get请求 新建请求 填写请求方式&#xff1a;GET 填写请求 URL&#xff1a; ceshiren.com/httpbin.ceshiren.com/get 填写请求参数&#xff1a; para_key para_value 发送 POST 请求 请求方式&…

PHP与Angular详细对比 帮助你选择合适的项目技术

开发可有效扩展并提供诺克斯堡级安全性的Web应用程序和网站是每个开发人员的梦想。而使用这样的产品是每个用户的愿望。因此&#xff0c;为您的项目选择最合适和可靠的技术非常关键。 虽然PHP和Angular是完全不同的技术——PHP与JavaScript是一个更恰当的比较——但它们都广泛…

2024 React 后台系统 搭建学习看这一篇就够了(1)

年初&#xff0c;自己想写一篇关于 React 实战后台项目的 课程文章&#xff0c;也算是对自己 2023的前端学习做一个系统性总结&#xff0c;方便后续查阅&#xff0c;也方便自己浏览&#xff0c;还能增加自己的文笔 网上很多平台都不太稳定&#xff0c;所以用了阿里的语雀&…

【C++】命名空间、输入输出、缺省参数和函数重载详解

文章目录 前言命名空间命名空间的定义命名空间的使用 C输入输出缺省参数缺省参数定义缺省参数分类 函数重载函数重载的概念函数名修饰规则extern "C"的使用 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; C 是一门强大而灵活的编程语言…

EBU7140 Security and Authentication(二)非对称加密;授权

B2 非对称加密介绍 前面的传统加密算法都是对称加密。就是加密解密用一个密钥。非对称加密就是用不同的密钥&#xff0c;加密复杂度更高。 Diffie-Hellman 密钥交换法 一种密钥交换方法。 common 是公共基础颜色&#xff0c;secret 是各自私有颜色&#xff0c;公共颜色和自己…

Pillow图像处理(PIL.Image类的详细使用)

文章目录 Opencv、Matplotlib(plt)、Pillow(PIL)、Pytorch读取数据的通道顺序Python图像处理库&#xff08;PIL、Pillow、Scikit-image、Opencv&#xff09;Pillow 官方文档&#xff08;超详细&#xff0c;超推荐&#xff09;一、PIL库与Pillow库的区别二、Pillow库&#xff08…
最新文章