卫星信息

本示例展示了使用 Sky View、TableView 或 RSSI View 和用户当前位置查看可用的卫星。它使用 Qt 位置定位和 Qt Quick 实现。

此示例演示了 Qt 位置定位 QML API 的用法。

示例还展示了如何使用自定义 C++ 模型以及来自 QML 的自定义代理模型。

UI 概览

示例在三个不同的标签中展示了卫星信息。数据来源于 SatelliteSource::satellitesInView 和 SatelliteSource::satellitesInUse 属性。

天空视图 标签展示了使用 Azimuth 和 Elevation 属性的相对卫星位置。点击单个卫星对象将弹出一个包含卫星标识符、其方位角和仰角的弹出窗口。

表格视图 标签展示了所有检测到的卫星的列表,并允许对列表进行排序和筛选。

RSSI 视图 标签展示了所视卫星的信号强度,使用 signalStrength 属性。条形图下方数字代表单个卫星标识符。

天空视图RSSI 视图 标签也显示了当前纬度和经度。它们使用 PositionSource::position 属性来提取此信息。

标签页上方的 状态 块显示了当前模式或最后错误。

设置 菜单允许切换应用程序颜色模式并显示帮助信息。

应用程序以三种不同的模式运行

应用程序模式描述
运行中应用程序不断查询系统以获取卫星和位置更新。当有新数据可用时,它将进行显示。
停止应用程序停止更新卫星和位置信息。
单次应用程序发送单次卫星和位置更新请求。

如果平台不提供卫星或位置信息,应用程序将自动切换到模拟模式。模拟模式使用预记录的 NMEA 数据的 NMEA 插件。

注意: Apple 不提供任何获取卫星信息的 API,因此,在 macOS 和 iOS 上,卫星信息始终来自预记录的数据。这些 API 限制不会影响定位信息,因此可以正确显示当前位置。

运行示例

Qt Creator中运行示例,打开欢迎模式并从示例中选择示例。更多详细信息,请访问构建和运行示例

获取当前位置

当前位置是从PositionSource QML对象中检索的。使用onPositionChanged处理程序接收位置更新。从coordinate属性中提取纬度和经度的字符串表示形式。

PositionSource {
    id: positionSource
    name: root.simulation ? "nmea" : ""
    onPositionChanged: {
        let posData = position.coordinate.toString().split(", ")
        positionBox.latitudeString = posData[0]
        positionBox.longitudeString = posData[1]
    }
}

获取卫星信息

与位置类似,当前卫星信息是从SatelliteSource QML对象中检索的。使用onSatellitesInViewChangedonSatellitesInUseChanged处理程序分别获取可视卫星和使用的卫星。在此示例中,数据随后被转发到C++模型,该模型随后用于所有视图中。

SatelliteSource {
    id: satelliteSource
    name: root.simulation ? "nmea" : ""
    onSatellitesInViewChanged: root.satellitesModel.updateSatellitesInView(satellitesInView)
    onSatellitesInUseChanged: root.satellitesModel.updateSatellitesInUse(satellitesInUse)
}

注意:示例展示了QML定位API以及C++模型与QML的集成。这正是为什么卫星信息首先在QML中检索,然后转发到C++,然后再次返回到QML以在模型中使用。在实际应用中,如果应用程序应该使用复杂的C++模型,请考虑直接从C++使用QGeoSatelliteInfoSource类。

使用自定义C++模型

示例使用了两个自定义模型 - SatelliteModelSortFilterModel

卫星模型

SatelliteModel类从QAbstractListModel派生,并重新实现rowCount()、data()和roleNames()方法来表示卫星信息。使用QAbstractListModel作为基类可以轻松地将模型与QMLListViewRepeater类型一起使用。仅使用自定义的size属性来动态计算信号强度视图选项卡的标签栏宽度。

class SatelliteModel : public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(int size READ rowCount NOTIFY sizeChanged)
    QML_ELEMENT
public:
    explicit SatelliteModel(QObject *parent = nullptr);

    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QHash<int, QByteArray> roleNames() const override;

public slots:
    void updateSatellitesInView(const QList<QGeoSatelliteInfo> &inView);
    void updateSatellitesInUse(const QList<QGeoSatelliteInfo> &inUse);

signals:
    void sizeChanged();
};

使用roleNames()方法将模型的角色映射到属性名,可以从QML访问模型数据。例如,id名称用于提取卫星标识符,而rssi名称用于获取信号强度。

QHash<int, QByteArray> SatelliteModel::roleNames() const
{
    return {
        {Roles::IdRole, "id"},
        {Roles::RssiRole, "rssi"},
        {Roles::AzimuthRole, "azimuth"},
        {Roles::ElevationRole, "elevation"},
        {Roles::SystemRole, "system"},
        {Roles::SystemIdRole, "systemId"},
        {Roles::InUseRole, "inUse"},
        {Roles::VisibleNameRole, "name"}
    };
}

QML侧,我们可以使用这些名称来获取实际值。例如,信号强度视图实现使用rssiinUseid角色名称以绘制表示单个卫星的条形图。

Repeater {
    id: repeater
    model: root.satellitesModel
    delegate: Rectangle {
        required property var modelData
        height: rect.height
        width: view.singleWidth
        color: "transparent"
        SemiRoundedRectangle {
            anchors.bottom: satId.top
            width: parent.width
            height: (parent.height - satId.height)
                    * Math.min(parent.modelData.rssi, rect.maxVisibleLevel)
                    / rect.maxVisibleLevel
            color: parent.modelData.inUse ? root.inUseColor : root.inViewColor
        }
        Text {
            id: satId
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottom: parent.bottom
            text: parent.modelData.id
            color: Theme.textSecondaryColor
            font.pixelSize: Theme.smallFontSize
            font.weight: Theme.fontLightWeight
        }
    }
}
代理模型

SortFilterModel类用于在表视图选项卡中提供卫星对象的自定义排序和过滤。

模型从QSortFilterProxyModel派生,并重新实现了filterAcceptsRow()和lessThan()方法以提供过滤和排序。该模型还公开了几个slots以调整过滤和排序行为。

class SortFilterModel : public QSortFilterProxyModel
{
    Q_OBJECT
    QML_ELEMENT
public:
    explicit SortFilterModel(QObject *parent = nullptr);

public slots:
    void updateFilterString(const QString &str);
    void updateShowInView(bool show);
    void updateShowInUse(bool show);
    void updateSelectedSystems(int id, bool show);
    void updateSortRoles(int role, bool use);

protected:
    bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
};

这些槽位既可以从 C++QML 调用。例如,卫星标识符 委托使用 updateSelectedSystems() 槽来显示或隐藏属于特定卫星系统的卫星信息。同样,卫星状态 委托使用 updateShowInView()updateShowInUse() 槽来过滤具有特定状态的卫星。

Repeater {
    model: root.satelliteSystemModel
    delegate: CheckElement {
        required property var modelData
        text: modelData.name
        Layout.alignment: Qt.AlignRight
        onCheckedChanged: {
            root.sortFilterModel.updateSelectedSystems(modelData.id, checked)
        }
    }
}
    ...
CheckElement {
    text: qsTr("In View")
    Layout.alignment: Qt.AlignRight
    onCheckedChanged: root.sortFilterModel.updateShowInView(checked)
}
CheckElement {
    text: qsTr("In Use")
    Layout.alignment: Qt.AlignRight
    onCheckedChanged: root.sortFilterModel.updateShowInUse(checked)
}

QML 模块注册

CMake 构建

对于基于 CMake 的构建,我们需要将以下内容添加到 CMakeLists.txt

qt_add_qml_module(satelliteinfo
    URI SatelliteInformation
    VERSION 1.0
    SOURCES
        roles.h
        satellitemodel.cpp satellitemodel.h
        sortfiltermodel.cpp sortfiltermodel.h
    QML_FILES
        ApplicationScreen.qml
        Button.qml
        Header.qml
        HelpPopup.qml
        LegendBox.qml
        Main.qml
        RssiView.qml
        PageButton.qml
        PermissionsScreen.qml
        PositionBox.qml
        SatelliteView.qml
        SettingsView.qml
        SkyView.qml
        Theme.qml
        ViewSwitch.qml
    RESOURCES
        icons/checkbox.svg
        icons/checkbox_blank.svg
        icons/darkmode.svg
        icons/filter.svg
        icons/help.svg
        icons/lightmode.svg
        icons/place.svg
        icons/qtlogo_green.png
        icons/qtlogo_white.png
        icons/rssiview.svg
        icons/satellite_small.png
        icons/satellite1.png
        icons/satellite2.png
        icons/search.svg
        icons/settings.svg
        icons/skyview.svg
        icons/sort.svg
        icons/tableview.svg
)
qmake 构建

对于 qmake 构建,我们需要按照以下方式修改位于项目的 satelliteinfo.pro 文件

CONFIG += qmltypes
QML_IMPORT_NAME = SatelliteInformation
QML_IMPORT_MAJOR_VERSION = 1

qml_resources.files = \
    qmldir \
    ApplicationScreen.qml \
    Button.qml \
    Header.qml \
    HelpPopup.qml \
    LegendBox.qml \
    Main.qml \
    RssiView.qml \
    PageButton.qml \
    PermissionsScreen.qml \
    PositionBox.qml \
    SatelliteView.qml \
    SettingsView.qml \
    SkyView.qml \
    Theme.qml \
    ViewSwitch.qml

qml_resources.prefix = /qt/qml/SatelliteInformation

RESOURCES += qml_resources

icon_resources.files = \
    icons/checkbox.svg \
    icons/checkbox_blank.svg \
    icons/darkmode.svg \
    icons/filter.svg \
    icons/help.svg \
    icons/lightmode.svg \
    icons/place.svg \
    icons/qtlogo_green.png \
    icons/qtlogo_white.png \
    icons/rssiview.svg \
    icons/satellite_small.png \
    icons/satellite1.png \
    icons/satellite2.png \
    icons/search.svg \
    icons/settings.svg \
    icons/skyview.svg \
    icons/sort.svg \
    icons/tableview.svg

icon_resources.prefix = /qt/qml/SatelliteInformation

RESOURCES += icon_resources

示例项目 @ code.qt.io

© 2024 Qt 公司有限公司。此处包含的文档贡献属于各自的版权所有者。此处提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证版本 1.3 的条款提供的。Qt 以及相应的标志是芬兰及/或其他国家 Qt 公司的商标。所有其他商标均为其各自所有者的财产。