C++ Qt development: Linkage between Charts and database components

Qt is a cross-platform C++ graphical interface development library. You can use Qt to quickly develop cross-platform form applications. In Qt, we can drag and drop different components into designated locations to achieve great convenience in graphical development. In order to improve development efficiency, this chapter will focus on the common methods and flexible applications of Chartscomponents and database components.QSql

The previous article introduced in detail QChartshow to use the drawing component. This chapter will continue this knowledge point by using QSqlthe database module to dynamically read the data at a certain time node. When the user clicks to query the data, the data will be dynamically output. All data of the event node, and the data is drawn into the graphics component to realize the function of dynamically querying the graphics.

InitDatabaseFirst we need to generate some test data. There is a case in the article courseware . In this case, QSqla table is dynamically created through components Times. There are three fields in the table that record the host IP address, time, and data respectively, and dynamically add them to the table. Insert some random test data. Readers can run this program and wait for more than ten minutes. At this time, database.sqlite3the data set as shown below will appear in the database;

Let’s look at how the main form is designed. A ComboBoxdrop-down selection box is used on the left, two freely adjustable Date/TimeEditcomponents are used on the right, and a graphicsViewdrawing component is used at the bottom, as shown below;

Since it involves the selection of IP address, we need to initialize the component MainWindowin the main constructor . During initialization, we need to open the database and put the tables in the database and query the fields. Here we use the statement in the query statement . This statement Is a keyword used to select unique values ​​in a SQL query, which ensures that the value of each column in the query's result set is unique.ComboBoxTimesaddressDISTINCT

SELECT DISTINCT address FROM Times;

In the code, the purpose of the above query is to select the unique "address" column value from the "Times" table. If there are multiple rows in the "Times" table with the same "address" value, DISTINCTit is ensured that only one of that value is returned in the results to avoid duplication.

With this statement, it will be very easy to query the unique value. When the corresponding value is queried, you only need to comboBox->addItemappend the unique IP address to the component, as shown in the following code;

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;
    }
}

Next, let’s take a look at how to implement InitLineChart()the drawing function. In the drawing part, since we don’t need to draw directly, we can initialize the line chart first and wait for the data to be added later to draw. The implementation of this code is as follows;

First, create an QChartobject that represents the entire chart and add it to QGraphicsViewthe . Then, improve the aesthetics of the chart by hiding the legend. Next, create an QLineSeriesobject that represents the data series in the line chart and add it to the chart. To ensure correct display, the coordinate axis objects for the X-axis and Y-axis are created, and the range, format, and scale are set. Finally, associate the X-axis and Y-axis with the polyline series to display the data in the chart. This code implements the initialization of a simple line chart, providing a basis for further adding and displaying data.

// 初始化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);
}

When the button in the interface is clicked, it is executed when the event is triggered. Its main function is to query records from the database and filter the data that meets the conditions based on the device address, start time and end time conditions selected by the user on the interface, and then It is displayed in a line chart.

First, get the pointers to the line chart object and database query results, and then clear the line sequence to prepare to receive new data. By traversing the database query results, the field values ​​of each record are obtained, and the query conditions entered by the user are obtained. Calculate the time difference and limit the query range to 3600 seconds, then determine whether the record is within the specified time range, and add qualified data points to the polyline series. If the query range exceeds the definition, an error message is output.

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;
            }
        }
    }
}

This code implements the function of querying the database through user input conditions and dynamically updating the line chart, which is used to display data trends that meet the conditions on the interface.

At this point, the linkage effect between the database and the drawing component has been achieved. It is actually very easy to understand because it is a case and does not contain any complex functions. This is also to facilitate the display of functions. Readers can run and query the line chart within an interval, as follows shown;

Supongo que te gusta

Origin blog.csdn.net/lyshark_csdn/article/details/135427614
Recomendado
Clasificación