背景知识:
Qt SQL的API分为不同层:
- 驱动层
驱动层 对于QT是基于C++来实现的框架,该层主要包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorbase、QSqlDriverPlugin and QSqlResult。这一层提供了特定数据库和SQL API层之间的底层桥梁。
- SQL API层
SQL API层 对于SQL API 层提供了数据库的访问相关类,其中,QSqlDataBase类进行连接,QSqlQuery完成数据库的交互。除此之外,还有QSqlError、QSqlField、QSqlIndex and QSqlRecord类。
- 用户接口层
用户接口层 用户接口层的几个类实现将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,他们是更高层次的抽象,主要包括QSqlQureyModel,QSqlTableModel and QSqlRelationalTableModel。
用户接口层的类使用模型/视图框架实现了将数据库中的数据链接到窗口控件上。
QTableView是常用的内容显示视图组件。数据模型类有:QSqlQueryModel 、QSqlTableModel 、QSqlRelationalTableModel
QSqlQueryModel :通过设置SELECT语句查询获取内容,Model数据是只读的,不能进行编辑。
QSqlTableModel : 直接设置一个数据表的名称,可以获取数据表的全部记录,结果是可编辑的。
QSqlRelationalTableModel: 编辑一个数据表,将代码字段通过关系与代码表关联,将代码字段的编辑转换为直观的内容选择编辑。
QSqlRelationalTableModel
QSqlRelationalTableModel为QSqlTableModel 的子类,为单张的数据库表提供了一个可编辑的数据模型,它支持外键
即将主表里的某个字段存储为代码型字段,而代码的具体意义存储在另外一个数据表里。
主表代码字段和关联数据表的关联通过setRelation函数实现。
//关联函数
virtual void setRelation(int column, const QSqlRelation &relation);
QSqlRelation(const QString &aTableName, const QString &indexCol,
const QString &displayCol)
Column:主表的代码字段的序号
QSqlRelation
aTableName :代码表
indexCol:代码字段名称
displayCol:代码意义的字段名称
如
tabModel->setRelation(3,QSqlRelation("departments","departID","department")); //学院 tabModel->setRelation(4,QSqlRelation("majors","majorID","major"));//专业
例子
- 数据库使用SQLite数据库,格式为.db3
- 模型使用QSqlRelationalTableModel,视图使用QTableView
- 因为QSqlRelationalTableModel可编辑,可使用代理处理编辑操作。
- 除了关联字段特殊处理外,其他的和QSqlTableModel一样的操作。
打开数据库
void MainWindow::on_actOpenDB_triggered()
{
QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","",
"SQL Lite数据库(*.db *.db3)");
// QString aFile= QFileDialog::getOpenFileName(this,"选择数据库文件","","SQL Lite数据库(*.db *.db3)");
if (aFile.isEmpty())
return;
//打开数据库
DB=QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动
DB.setDatabaseName(aFile); //设置数据库名称
// DB.setHostName();
// DB.setUserName();
// DB.setPassword();
if (!DB.open()) //打开数据库
{
// QMessageBox::warning(this, "错误", "打开数据库失败",QMessageBox::Ok,QMessageBox::NoButton);
return;
}
//打开数据表
openTable();
}
打开数据表
void MainWindow::openTable()
{//打开数据表
tabModel=new QSqlRelationalTableModel(this,DB);
tabModel->setTable("studInfo"); //设置数据表
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); //OnManualSubmit , OnRowChange
tabModel->setSort(0,Qt::AscendingOrder);
tabModel->setHeaderData(0,Qt::Horizontal,"学号");
tabModel->setHeaderData(1,Qt::Horizontal,"姓名");
tabModel->setHeaderData(2,Qt::Horizontal,"性别");
tabModel->setHeaderData(3,Qt::Horizontal,"学院");
tabModel->setHeaderData(4,Qt::Horizontal,"专业");
//设置代码字段的查询关系数据表
tabModel->setRelation(3,QSqlRelation("departments","departID","department")); //学院
tabModel->setRelation(4,QSqlRelation("majors","majorID","major"));//专业
theSelection=new QItemSelectionModel(tabModel);
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
ui->tableView->setModel(tabModel);
ui->tableView->setSelectionModel(theSelection);
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件
tabModel->select(); //打开数据表
// ui->tableView->resizeColumnsToContents();
// ui->tableView->horizontalHeader()->setStretchLastSection(true);
ui->actOpenDB->setEnabled(false);
ui->actRecAppend->setEnabled(true);
ui->actRecInsert->setEnabled(true);
ui->actRecDelete->setEnabled(true);
ui->actFields->setEnabled(true);
}
添加操作
void MainWindow::on_actRecAppend_triggered()
{//添加记录
tabModel->insertRow(tabModel->rowCount(),QModelIndex()); //在末尾添加一个记录
QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);//创建最后一行的ModelIndex
theSelection->clearSelection();//清空选择项
theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);/
}
删除
void MainWindow::on_actRecDelete_triggered()
{//删除当前记录
tabModel->removeRow(theSelection->currentIndex().row());
tabModel->submitAll(); //立即更新
}
保存
void MainWindow::on_actSubmit_triggered()
{//保存修改
bool res=tabModel->submitAll();
if (!res)
QMessageBox::information(this, "消息", "数据保存错误,错误信息\n"+tabModel->lastError().text(),
QMessageBox::Ok,QMessageBox::NoButton);
else
{
ui->actSubmit->setEnabled(false);
ui->actRevert->setEnabled(false);
}
}
取消修改
void MainWindow::on_actRevert_triggered()
{//取消修改
tabModel->revertAll();
ui->actSubmit->setEnabled(false);
ui->actRevert->setEnabled(false);
}