QGC地面站手把手教你改——如何添加跟随面板显示关键参数


所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!

关于QGC地面站其它文章请点击这里:     QGC地面站


一. 要实现的目标

当飞机在地图上飞行时,实现飞机图标实时跟随一个参数小面板,让用户对关键信息一目了然。 此参数小面板设置为半透明,可实时跟随飞机图标移动,显示内容包括电池剩余百分比、电池电压、飞行模式、地速、空速、爬升速度、相对高度、飞行距离等关键参数。如下gif:

在这里插入图片描述

二. 代码分析与修改

1. 飞行地图文件的分析与修改

代码如下:(FlightDisplayViewMap.qml):

// Add the vehicles to the map  244行
MapItemView {
    
      											//标记1
    model: QGroundControl.multiVehicleManager.vehicles  //标记2
    delegate: VehicleMapItem {
    
     							//标记3
        vehicle:        		object
        coordinate:     		object.coordinate 		//标记4
        map:            		flightMap
		size:           		mainIsMap ? ScreenTools.defaultFontPixelHeight * 3 : ScreenTools.defaultFontPixelHeight
        //z:              QGroundControl.zOrderVehicles  //总修改1-1
    }
    z:              QGroundControl.zOrderTopMost         //总修改1-2
}

参考:QT Creator 帮助中搜 “MapItemView”,MapQuickItem

● 标记1:MapItemView是用来构成Map的一部分的。它数据主要是源自model(ListModel、RouteModel等)。和ListView 相似 ,也是mode-delegate模型。 仅仅不同于MapItemView的代理Delegate需要为地图控件,即位置设置为经纬度坐标。ListView的Delegate控件为桌面控件,位置设置为屏幕位置。 MapItemView类型只有在包含在Map中时才有意义,它不能独立存在。

● 标记2:model:提供数据给委托定义的mapItem(VehicleMapItem),由它提供的信息(飞行模式、地速、空速、爬升速度、相对高度、飞行距离)作为Map ItemView的输入,下面再具体讲解。记住model 仅支持 “QAbstractItemModel” 的基础模型。

显然 “QGroundControl.multiVehicleManager.vehicles” 是 QAbstractItemModel 类型的,如下:

// src\Vehicle\MultiVehicleManager.h:100
QmlObjectListModel* vehicles(void) {
    
     return &_vehicles; }

● 标记3:delegate:定义了模型中的每个项改如何显示。 要求 delegate 必须为组件,且包含一个map Item, “MapQuickItem”类型的居多。

● 标记4:coordinate:定位坐标。为什么能动态跟随,此为最关键的属性,它在C++ vehiclel 类中会实时更新。(NOTIFY修饰的属性,下文会讲到)

coordinate是“MapQuickItem”的一个属性。 此属性保存MapQuickItem的锚点坐标。在地图显示时,由anchorPoint指定的sourceItem上的点与此坐标保持会一致。

在此MapItemView中。object 对应的就是 vehicles ,委托了VehicleMapItem来实现,VehicleMapItem为MapQuickItem类型的。MapQuickItem的sourceItem指定了一个Item来如何显示。该Item就是9行3列的关键参数的显示信息。

● 修改1: 此文件中仅修改一处“z” 属性,是为了让面板在顶层显示。记得放在“MapItemView”的属性下,不然不会生效,这很关键

接下来让我再看看代理中的文件吧!

2. 代理文件中数据源

上文提到 model,由它提供的飞行模式、地速、空速、爬升速度、相对高度、飞行距离的。

flightMode、roll、groundSpeed都是在“VehicleMapItem”中定义的变量。 object.flightMode、object.roll.rawValue、 object.groundSpeed.rawValue来自于“vehicles”。那么再看下 C++中的Vehicle吧

● 修改2: 在文件头增加如下属性:

//总修改2: (object = vehicle = QGroundControl.multiVehicleManager.vehicles)
property string flightMode:           vehicle.flightMode;
property real   roll:                 vehicle.roll.rawValue;
property real   groundSpeed:          vehicle.groundSpeed.rawValue;
property real   airSpeed:             vehicle.airSpeed.rawValue;
property real   climbRate:            vehicle.climbRate.rawValue;
property real   altitudeRelative:     vehicle.altitudeRelative.rawValue;
property real   flightDistance:       vehicle.flightDistance.rawValue;
property real   distanceToHome:       object.distanceToHome.rawValue;
property real   batteryPercentRemain: object.battery.percentRemaining.value
property real   batteryVoltage:       object.battery.voltage.value;

object = vehicle = QGroundControl.multiVehicleManager.vehicles ,让我们在看看vehicle类…

● C++中的Vehicle类的分析。
要在QML实时显示,那么必须是“NOTIFY”修饰的信号,它给属性关联一个信号,当属性的值发生变化时就会触发该信号。比下flightMode属性,

  Q_PROPERTY(QString              flightMode              READ flightMode             WRITE setFlightMode             NOTIFY flightModeChanged)

C++和QML之间不懂如何交互的可以点击这里:Qt Quick Qml 之QML与C++ 混合编程学习

当我们在 C++中改变该参数值时,发射 flightModeChanged 信号, 来通知 qml 相关的属性有更改,进而实现相关的状态更改。没有“NOTIFY”修饰的,不会实时触发,也不会动态更新了。

但是是不是发现在Vehicle类中,一些关键的属性并没有使用NOTIFY ?

如下:

Fact* roll                              () {
    
     return &_rollFact; }
Fact* rollRate                          () {
    
     return &_rollRateFact; }
Fact* pitchRate                         () {
    
     return &_pitchRateFact; }
Fact* yawRate                           () {
    
     return &_yawRateFact; }
Fact* airSpeed                          () {
    
     return &_airSpeedFact; }
Fact* groundSpeed                       () {
    
     return &_groundSpeedFact; }
Fact* climbRate                         () {
    
     return &_climbRateFact; }

仔细分析Fact类:

class Fact : public QObject
{
    
    
    Q_OBJECT
...
    Q_PROPERTY(QString      shortDescription        READ shortDescription                                   CONSTANT)
    Q_PROPERTY(QString      units                   READ cookedUnits                                        CONSTANT)
    Q_PROPERTY(QVariant     value                   READ cookedValue            WRITE setCookedValue        NOTIFY valueChanged)
    Q_PROPERTY(QVariant     rawValue                READ rawValue               WRITE setRawValue           NOTIFY rawValueChanged)
}

发现“rawValue ”也用“NOTIFY”修饰了。所以问题就很简单了,直接去到 “rawValue” 就好

...
property string flightMode:           vehicle.flightMode;
property real   roll:                 vehicle.roll.rawValue;
property real   groundSpeed:          vehicle.groundSpeed.rawValue;
property real   airSpeed:             vehicle.airSpeed.rawValue;
property real   climbRate:            vehicle.climbRate.rawValue;
...

3. 代理文件中显示形式

● 修改3: 在MapQuickItem中的“ sourceItem: Item "中最后增加矩形框:

Rectangle {
    
    
    id:                         cchVehicleStatusView;
    anchors.bottom:             vehicleIcon.top;
    anchors.bottomMargin:  4
    anchors.horizontalCenter:   vehicleIcon.horizontalCenter;
    color:                      "#DDDDFF"
    radius:                     10
    width:                      buttonColumn.implicitWidth * 1.1
    height:                     buttonColumn.implicitHeight * 1.1
    opacity :                   0.8;
    border.color:               "black"
    border.width:               2

    Column {
    
    
        id:                 buttonColumn
        width:              statusNameRepeater.implicitWidth
        height:             statusNameRepeater.implicitHeight
        anchors.top:        parent.top
        anchors.topMargin:  6
        anchors.left:       parent.left
        anchors.leftMargin: 6
        spacing:            ScreenTools.defaultFontPixelHeight / 2

        Repeater {
    
    
            id:     statusNameRepeater
            model:  9
            property var statusNames:  [ "电池剩余百分比: ", "电池电压: ", qsTr("飞行模式:"), qsTr("地速: "), qsTr("空速: "), qsTr("爬升速度: "), qsTr("相对高度: "), qsTr("飞行距离: "),"到home点距离: "]
            property var statusValues: [batteryPercentRemain, batteryVoltage, flightMode, groundSpeed.toFixed(2), airSpeed.toFixed(2), climbRate.toFixed(2), altitudeRelative.toFixed(2), flightDistance.toFixed(2), distanceToHome.toFixed(2)]
            property var statusUnits: ["%", "v", "", "(m/s)", "(m/s)", "(m/s)", "(m)", "(m)", "(m)"]

            Row{
    
    
                id: _row
                QGCLabel {
    
    
                    color:                            "#424200"
                    horizontalAlignment:              Text.AlignHCenter
                    font.pointSize:                   ScreenTools.mediumFontPointSize * 1.0
                    text:                             statusNameRepeater.statusNames[index]
                    font.bold:                        true
                }
                QGCLabel {
    
    
                    color:                            "#336666"
                    horizontalAlignment:              Text.AlignHCenter
                    font.pointSize:                   ScreenTools.mediumFontPointSize *1.0
                    text:                             statusNameRepeater.statusValues[index] + statusNameRepeater.statusUnits[index]
                    font.bold:                        true
                }
            }
        }
    }
}

这个Column和Row的嵌套布局的详细解释,可以看我的 QT Quick QML 布局——定位置布局(Row、Column、Grid、Flow和Repeater) 总结。 这里不再介绍。

如下绿色框中:
在这里插入图片描述

有其他想法的,可以在飞行视图中,增加一个控件,来配置矩形框是否显示;还可以增加一个定时器让变化的数据高亮显示;有UI美工支持的还可以弄个炫酷的皮肤。为什么要这样呢?

没有别的原因,一切为狂拽酷炫,哈哈! 具体就不一一介绍啦,自己开动小脑袋瓜子哦~


关于QGC地面站其它文章请点击这里:     QGC地面站

猜你喜欢

转载自blog.csdn.net/qq_16504163/article/details/110779071
今日推荐