【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. 实时更新
  • 定时器出发航向和目标高度的动态变化,模拟飞行状态。
相关推荐
CT随8 分钟前
Redis内存碎片详解
java·开发语言
anlog17 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐30 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀38 分钟前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun39 分钟前
C语言初阶习题【9】数9的个数
c语言·开发语言
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区1 小时前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光1 小时前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求1 小时前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生1 小时前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt