程序
程序的运行样子
- 窗口介绍 左边窗口为listview,右边为plaintext,包含在QstackedWidget里,这是第一页
- 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