Qt QlistrView搭配数据库显示数据,QCharts显示折线图

程序

程序的运行样子
在这里插入图片描述

  1. 窗口介绍 左边窗口为listview,右边为plaintext,包含在QstackedWidget里,这是第一页

在这里插入图片描述

  1. QstackedWidget第二页是一个提升部件,从QGraphicsView提升为QChartView
    在这里插入图片描述

事先准备

说明一下,大部分代码是参考了qt5.9 c++开发指南
由于用到了数据库和图表,需要在工程文件下(*.pro)加入

QT += sql charts

再按下小锤子编译一下。

由于用到了数据库所以我们首先需要连接数据库,还有准备好数据库的文件,这里我用的数据库是sqlite,查看数据库的文件用的软件是Sqlite Expert Personal,百度一下就有了。

#include <QtSql>
class MainWindow : public QMainWindow
{
    
    
。。。。。
    //数据库
    QSqlDatabase db;					//连接数据库
    QSqlTableModel *tabModel;//数据库的模型,用于查找数据			
    QItemSelectionModel *theSelection;	//选择模型,判断选择的行数
。。。。

};

首先,我们要添加数据库的驱动,打开数据库后,再打开数据表,然后将tabModel设置为listview的模型,theSelection设置为listview的选择模型

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

    db = QSqlDatabase::addDatabase("QSQLITE");//数据库驱动
    openSqlite();//失败也会自动创建文件  *.db
    openTable();
    ui->listDiary->setModel(tabModel);
    ui->listDiary->setSelectionModel(theSelection);
	。。。。。

}
bool MainWindow::openSqlite()
{
    
    
    QString aFile = "./data.db";//在当前运行的目录下文件“data.db”

    db.setDatabaseName(aFile);
    if(!db.open())
    {
    
    
        QMessageBox::warning(this, "错误","打开数据库失败",QMessageBox::Ok,QMessageBox::NoButton);
        return false;
    }
    return true;
}

在debug下运行
在这里插入图片描述
连接数据库后,打开数据表,设置模型的编辑策略为OnManualSubmit,只有使用submitAll() revertAll() 才能保存修改。
theSelection的currentChanged信号用来响应,当数据改变时,保存的撤回按钮使能,currentRowChanged信号用来响应,当行变化时在plaintext上显示数据。

void MainWindow::openTable()
{
    
    
    tabModel = new QSqlTableModel(this, db);
    //我的数据表名字叫做“diaryData”
    tabModel->setTable("diaryData");
    //设置编辑的策略,所有修改都保存在缓存中
    tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
    if(!(tabModel->select()))
    {
    
    
        QMessageBox::warning(this, "错误","打开数据表失败\n"+tabModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }
	//选择模型
    theSelection = new QItemSelectionModel(tabModel);
	//当数据模型tabModel中有数据发生改变,会发送currentChanged信号
    connect(theSelection, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            this, SLOT(on_currentChanged(QModelIndex, QModelIndex)));
    //当行发生改变,发送currentRowChanged信号
    connect(theSelection, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
            this, SLOT(on_currentRowChanged(QModelIndex, QModelIndex)));
}

回到mainwindow的构造函数,加上这两句,listview不允许用户双击改变数据,并设置可以多选。

 //不允许双击编辑
    ui->listDiary->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->listDiary->setSelectionMode(QAbstractItemView::ExtendedSelection);//设置多选

按照增删改的方式说下代码



第一个按钮,新建数据。这里需要用到一个自定义的对话框。
在这里插入图片描述
在这里插入图片描述
新建数据的时候,弹出对话框,将得到的数据保存,并且将当前选择移动至新建的那一行。

void MainWindow::on_actionNewData_triggered()
{
    
    
    DialogNewDiary *digNewDiary = new DialogNewDiary(this);
    Qt::WindowFlags flags = digNewDiary->windowFlags();

    digNewDiary->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint);
    int ret = digNewDiary->exec();//模态对话框
    if(ret == QDialog::Accepted)
    {
    
    
    	//获取对话框的数据
        MOOD the_mood = digNewDiary->get_Mood();
        QString title = digNewDiary->get_title();
        QString content = digNewDiary->get_content();
        QString dateTime = digNewDiary->get_dateTime();
        QString id = digNewDiary->get_id();
        //插入一行
        tabModel->insertRow(tabModel->rowCount(),QModelIndex());
		//获取当前行索引
        QModelIndex curIndex = tabModel->index(tabModel->rowCount()-1,1);
        theSelection->clearSelection();
        //设置新建行为当前选择
        theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
        int currow = curIndex.row();
        //往这一行的添加数据,数据表中我的标题是第0行,以此类推
        tabModel->setData(tabModel->index(currow,THE_TITLE),title);
        tabModel->setData(tabModel->index(currow,THE_MOOD),the_mood);
        tabModel->setData(tabModel->index(currow,THE_CONTENT),content);
        tabModel->setData(tabModel->index(currow,THE_DATE_TIME),dateTime);
        tabModel->setData(tabModel->index(currow,THE_ID),id);

		//按照格式生成日记数据
        QString data = DiaryHelp::make_A_diary(title,the_mood,content);
        ui->plainTextData->setPlainText(data);
        //保存到数据库里
        bool res = tabModel->submitAll();
        if(!res)
            QMessageBox::information(this, "消息","数据保存错误\n"
                                     +tabModel->lastError().text(),QMessageBox::NoButton);
    }
    delete digNewDiary;
}


这里可能有点问题,删除操作刚刚试着删除会留一行,但是再运行一下,又没这问题了。
在这里插入图片描述

void MainWindow::on_actionDeleteData_triggered()
{
    
    
    //多选删除
    if(QMessageBox::Yes == QMessageBox::warning(this, "警告","是否删除\n",QMessageBox::Yes | QMessageBox:: No))
    {
    
    
//        QModelIndex curIndex = theSelection->currentIndex();
        QModelIndexList modelIndexList = ui->listDiary->selectionModel()->selectedIndexes();
		//得到选中的数据,根据他的row进行删除
        foreach(QModelIndex modelIndex, modelIndexList)
        {
    
    
            qDebug()<<modelIndex.row();
            tabModel->removeRow(modelIndex.row());
        }
        tabModel->submitAll();
        ui->plainTextData->clear();
    }
    else
        return;
}


将选中那一行数据获取后放在对话框,供用户修改。其中用到QSqlRecord 用来查询数据,如下所示,以下是在当前选中的那一行,查询数据表中titile字段的内容

QSqlRecord curRec = tabModel->record(curRecNo);
QString title = curRec.value(“title”).toString();

void MainWindow::on_actionEdt_triggered()
{
    
    
    DialogNewDiary *digNewDiary = new DialogNewDiary(this);
    Qt::WindowFlags flags = digNewDiary->windowFlags();

    QModelIndex curIndex = theSelection->currentIndex();
    int curRecNo = curIndex.row();
    QSqlRecord curRec = tabModel->record(curRecNo);
	//获取数据
    MOOD the_mood = (MOOD)(curRec.value("mood").toInt());
    QString title = curRec.value("title").toString();
    QString content = curRec.value("content").toString();
    QString id = curRec.value("id").toString();
	//将数据填充到对话框
    digNewDiary->set_date(id,the_mood,title,content);

    digNewDiary->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint);
    int ret = digNewDiary->exec();//模态对话框

    if(ret == QDialog::Accepted)
    {
    
    
        //获取数据
        。。。。。

        theSelection->clearSelection();
        theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
        int currow = curIndex.row();
       //填充数据
		。。。。
        QString data = DiaryHelp::make_A_diary(title,the_mood,content);
        ui->plainTextData->setPlainText(data);
	//使能保存和撤回按钮
    ui->actionSave->setEnabled(tabModel->isDirty());
    ui->actionRevert->setEnabled(tabModel->isDirty());
    delete digNewDiary;
}

现在说回曲线图

使用qt charts

//.h
#include <QtCharts>
class MainWindow : public QMainWindow
{
    
    
。。。。。。

    //图表
    QSplineSeries *curSeries; //光滑曲线

    QDateTimeAxis *axisX_Time;//时间x轴

    void createChart();
    void prepareData();
    void updateFromChart();

};

//.cpp
using namespace QtCharts;

创建曲线图

void MainWindow::createChart()
{
    
    
    QChart *chart = new QChart();
    chart->setTitle("变化");
    ui->charView->setChart(chart);
    ui->charView->setRenderHint(QPainter::Antialiasing);

    curSeries = new QSplineSeries();

    curSeries->setName("心情");

    QPen pen;
    pen.setStyle(Qt::DotLine);
    pen.setWidth(5);
    pen.setColor(Qt::red);
    curSeries->setPen(pen);
    pen.setStyle(Qt::SolidLine);
    pen.setColor(Qt::blue);
    chart->addSeries(curSeries);

    axisX_Time = new QDateTimeAxis(this);
//设置曲线图显示范围,时间变化值(x轴)
//默认情况下如果数据小于两行不显示曲线图
    if(tabModel->rowCount()<=1)
    {
    
    
        QDateTime temp_StartTime(QDate(2000, 1, 1), QTime(0, 0, 0)); //前面是年月日,后面是小时、分钟、秒
        QDateTime temp_EndTime(QDate(2000, 1, 1), QTime(0, 20, 0));//
        axisX_Time->setTickCount(5);//设置显示的时间个数
        axisX_Time->setRange(temp_StartTime, temp_EndTime);//设置显示范围
    }
    else
    {
    
    
        QSqlRecord start = tabModel->record(0);
        QSqlRecord end = tabModel->record(tabModel->rowCount()-1);
        QDateTime temp_StartTime = QDateTime::fromString(start.value("dateTime").toString(),DATE_FORMAT);
        QDateTime temp_EndTime = QDateTime::fromString(end.value("dateTime").toString(),DATE_FORMAT);

        int rangeX = (tabModel->rowCount()<=1)?7:tabModel->rowCount();
        axisX_Time->setTickCount(rangeX);
        axisX_Time->setRange(temp_StartTime,temp_EndTime);//显示范围
        axisX_Time->setFormat("MM/dd");//显示的时间格式
    }
//设置心情变化值(y轴)
    QValueAxis *axisY = new QValueAxis();
    axisY->setRange(-3,4);
    axisY->setTitleText("value");
    axisY->setTickCount(8);
    axisY->setLabelFormat("%d");
    axisY->setMinorTickCount(0);

    chart->addAxis(axisX_Time,Qt::AlignBottom); //坐标轴添加到图表,并指定方向axisX
    chart->addAxis(axisY,Qt::AlignLeft);

    curSeries->attachAxis(axisX_Time); //序列 series0 附加坐标轴axisX
    curSeries->attachAxis(axisY);
}

给曲线图添加数据,遍历数据后添加进去

void MainWindow::prepareData()
{
    
    
    QSplineSeries *series = (QSplineSeries *)ui->charView->chart()->series().at(0);

    series->clear();
    for(int i = 0; i<tabModel->rowCount(); i++)
    {
    
    
        QSqlRecord aRec = tabModel->record(i);
        int mood = aRec.value("mood").toInt()-2;
        QDateTime temp = QDateTime::fromString(aRec.value("dateTime").toString(),"yyyy-MM-dd hh:mm:ss.zzz");
        series->append(temp.toMSecsSinceEpoch(),mood);
    }
}

更新数据,当数据变化,更改x轴显示范围,再次添加数据

void MainWindow::updateFromChart()
{
    
    
    if(tabModel->rowCount()<=1)
    {
    
    
        QDateTime temp_StartTime(QDate(2000, 1, 1), QTime(0, 0, 0)); //前面是年月日,后面是小时、分钟、秒
        QDateTime temp_EndTime(QDate(2000, 1, 1), QTime(0, 20, 0));//
        axisX_Time->setTickCount(5);//设置显示的时间个数
        axisX_Time->setRange(temp_StartTime, temp_EndTime);//设置显示范围
    }
    else
    {
    
    

        QSqlRecord start = tabModel->record(0);
        QSqlRecord end = tabModel->record(tabModel->rowCount()-1);

        QDateTime temp_StartTime = QDateTime::fromString(start.value("dateTime").toString(),DATE_FORMAT);
        QDateTime temp_EndTime = QDateTime::fromString(end.value("dateTime").toString(),DATE_FORMAT);

        int rangeX = tabModel->rowCount();
        axisX_Time->setTickCount(rangeX/2);
        axisX_Time->setRange(temp_StartTime,temp_EndTime);
    }
    prepareData();
}

补充说明一下,因为我是写完代码后开始写博客,已经提前把代码上传到csdn了,而我在写博客的时候,有一些小修改(基本没有大改动)可能你下载的代码和我上面写的有一些不一样,但是基本不影响。
还有一件事,就是
在这里插入图片描述
下载:https://download.csdn.net/download/weixin_43387612/12667977

猜你喜欢

转载自blog.csdn.net/weixin_43387612/article/details/107631412