当前位置: 首页 > news >正文

【QGC】深入解析 QGC 配置管理

引言

在软件开发中,配置管理是一项至关重要的任务,它能帮助我们灵活地管理应用程序的各种参数和设置。QGroundControl(QGC)作为一款强大的开源无人机地面站软件,其配置管理系统设计精巧,值得我们深入学习。本文将详细介绍 QGC 配置管理的核心技术,并结合代码示例进行讲解。

一、QGC 配置管理概述

QGC 的配置管理主要通过 SettingsGroup 类及其相关宏来实现。这些机制允许开发者将不同的设置分组管理,同时支持设置项的创建、访问和可见性控制。下面我们逐步分析其关键组成部分。

1. 头文件保护与依赖引入

SettingsGroup.h

#pragma once
#include "SettingsFact.h"

#pragma once 确保头文件只被编译一次,避免重复包含。SettingsFact.h 引入了处理设置项的相关类。

2. 宏定义设置组名称和 QSettings 组名

SettingsGroup.h

#define DEFINE_SETTING_NAME_GROUP() \static const char* name; \static const char* settingsGroup;

该宏用于在设置组类中声明静态成员变量 namesettingsGroup,分别表示设置组的名称和在 QSettings 中使用的组名。

3. 声明设置组类

SettingsGroup.h

#define DECLARE_SETTINGGROUP(NAME, GROUP) \const char* NAME ## Settings::name = #NAME; \const char* NAME ## Settings::settingsGroup = GROUP; \NAME ## Settings::NAME ## Settings(QObject* parent) \: SettingsGroup(name, settingsGroup, parent)

此宏声明了设置组类的静态成员变量 namesettingsGroup 的定义,并定义了设置组类的构造函数。

4. 声明设置项事实

SettingsGroup.h

#define DECLARE_SETTINGSFACT(CLASS, NAME) \const char* CLASS::NAME ## Name = #NAME; \Fact* CLASS::NAME() \{ \if (!_ ## NAME ## Fact) { \_ ## NAME ## Fact = _createSettingsFact(NAME ## Name); \} \return _ ## NAME ## Fact; \}

该宏声明了设置项事实的名称和访问函数,确保设置项事实对象只被创建一次。

5. 定义设置项事实

SettingsGroup.h

#define DEFINE_SETTINGFACT(NAME) \private: \SettingsFact* _ ## NAME ## Fact = nullptr; \public: \Q_PROPERTY(Fact* NAME READ NAME CONSTANT) \Fact* NAME(); \static const char* NAME ## Name;

此宏在设置组类中定义设置项事实的私有成员变量、Qt 属性和访问函数。

6. SettingsGroup 类实现

SettingsGroup.h

class SettingsGroup : public QObject
{Q_OBJECTpublic:SettingsGroup(const QString &name, const QString &settingsGroup, QObject* parent = nullptr);Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)virtual bool    visible             () { return _visible; }virtual void    setVisible          (bool vis) { _visible = vis; emit visibleChanged(); }signals:void            visibleChanged      ();protected:SettingsFact*   _createSettingsFact(const QString& factName);bool            _visible;QString         _name;QString         _settingsGroup;QMap<QString, FactMetaData*> _nameToMetaDataMap;private:static constexpr const char* kJsonFile = ":/json/%1.SettingsGroup.json";
};

SettingsGroup 类是配置管理的核心类,提供了设置组的创建、可见性控制等功能。

二、配置管理技术方案

1. 类继承与模块化设计

理论

类继承是面向对象编程的核心特性之一,子类可以继承父类的属性和方法,实现代码复用和功能扩展。模块化设计将系统划分为独立的模块,每个模块负责特定功能,提高代码的可维护性和可扩展性。

应用场景

在配置管理中,当多个配置类有共同的属性和方法时,可定义一个基类来封装这些通用功能,子类继承基类并添加各自特有的配置项和方法。

示例代码
// app_settings_example.h// 基类:SettingsGroup
class SettingsGroup {
public:SettingsGroup() = default;virtual ~SettingsGroup() = default;virtual void loadSettings() = 0;virtual void saveSettings() = 0;
};// 子类:AppSettings
class AppSettings : public SettingsGroup {
public:AppSettings() = default;~AppSettings() override = default;void loadSettings() override {// 实现加载应用设置的逻辑std::cout << "Loading app settings..." << std::endl;}void saveSettings() override {// 实现保存应用设置的逻辑std::cout << "Saving app settings..." << std::endl;}
};

2. 宏定义配置项

理论

宏定义是 C++ 预处理阶段的文本替换机制,通过定义宏可以简化代码编写,提高代码的可维护性和可读性。

应用场景

在配置管理中,当需要批量定义相似的配置项时,使用宏可以减少重复代码。

示例代码
// app_settings_example.h#include <iostream>
#include <string>// 定义宏
#define DEFINE_SETTINGFACT(name) \
private: \std::string name##Value; \
public: \void set##name(const std::string& value) { name##Value = value; } \std::string get##name() const { return name##Value; }class AppSettings {DEFINE_SETTINGFACT(offlineEditingFirmwareClass)DEFINE_SETTINGFACT(offlineEditingVehicleClass)
};

3. Qt 属性系统

理论

Qt 属性系统是 Qt 框架提供的一种机制,允许在类中定义属性,这些属性可以像普通成员变量一样使用,同时支持信号-槽机制和 QML 绑定。

应用场景

在 Qt 应用程序的配置管理中,使用属性系统可以方便地将配置项暴露给 QML 界面,实现界面与后端数据的同步。

示例代码
// app_settings_example.h#include <QObject>
#include <QString>class AppSettings : public QObject {Q_OBJECTQ_PROPERTY(QString missionSavePath READ missionSavePath WRITE setMissionSavePath NOTIFY missionSavePathChanged)public:explicit AppSettings(QObject* parent = nullptr) : QObject(parent) {}QString missionSavePath() const { return m_missionSavePath; }void setMissionSavePath(const QString& path) {if (m_missionSavePath != path) {m_missionSavePath = path;emit missionSavePathChanged();}}signals:void missionSavePathChanged();private:QString m_missionSavePath;
};

4. 信号与槽机制

理论

信号与槽是 Qt 框架的核心机制之一,用于对象间的通信。当信号被发射时,与之连接的槽函数会被自动调用。

应用场景

在配置管理中,当配置项发生变化时,通过发射信号通知其他对象更新状态。

示例代码
// app_settings_example.h#include <QObject>
#include <QString>class AppSettings : public QObject {Q_OBJECT
public:explicit AppSettings(QObject* parent = nullptr) : QObject(parent) {}void changeSetting() {// 模拟配置变化emit settingChanged();}signals:void settingChanged();
};class SettingListener : public QObject {Q_OBJECT
public:explicit SettingListener(QObject* parent = nullptr) : QObject(parent) {}public slots:void onSettingChanged() {std::cout << "Setting has been changed." << std::endl;}
};

5. 常量定义

理论

常量定义用于定义程序中不会改变的值,使用 constconstexpr 关键字保证值的不可修改性,提高代码的安全性和可读性。

应用场景

在配置管理中,文件扩展名、子目录名称等固定值通常使用常量定义。

示例代码
// app_settings_example.h#include <iostream>class AppSettings {
public:static constexpr const char* parameterFileExtension = "params";static constexpr const char* parameterDirectory = "Parameters";
};

6. 工具函数

理论

工具函数是为了实现特定功能而封装的独立函数,提高代码的复用性和可维护性。

应用场景

在配置管理中,类型转换、状态标记等操作可以封装成工具函数。

示例代码
// app_settings_example.h#include <QVariant>
#include <QList>class AppSettings {
public:static QList<int> firstRunPromptsIdsVariantToList(const QVariant& firstRunPromptIds) {QList<int> ids;if (firstRunPromptIds.canConvert<QList<int>>()) {ids = firstRunPromptIds.value<QList<int>>();}return ids;}static QVariant firstRunPromptsIdsListToVariant(const QList<int>& rgIds) {return QVariant::fromValue(rgIds);}
};

7. 友元类设计

理论

友元类是一种特殊的类,它可以访问另一个类的私有成员,打破了类的封装性,增强了类之间的协作能力。

应用场景

在配置管理中,当某个类需要频繁访问另一个类的私有成员时,可以将其声明为友元类。

示例代码
// app_settings_example.hclass AppSettings {
private:int privateSetting = 0;friend class QGCApplication;
};class QGCApplication {
public:void accessPrivateSetting(AppSettings& settings) {// 可以访问 AppSettings 的私有成员settings.privateSetting = 10;}
};

完整示例整合

// main.cpp#include <iostream>
#include <QObject>
#include <QString>
#include <QVariant>
#include <QList>// 基类:SettingsGroup
class SettingsGroup {
public:SettingsGroup() = default;virtual ~SettingsGroup() = default;virtual void loadSettings() = 0;virtual void saveSettings() = 0;
};// 定义宏
#define DEFINE_SETTINGFACT(name) \
private: \std::string name##Value; \
public: \void set##name(const std::string& value) { name##Value = value; } \std::string get##name() const { return name##Value; }// 子类:AppSettings
class AppSettings : public SettingsGroup, public QObject {Q_OBJECTQ_PROPERTY(QString missionSavePath READ missionSavePath WRITE setMissionSavePath NOTIFY missionSavePathChanged)public:explicit AppSettings(QObject* parent = nullptr) : QObject(parent) {}void loadSettings() override {std::cout << "Loading app settings..." << std::endl;}void saveSettings() override {std::cout << "Saving app settings..." << std::endl;}DEFINE_SETTINGFACT(offlineEditingFirmwareClass)DEFINE_SETTINGFACT(offlineEditingVehicleClass)QString missionSavePath() const { return m_missionSavePath; }void setMissionSavePath(const QString& path) {if (m_missionSavePath != path) {m_missionSavePath = path;emit missionSavePathChanged();}}void changeSetting() {emit settingChanged();}static QList<int> firstRunPromptsIdsVariantToList(const QVariant& firstRunPromptIds) {QList<int> ids;if (firstRunPromptIds.canConvert<QList<int>>()) {ids = firstRunPromptIds.value<QList<int>>();}return ids;}static QVariant firstRunPromptsIdsListToVariant(const QList<int>& rgIds) {return QVariant::fromValue(rgIds);}static constexpr const char* parameterFileExtension = "params";static constexpr const char* parameterDirectory = "Parameters";private:int privateSetting = 0;QString m_missionSavePath;signals:void missionSavePathChanged();void settingChanged();friend class QGCApplication;
};class SettingListener : public QObject {Q_OBJECT
public:explicit SettingListener(QObject* parent = nullptr) : QObject(parent) {}public slots:void onSettingChanged() {std::cout << "Setting has been changed." << std::endl;}
};class QGCApplication {
public:void accessPrivateSetting(AppSettings& settings) {settings.privateSetting = 10;}
};#include "main.moc"int main() {AppSettings appSettings;SettingListener listener;QObject::connect(&appSettings, &AppSettings::settingChanged, &listener, &SettingListener::onSettingChanged);appSettings.loadSettings();appSettings.setofflineEditingFirmwareClass("FirmwareClass");std::cout << "Offline Editing Firmware Class: " << appSettings.getofflineEditingFirmwareClass() << std::endl;appSettings.setMissionSavePath("NewMissionSavePath");appSettings.changeSetting();appSettings.saveSettings();QList<int> ids = {1, 2, 3};QVariant variantIds = AppSettings::firstRunPromptsIdsListToVariant(ids);QList<int> convertedIds = AppSettings::firstRunPromptsIdsVariantToList(variantIds);for (int id : convertedIds) {std::cout << "ID: " << id << std::endl;}QGCApplication qgcApp;qgcApp.accessPrivateSetting(appSettings);return 0;
}

总结

通过上述分析和示例,我们了解了 QGC 配置管理的核心机制,包括宏定义的使用、SettingsGroup 类的实现以及如何创建和使用设置组与设置项。这种设计使得 QGC 的配置管理具有良好的可扩展性和可维护性,开发者可以方便地添加新的设置组和设置项。希望本文能帮助你更好地理解 QGC 配置管理,并在自己的项目中应用相关技术。

http://www.dtcms.com/a/275768.html

相关文章:

  • AAAI-2025 | 西交模拟人类空间推理策略的具身导航!REGNav:房间专家引导的图像目标导航
  • Linux文件的权限
  • Kotlin基础学习记录
  • 【MediaSoup】MS_DUMP打印转换为PLOGI的形式
  • Python-难点-uinttest
  • 网络资源模板--基于Android Studio 实现的记事本App
  • 通过卫星图像追踪城市扩张
  • Windows npx n8n 方式运行n8n密码忘了重置密码
  • IDEA中一个服务创建多个实例
  • PyQt5布局管理(QBoxLayout(框布局))
  • 企业商业秘密保卫战:经营信息类案件维权全攻略
  • WildCard野卡已跑路(包含gpt plus升级方案)
  • C++结构体嵌套
  • Datawhale AI夏令营 MCP初体验——简历小助手
  • DeepSeek-Qwen蒸馏模型解析
  • 苍穹外卖-day06
  • 自助空间系统迭代历程|自助门店运营系统全新升级
  • AI炼丹日志-30-新发布【1T 万亿】参数量大模型!Kimi‑K2开源大模型解读与实践
  • 电子电气架构 --- ECU存储与计算资源冗余设计规范
  • 实习内容总结
  • 笔记/了解未来:财务建模与预测
  • 系统思考助力转型
  • Git企业级开发(最终篇)
  • 【PTA数据结构 | C语言版】车厢重排
  • JDBC 事务控制详解:保障数据安全的完整指南
  • ​Windows API 介绍及核心函数分类表
  • 使用langgraph 构建RAG 智能问答代理
  • Kotlin文件
  • 【GESP】C++ 2025年6月一级考试-客观题真题解析
  • 小学家长和老师最喜欢的出题神器!