所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!
关于QGC地面站其它文章请点击这里: QGC地面站
当飞机在地图上飞行时,实现飞机图标实时跟随一个参数小面板,让用户对关键信息一目了然。 此参数小面板设置为半透明,可实时跟随飞机图标移动,显示内容包括电池剩余百分比、电池电压、飞行模式、地速、空速、爬升速度、相对高度、飞行距离等关键参数。如下gif:
代码如下:(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”的属性下,不然不会生效,这很关键
接下来让我再看看代理中的文件吧!
上文提到 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: 在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地面站