【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. 实时更新
  • 定时器出发航向和目标高度的动态变化,模拟飞行状态。
相关推荐
练小杰3 分钟前
Linux系统 C/C++编程基础——基于Qt的图形用户界面编程
linux·c语言·c++·经验分享·qt·学习·编辑器
勤又氪猿4 分钟前
【问题】Qt c++ 界面 lineEdit、comboBox、tableWidget.... SIGSEGV错误
开发语言·c++·qt
Ciderw16 分钟前
Go中的三种锁
开发语言·c++·后端·golang·互斥锁·
查理零世18 分钟前
【算法】经典博弈论问题——巴什博弈 python
开发语言·python·算法
jk_1011 小时前
MATLAB中insertAfter函数用法
开发语言·matlab
啥也学不会a1 小时前
PLC通信
开发语言·网络·网络协议·c#
C++小厨神1 小时前
C#语言的学习路线
开发语言·后端·golang
心之语歌2 小时前
LiteFlow Spring boot使用方式
java·开发语言
人才程序员2 小时前
【C++拓展】vs2022使用SQlite3
c语言·开发语言·数据库·c++·qt·ui·sqlite
梁雨珈3 小时前
PL/SQL语言的图形用户界面
开发语言·后端·golang