【QT】实现电子飞行显示器(改进版)

在简易版中我们只绘制了简单的文本和数值。改进版我们将速度和高度设计成滚动的刻度,并显示刻度值。添加航迹标和高度选择指针。

1. 速度和高度滚动刻度实现

实现步骤

  1. 定义滚动刻度
  • 使用 QPainter 绘制一组分布均匀的刻度线和对应的数值。
  • 刻度值随着飞行参数(速度、高度)的变化而动态滚动。
  1. 绘制指示框
  • 在固定位置绘制一个窗口,作为指示器。
  • 通过移动刻度,实现滚动效果。
  1. 实时更新数值
  • 实现信号槽机制或定时器(QTimer)动态更新速度和高度,并重新绘制滚动效果。

完整代码示例

cpp 复制代码
#include <QWidget>
#include <QPainter>
#include <QTimer>

public PFDWidget : public QWidget {
	Q_OBJECT
public:
	explicit PFDWidget(QWidget *parent = nullptr)
		: QWidget(parent), airspeed(120), altitude(10000) {
		// 定时器更新数据
		QTimer *timer = new QTimer(this);
		connect(timer, &QTimer::timeout, this, &PFDWidget::updateData);
		timer->start(100);		// 每 100ms 更新一次
	}

protected:
	void paintEvent(QPaintEvent *event) override {
		QPainter painter(this);
		painter.setRenderHint(QPainter::Antialiasing);

		// 设置背景
		painter.fillRect(rect(), Qt::black);

		// 绘制速度滚动刻度
		drawAirspeedScale(painter);
	}

private:
	double airspeed;
	double altitude;

	void drawAirspeedScale(QPainter &painter) {
		int centerY = height() / 2;
		int scaleWidth = 60;

		// 保存状态
		painter.save();

		// 设置绘图区域
		QRect airspeedRect(10, 10, scaleWidth, height()-20);
		painter.setClipRect(airspeedRect);

		// 绘制背景框
		painter.setPen(Qt::NoPen);
		painter.setBrush(Qt::darkGray);
		painter.drawRect(airspeedRect);

		// 绘制刻度
		painter.setPen(Qt::white);
		int step = 10;
		int range = 5;
		int startValue = static_cast<int>(airspeed/step) *step;

		for(int i=-range; i<=range; ++i) {
			int value = startValue + i * step;
			int y = centerY + (i * 30) - static_cast<int>((airspeed - startValue) * 3);

			if(y >= 10 && y <= height() - 10) {
				painter.drawText(10, y, scaleWidth-20, 20, Qt::AlignRight, QString::number(value));
				painter.drawLine(scaleWidth-20, y, scaleWidth-5, y);
			}
		}

		// 绘制固定指示框
		painter.setPen(Qt::yellow);
		painter.drawRect(5, centerY - 15, scaleWidth, 30);

		// 显示当前数值
		painter.drawText(5, centerY-15, scaleWidth, 30, Qt::AlignCenter, QString::number(static_cast<int>(airspeed)));

		// 恢复状态
		painter.restore();
	}

	void drawAltitudeScale(QPainter &painter) {
		int centerY = height() / 2;
		int scaleWidth = 60;

		// 保存状态
		painter.save();
	
		// 设置绘图区域
		QRect altitudeRect(width() - scaleWidth - 10, 10, scaleWidth, height()-20);
		painter.setClipRect(altitudeRect);

		// 绘制背景框
		painter.setPen(Qt::NoPen);
		painter.setBrush(Qt::darkGray);
		painter.drawRect(altitudeRect);

		// 绘制刻度
		painter.setPen(Qt::white);
		int step = 100;
		int range = 5;
		int startValue = static_cast<int>(altitude/step)*step;

		for(int i=-range; i<=range; ++i) {
			int value = startValue + i * step;
			int y = centerY + (i*30) - static_cast<int>((altitude-startValue)*0.3);

			if(y >= 10 && y <= height()-10) {
				painter.drawText(width() - scaleWidth, y, scaleWidth - 20, Qt::AlignLeft, QString::number(value));
				painter.drawLine(width() - scaleWidth, y, width()-scaleWidth+15, y);
			}
		}

		// 绘制固定指示框
		painter.setPen(Qt::yellow);
		painter.drawRect(width()-scaleWidth-5, centerY-15, scaleWidth, 30);

		// 显示当前数值
		painter.drawText(width()-scaleWidth-5, centerY-15, scaleWidth, 30, Qt::AlignCenter, QString::number(static_cast<int>(altitude)));

		// 恢复状态
		painter.restore();
	}

private slots:
	void updateData() {
		// 模拟数据变化
		airspeed += 0.5;
		altitude += 2.0;

		// 循环更新显示
		if(airspeed > 200)
			airspeed = 100;
		if(altitude > 11000)
			altitude = 10000;
	
		update();
	}
};

运行效果

  1. 滚动刻度
  • 中间为当前值,刻度在窗口内上下滚动。
  • 刻度会根据速度和高度动态更新,滚动效果流畅。
  1. 固定指示框
  • 在中间绘制一个固定窗口,显示精确的当前值。
  1. 动态更新
  • 使用定时器每 100ms 更新速度和高度,实现实时变化。

2. 添加航迹标和高度选择指针

这里的航迹标和高度选择指针以简单方式呈现,不涉及真实运行环境。
功能说明

  1. 航迹标
  • 一个三角形符号,显示当前航迹角。
  • 通常绘制带速度滚动刻度旁边。
  1. 高度选择指针
  • 一个标记线或箭头,用于显示目标高度。
  • 在高度滚动刻度上绘制。

修改后的代码

cpp 复制代码
#include <QWidget>
#include <QPainter>
#include <QTimer>

public PFDWidget : public QWidget {
	Q_OBJECT
public:
	explicit PFDWidget(QWidget *parent = nullptr)
		: QWidget(parent), airspeed(120), altitude(10000), heading(45), targetAltitude(10500) {
		// 定时器更新数据
		QTimer *timer = new QTimer(this);
		connect(timer, &QTimer::timeout, this, &PFDWidget::updateData);
		timer->start(100);		// 每 100ms 更新一次
	}

protected:
	void paintEvent(QPaintEvent *event) override {
		QPainter painter(this);
		painter.setRenderHint(QPainter::Antialiasing);

		// 设置背景
		painter.fillRect(rect(), Qt::black);

		// 绘制速度滚动刻度
		drawAirspeedScale(painter);
		
		// 绘制航迹标
		drawHeadingMarker(painter);

		// 绘制目标高度指针
		drawTargetAltitudePointer(painter);
	}

private:
	double airspeed;
	double altitude;
	double heading;
	double targetAltitude;

	void drawAirspeedScale(QPainter &painter) {
		int centerY = height() / 2;
		int scaleWidth = 60;

		// 保存状态
		painter.save();

		// 设置绘图区域
		QRect airspeedRect(10, 10, scaleWidth, height()-20);
		painter.setClipRect(airspeedRect);

		// 绘制背景框
		painter.setPen(Qt::NoPen);
		painter.setBrush(Qt::darkGray);
		painter.drawRect(airspeedRect);

		// 绘制刻度
		painter.setPen(Qt::white);
		int step = 10;
		int range = 5;
		int startValue = static_cast<int>(airspeed/step) *step;

		for(int i=-range; i<=range; ++i) {
			int value = startValue + i * step;
			int y = centerY + (i * 30) - static_cast<int>((airspeed - startValue) * 3);

			if(y >= 10 && y <= height() - 10) {
				painter.drawText(10, y, scaleWidth-20, 20, Qt::AlignRight, QString::number(value));
				painter.drawLine(scaleWidth-20, y, scaleWidth-5, y);
			}
		}

		// 绘制固定指示框
		painter.setPen(Qt::yellow);
		painter.drawRect(5, centerY - 15, scaleWidth, 30);

		// 显示当前数值
		painter.drawText(5, centerY-15, scaleWidth, 30, Qt::AlignCenter, QString::number(static_cast<int>(airspeed)));

		// 恢复状态
		painter.restore();
	}

	void drawAltitudeScale(QPainter &painter) {
		int centerY = height() / 2;
		int scaleWidth = 60;

		// 保存状态
		painter.save();
	
		// 设置绘图区域
		QRect altitudeRect(width() - scaleWidth - 10, 10, scaleWidth, height()-20);
		painter.setClipRect(altitudeRect);

		// 绘制背景框
		painter.setPen(Qt::NoPen);
		painter.setBrush(Qt::darkGray);
		painter.drawRect(altitudeRect);

		// 绘制刻度
		painter.setPen(Qt::white);
		int step = 100;
		int range = 5;
		int startValue = static_cast<int>(altitude/step)*step;

		for(int i=-range; i<=range; ++i) {
			int value = startValue + i * step;
			int y = centerY + (i*30) - static_cast<int>((altitude-startValue)*0.3);

			if(y >= 10 && y <= height()-10) {
				painter.drawText(width() - scaleWidth, y, scaleWidth - 20, Qt::AlignLeft, QString::number(value));
				painter.drawLine(width() - scaleWidth, y, width()-scaleWidth+15, y);
			}
		}

		// 绘制固定指示框
		painter.setPen(Qt::yellow);
		painter.drawRect(width()-scaleWidth-5, centerY-15, scaleWidth, 30);

		// 显示当前数值
		painter.drawText(width()-scaleWidth-5, centerY-15, scaleWidth, 30, Qt::AlignCenter, QString::number(static_cast<int>(altitude)));

		// 恢复状态
		painter.restore();
	}

	void drawHeadingMarker(QPainter &painter) {
		int markerX = width()/2 - 30;

		QPolygon markker;
		makrker << QPoint(markerX, height()/2-10)
				<< QPoint(markerX-10, height()/2)
				<< QPoint(markerX, height()/2+10);
		
		painter.setBrush(Qt::yellow);
		painter.setPen(Qt::yellow);
		painter.drawPolygon(marker);

		// 显示航向角度值
		painter.setPen(Qt::white);
		painter.drawText(markerX-50, height()/2-10, 40, 20, Qt::AlignRight, QString::number(static_cast<int>(heading));
	}
	
	void MainWindow::drawTargetAltitudePointer(QPainter &painter)
	{
	    int scaleWidth = 60;
	    int centerY = height() / 2;
	
	    int step = 100;
	    int range = centerY - 30;
	    int deltaY = static_cast<int>((targetAltitude - altitude)*0.3);
	    int pointerY = centerY - deltaY;
	
	    if(pointerY >= 10 && pointerY <= height()-10) {
	        painter.setPen(Qt::cyan);
	        painter.drawLine(width()-scaleWidth-20, pointerY, width()-10, pointerY);
	
	        painter.setPen(Qt::cyan);
	        painter.drawText(width()-scaleWidth-80, pointerY-10, 60, 20, Qt::AlignRight, QString::number(static_cast<int>(targetAltitude)));
	    }
	}

private slots:
	void updateData() {
		// 模拟数据变化
		airspeed += 0.5;
		altitude += 2.0;

		heading += 1;
		if(heading >= 360) heading -= 360;

		targetAltitude = 10500 + qrand() % 500;

		// 循环更新显示
		if(airspeed > 200)
			airspeed = 100;
		if(altitude > 11000)
			altitude = 10000;
	
		update();
	}
};

代码解析

  1. 航迹标
  • 使用 QPolygon 绘制一个黄色三角形。
  • 显示在速度刻度旁,附带显示当前航向角。
  1. 高度选择指针
  • 根据目标高度和当前高度的差异,计算指针的位置。
  • 使用一条水平线和数值标注指示目标高度。
  1. 实时更新
  • 定时器出发航向和目标高度的动态变化,模拟飞行状态。
相关推荐
荒川之神1 小时前
拉链表概念与基本设计
java·开发语言·数据库
chushiyunen1 小时前
python中的@Property和@Setter
java·开发语言·python
小樱花的樱花1 小时前
C++ new和delete用法详解
linux·开发语言·c++
froginwe111 小时前
C 运算符
开发语言
fengfuyao9852 小时前
低数据极限下模型预测控制的非线性动力学的稀疏识别 MATLAB实现
开发语言·matlab
摇滚侠2 小时前
搭建前端开发环境 安装 nodejs 设置淘宝镜像 最简化最标准版本 不使用 NVM NVM 高版本无法安装低版本 nodejs
java·开发语言·node.js
t198751282 小时前
MATLAB十字路口车辆通行情况模拟系统
开发语言·matlab
yyk的萌2 小时前
AI 应用开发工程师基础学习计划
开发语言·python·学习·ai·lua
Amumu121383 小时前
Js:正则表达式(一)
开发语言·javascript·正则表达式
无人机9014 小时前
Delphi 网络编程实战:TIdTCPClient 与 TIdTCPServer 类深度解析
java·开发语言·前端