【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. 实时更新
  • 定时器出发航向和目标高度的动态变化,模拟飞行状态。
相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00615 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术15 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript