首页 > 数据库 >C++ Qt开发:Charts与数据库组件联动

C++ Qt开发:Charts与数据库组件联动

时间:2024-01-06 18:05:35浏览次数:35  
标签:Qt 数据库 Charts C++ 查询 ui time 组件 query

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍Charts组件与QSql数据库组件的常用方法及灵活运用。

在之前的文章中详细介绍了关于QCharts绘图组件的使用方式,本章将继续延续这个知识点,通过使用QSql数据库模块动态的读取某一个时间节点上的数据,当用户点击查询数据时则动态的输出该事件节点的所有数据,并将数据绘制到图形组件内,实现动态查询图形的功能。

首先我们需要生成一些测试数据,在文章课件中有一个InitDatabase案例,该案例中通过QSql组件动态创建一个Times表,该表中有三个字段分别记录了主机IP地址、时间、以及数据,并动态的想表中插入一些随机测试数据,读者可运行这段程序并等待十分钟以上,此时数据库database.sqlite3中将会出现如下所示的数据集;

再来看下主窗体是如何设计的,左侧使用一个ComboBox下拉选择框,右侧使用两个可自由调节的Date/TimeEdit组件,最底部则是一个graphicsView绘图组件,如下图;

由于涉及到IP地址的选择,所以在MainWindow主构造函数中我们需要对ComboBox组件进行初始化,在初始化时我们需要打开数据库并将数据库中的Times表,并查询到address字段,这里在查询语句中使用DISTINCT语句,该语句是用于在SQL查询中选择唯一值的关键字,它能够确保查询的结果集中每个列的值都是唯一的。

SELECT DISTINCT address FROM Times;

在代码中,上述查询的目的是从 "Times" 表中选择唯一的 "address" 列的值。如果 "Times" 表中有多个行具有相同的 "address" 值,DISTINCT 会确保在结果中只返回一个该值,以避免重复。

当具备了这条语句那么查询唯一值将变得非常容易,当查询到对应值只有只需要通过comboBox->addItem即可将唯一的IP地址追加到组件中,如下代码所示;

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

    // 初始化绘图
    InitLineChart();

    // 初始化时间组件
    QDateTime curDateTime = QDateTime::currentDateTime();

    // 设置当前时间
    ui->dateTimeEdit_Start->setDateTime(curDateTime);
    ui->dateTimeEdit_End->setDateTime(curDateTime);

    // 设置时间格式
    ui->dateTimeEdit_Start->setDisplayFormat("yyyy-MM-dd hh:mm:ss");
    ui->dateTimeEdit_End->setDisplayFormat("yyyy-MM-dd hh:mm:ss");

    // 初始化数据库
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("database.sqlite3");

    if (!db.open())
    {
        std::cout << db.lastError().text().toStdString() << std::endl;
        return;
    }

    // 查询数据库中的IP地址信息
    QSqlQuery query;
    if (query.exec("SELECT DISTINCT address FROM Times;"))
    {
        QSet<QString> uniqueAddresses;

        while (query.next())
        {
            // Assuming 'address' is the name of the column
            QString data_name = query.value(0).toString();
            uniqueAddresses.insert(data_name);
        }

        // 清空现有的项
        ui->comboBox->clear();

        // 将唯一地址添加到 QComboBox 中
        foreach (const QString &uniqueAddress, uniqueAddresses)
        {
            ui->comboBox->addItem(uniqueAddress);
        }
    }
    else
    {
        std::cout << query.lastError().text().toStdString() << std::endl;
    }
}

接着来看下如何实现InitLineChart()绘图函数,绘图部分由于我们不需要直接绘制所以这里可以先初始化折线图表,等待后期添加数据绘制即可,这段代码的实现如下所示;

首先,创建一个QChart对象,代表整个图表,并将其添加到QGraphicsView中。随后,通过隐藏图例提高图表的美观度。接着,创建一个QLineSeries对象,表示折线图中的数据序列,并将其添加到图表中。为确保正确显示,创建了X轴和Y轴的坐标轴对象,并设置了范围、格式和刻度。最后,将X轴和Y轴与折线序列关联,以便在图表中显示数据。这段代码实现了一个简单的折线图的初始化,为进一步添加和展示数据提供了基础。

// 初始化Chart图表
void MainWindow::InitLineChart()
{
    // 创建图表的各个部件
    QChart *chart = new QChart();

    // 将Chart添加到ChartView
    ui->graphicsView_line->setChart(chart);
    ui->graphicsView_line->setRenderHint(QPainter::Antialiasing);

    // 隐藏图例
    chart->legend()->hide();

    // 创建曲线序列
    QLineSeries *series0 = new QLineSeries();

    // 序列添加到图表
    chart->addSeries(series0);

    // 创建坐标轴
    QValueAxis *axisX = new QValueAxis;    // X轴
    axisX->setRange(1, 100);               // 设置坐标轴范围
    axisX->setLabelFormat("%d %");         // 设置X轴格式
    axisX->setMinorTickCount(5);           // 设置X轴刻度

    QValueAxis *axisY = new QValueAxis;    // Y轴
    axisY->setRange(0, 100);               // Y轴范围
    axisY->setMinorTickCount(4);           // s设置Y轴刻度

    // 设置X于Y轴数据集
    chart->setAxisX(axisX, series0);       // 为序列设置坐标轴
    chart->setAxisY(axisY, series0);
}

当界面中的按钮被点击后,事件触发时执行,其主要功能是从数据库中查询记录并根据用户在界面上选择的设备地址、起始时间和结束时间条件,筛选符合条件的数据,并将其显示在折线图中。

首先,获取折线图对象和数据库查询结果的指针,然后清空折线序列准备接收新的数据。通过遍历数据库查询结果,获取每条记录的字段值,同时获取用户输入的查询条件。计算时间差并限制查询范围在3600秒内,然后判断记录是否在指定的时间范围内,并将符合条件的数据点添加到折线序列中。如果查询范围超出定义,输出错误消息。

void MainWindow::on_pushButton_clicked()
{
    // 获取指针
    QLineSeries *series0=(QLineSeries *)ui->graphicsView_line->chart()->series().at(0);

    // 清空图例
    series0->clear();

    // 查询数据
    QSqlQuery query("SELECT * FROM Times;",db);
    QSqlRecord rec = query.record();

    // 赋予数据
    qreal t=0,intv=1;

    // 循环所有记录
    while(query.next())
    {
        // 判断当前记录是否有效
        if(query.isValid())
        {
            QString address_value = query.value(rec.indexOf("address")).toString();
            QString date_time = query.value(rec.indexOf("datetime")).toString();
            int this_value = query.value(rec.indexOf("value")).toInt();

            // 获取组件字符串
            QString address_user = ui->comboBox->currentText();
            QString start_user_time = ui->dateTimeEdit_Start->text();
            QString end_user_time = ui->dateTimeEdit_End->text();

            // 将时间字符串转为秒,并计算差值 (秒为单位)
            QDateTime start_timet = QDateTime::fromString(start_user_time, "yyyy-MM-dd hh:mm:ss");
            QDateTime end_timet = QDateTime::fromString(end_user_time, "yyyy-MM-dd hh:mm:ss");

            uint stime = start_timet.toTime_t();
            uint etime = end_timet.toTime_t();

            // 只允许查询小于3600秒的记录
            uint sub_time = etime - stime;
            if(sub_time <= 3600)
            {
                // 查询指定区间内的数据
                if(date_time.toStdString() >= start_user_time.toStdString() &&
                        date_time.toStdString() <= end_user_time.toStdString() &&
                        address_value == address_user
                        )
                {
                    // std::cout << "区间内的数据: " << this_value << std::endl;
                    series0->append(t,this_value);
                    t+=intv;
                }
            }
            else
            {
                std::cout << "查询范围超出定义." << std::endl;
                return;
            }
        }
    }
}

这段代码实现了通过用户输入条件查询数据库,并动态更新折线图的功能,用于在界面上显示符合条件的数据趋势。

至此数据库与绘图组件的联动效果就实现了,其实很容易理解,因为是一个案例并没有包含任何复杂的功能这也是为了方便功能的展示,读者可自行运行并查询一个区间内的折线图,如下所示;

标签:Qt,数据库,Charts,C++,查询,ui,time,组件,query
From: https://blog.51cto.com/lyshark/9127264

相关文章

  • 刷题笔记——单向链表(C++)
    206.反转链表-力扣(LeetCode)给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。解题思路三指针。temp指针用于存储当前节点的下一节点,pre指针用于存储当前节点反转后指向的新节点。具体操作如下:反转过程:代码实现classSolution{public:ListNode*reverseList(Li......
  • c++ 期末编程题
    当然,我可以帮你整理一下你提供的C++代码,并为每个代码片段添加相应的标题。请看下面的整理:1.计算两点之间的距离#include<iostream>#include<cmath>usingnamespacestd;intmain(){intx1,x2,y1,y2;cout<<"请输入x1,x2,y1,y2的值";cin>>x1>>x2>>......
  • qt c语言双三次线性插值
    用chatgpt生成的测试了比较卡for(inty=0;y<enlargedHeight;y++){for(intx=0;x<enlargedWidth;x++){//计算原始图像中对应的浮点坐标floatoriginalX=(float)x/(float)enlar......
  • QT: Qt for MCU + PyQt6 to Android
    https://www.riverbankcomputing.com/static/Docs/PyQt6/https://www.qt.io/blog/taking-qt-for-python-to-androidhttps://github.com/shyamnathp/python-for-android/tree/pyside_supporthttps://www.qt.io/blog/qt-for-mcus-2.5.2-lts-releasedQtforMCUs2.5.2LTS(......
  • 【可视化库对比】ECharts、AntV、D3和Three
    本文写作目的:大家在使用可视化库创作可视化作品的时候,可能会产生这样的问题:“现如今成熟的可视化库有这么多,我到底该选择哪一个呢?”这其实也是我在学习数据可视化课程的时候面临的一个问题。因此本文旨在对比上述广泛被使用到的4个前端可视化库:Echart、AntV、D3和Three,了解它们的......
  • MQTT 客户端 MQTT.fx 使用说明
    下载官网:https://softblade.de/en/download-2/说明:最后的免费版本是MQTT.fx1.7.1,官网已经没有免费的版本下载MQTT.fx1.7.1https://nowjava.com/download/44364【需关注其公众号才能下载】安装一路Next即可使用安装好后,直接启动MQTT.fx点击第1步中界......
  • echarts选项变化后,图表不更新
    echarts做地图下钻,全国地图切换省份地图使用chart.setOption(option)后地图不刷新,原因如下:setOption有三个参数chart.setOption(option,notMerge,lazyUpdate)option——图表的配置项和数据notMerge——可选,是否不跟之前设置的option进行合并,默认为false,即合并。lazy......
  • Highcharts 甘特图的任务配置​
    需求甘特图中的条形显示任务的完整持续时间,这些持续时间是根据开始和结束数据点属性计算得出的。分析与解决进度条:使用进度条可以快速了解任务的完成百分比。通过在series.data点上设置completed属性,将常规任务转换为进度条。此属性采用具有选项的对象,用于设置对比度颜色和完成......
  • PythonQt简明教程
    PythonQt简明教程PythonQt是Qt框架的Python动态绑定,是一种将Python脚本语言嵌入C++Qt应用程序的简便方法。与PyQt、PySide不同,PythonQt侧重点在于将Python嵌入到现有的C++应用程序,而不是使用Python编写应用程序。接口PythonQt的主要接口通过PythonQt::self()单例提供,并由Pytho......
  • C++ Module详解,模块化编程终极指南
    C++Module详解,模块化编程终极指南模块接口文件定义和扩展名模块接口文件定义了模块所提供功能的接口。这些文件通常具有.cppm扩展名。模块接口以声明文件定义了某个名称的模块开始,这被称为模块声明。模块的名称可以是任何有效的C++标识符。名称可以包含点,但不能以点开头或结......