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

2024-01-01 23:28:08

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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
}

文章来源:https://blog.csdn.net/feixiaoxing/article/details/135328850
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。