Qt项目中使用 FieldManager 实现多进程间的字段数据管理

使用场景:

串口收到数据,会将所需要的字段写入FieldManager模块中即更新数据。可能多个接收的报文中分散多个不同字段的结果,实现了解耦。

再一个定时进程中从FieldManager中调用数值,并将数值写入log中实现log的记录。


✅ 一、文件结构

复制代码
YourProject/
├── FieldManager.h      ✅ 字段管理器头文件(线程安全版)
├── main.cpp            ✅ 主函数
├── mainwindow.h/cpp    ✅ 主窗口类
├── mainwindow.ui       ✅ 界面设计(按钮 + 文本框)
├── YourProject.pro     ✅ Qt 项目文件

✅ 二、1. FieldManager.h

线程安全版本 FieldManager.h

cpp 复制代码
#ifndef FIELDMANAGER_H
#define FIELDMANAGER_H

#include <string>
#include <unordered_map>
#include <any>
#include <mutex>
#include <stdexcept>
#include <type_traits>

enum class FieldType {
    U8, S8, U16, S16, U32, S32, FLOAT, DOUBLE
};

class FieldManager {
public:
    static FieldManager& getInstance() {
        static FieldManager instance;
        return instance;
    }

    // 注册字段
    void ADD(const std::string& tag, FieldType type) {
        std::lock_guard<std::mutex> lock(mtx);
        if (fields.find(tag) != fields.end()) return;

        switch (type) {
            case FieldType::U8:     fields[tag] = uint8_t(0); break;
            case FieldType::S8:     fields[tag] = int8_t(0); break;
            case FieldType::U16:    fields[tag] = uint16_t(0); break;
            case FieldType::S16:    fields[tag] = int16_t(0); break;
            case FieldType::U32:    fields[tag] = uint32_t(0); break;
            case FieldType::S32:    fields[tag] = int32_t(0); break;
            case FieldType::FLOAT:  fields[tag] = float(0); break;
            case FieldType::DOUBLE: fields[tag] = double(0); break;
        }
    }

    // 设置字段值
    template<typename T>
    void SET(const std::string& tag, FieldType type, T value) {
        checkTypeMatch<T>(type);
        std::lock_guard<std::mutex> lock(mtx);
        if (fields.find(tag) == fields.end()) throw std::runtime_error("标签未注册");
        fields[tag] = value;
    }

    // 获取字段值
    template<typename T>
    T GET(const std::string& tag, FieldType type) {
        checkTypeMatch<T>(type);
        std::lock_guard<std::mutex> lock(mtx);
        if (fields.find(tag) == fields.end()) throw std::runtime_error("标签未注册");
        return std::any_cast<T>(fields[tag]);
    }

private:
    std::unordered_map<std::string, std::any> fields;
    std::mutex mtx; // 互斥锁保护字段读写

    FieldManager() {}
    FieldManager(const FieldManager&) = delete;
    FieldManager& operator=(const FieldManager&) = delete;

    // 编译期类型检查
    template<typename T>
    void checkTypeMatch(FieldType type) {
        bool match = false;
        switch (type) {
            case FieldType::U8:     match = std::is_same_v<T, uint8_t>; break;
            case FieldType::S8:     match = std::is_same_v<T, int8_t>; break;
            case FieldType::U16:    match = std::is_same_v<T, uint16_t>; break;
            case FieldType::S16:    match = std::is_same_v<T, int16_t>; break;
            case FieldType::U32:    match = std::is_same_v<T, uint32_t>; break;
            case FieldType::S32:    match = std::is_same_v<T, int32_t>; break;
            case FieldType::FLOAT:  match = std::is_same_v<T, float>; break;
            case FieldType::DOUBLE: match = std::is_same_v<T, double>; break;
        }
        if (!match) throw std::invalid_argument("类型与FieldType不匹配");
    }
};

#endif // FIELDMANAGER_H

✅ 示例测试(支持多线程)

cpp 复制代码
#include "FieldManager.h"
#include <thread>
#include <iostream>

void threadFunc() {
    auto& fm = FieldManager::getInstance();
    fm.SET<float>("电压", FieldType::FLOAT, 3.14f);
    std::cout << "线程中设置电压: " << fm.GET<float>("电压", FieldType::FLOAT) << std::endl;
}

int main() {
    auto& fm = FieldManager::getInstance();
    fm.ADD("电压", FieldType::FLOAT);

    std::thread t1(threadFunc);
    std::thread t2(threadFunc);

    t1.join();
    t2.join();

    std::cout << "主线程读取电压: " << fm.GET<float>("电压", FieldType::FLOAT) << std::endl;

    return 0;
}

✅ 输出示例

cpp 复制代码
线程中设置电压: 3.14
线程中设置电压: 3.14
主线程读取电压: 3.14

如何使用:

确保你已经在文件顶部添加:

cpp 复制代码
#include <any>  // ✅ 必需
#include <mutex>
#include <unordered_map>
#include <string>

并确保 Qt 项目启用了 C++17。

CONFIG += c++17


✅ 三、2. mainwindow.ui 设计界面

在 Qt Designer 中拖入以下控件:

控件类型 ObjectName 说明
QPushButton btnSet 设置字段按钮
QPushButton btnGet 获取字段按钮
QLineEdit lineEditValue 输入值
QLabel labelResult 显示读取结果

✅ 四、3. mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_btnSet_clicked();
    void on_btnGet_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

✅ 五、4. mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "FieldManager.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 注册一个字段 "电压",类型为 FLOAT
    FieldManager::getInstance().ADD("电压", FieldType::FLOAT);

    connect(ui->btnSet, &QPushButton::clicked, this, &MainWindow::on_btnSet_clicked);
    connect(ui->btnGet, &QPushButton::clicked, this, &MainWindow::on_btnGet_clicked);
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::on_btnSet_clicked() {
    bool ok;
    float value = ui->lineEditValue->text().toFloat(&ok);
    if (ok) {
        FieldManager::getInstance().SET<float>("电压", FieldType::FLOAT, value);
        ui->labelResult->setText("设置成功");
    } else {
        ui->labelResult->setText("请输入有效数字");
    }
}

void MainWindow::on_btnGet_clicked() {
    try {
        float v = FieldManager::getInstance().GET<float>("电压", FieldType::FLOAT);
        ui->labelResult->setText(QString("读取值: %1").arg(v));
    } catch (std::exception& e) {
        ui->labelResult->setText("读取失败: " + QString(e.what()));
    }
}

✅ 六、5. main.cpp

cpp 复制代码
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

✅ 七、6. YourProject.pro(开启 C++17)

pro 复制代码
QT += core gui widgets

greaterThan(QT_MAJOR_VERSION, 5): QT += widgets

TARGET = YourProject
TEMPLATE = app

CONFIG += c++17

SOURCES += main.cpp \
           mainwindow.cpp

HEADERS += mainwindow.h \
           FieldManager.h

FORMS += mainwindow.ui

✅ 八、编译运行效果

  • 输入一个数字点击【设置】 → 会将其存入 FieldManager"电压" 字段。
  • 点击【获取】 → 会显示之前设置的值。
相关推荐
神仙别闹7 小时前
基于 C++ 实现(控制台)学生成绩管理系统
开发语言·c++
伞伞悦读8 小时前
【第36期】Python 目录与路径详解:pathlib、文件遍历、创建、复制、移动和删除风险
开发语言·python
2601_9669496510 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
m0_7345717611 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
RAN114267600812 小时前
1.3第一个程序的介绍
开发语言·qt
blue_ice .13 小时前
Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测
开发语言·单片机·嵌入式硬件·fpga开发
远翔调光芯片^1382879887213 小时前
ECP5702能芯科技PD取电芯片在市场上的优势有哪些?
开发语言·人工智能·单片机·嵌入式硬件·智能家居
泡海椒14 小时前
规则引擎对比:JQuick-Java vs Drools 轻量场景选型对比
java·开发语言
泡泡鱼(敲代码中)14 小时前
Python 容器类型学习笔记:列表、元组、字典、集合
开发语言·笔记·python·pycharm
2501_9336707914 小时前
平台招商运营校招能力模型:数据分析、SQL与增长场景拆解
开发语言