QSqlQueryModel 可以设置任意的 SELECT 语句来从数据库中查询数据,可以查询一个数据表部分字段的数据,也可以是多个数据表组合的数据。该模型的数据是只读的,即使在界面上修改了QSqlQueryModel 模型的数据,也不能将所做的修改提交到数据库。
要从数据库查询数据并将其作为 QSqlQueryModel 的数据源,需要运行函数 setQuery()
有两种原型:
void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase())
void QSqlQueryModel::setQuery(QSqlQuery &&query)
QSqlQuery 是可以运行任何 SQL 语句的类,当然也能运行 SELECT 语句从数据库获取数据。
查询出数据后,可以用 QSqlQueryModel 的函数 record()访问数据记录。
//1. 创建数据模型,查询数据qryModel=new QSqlQueryModel(this);qryModel->setQuery("SELECT empNo, Name, Gender, Birthday, Province, Department, "" Salary FROM employee ORDER BY empNo",DB);if (qryModel->lastError().isValid()){QMessageBox::critical(this, "错误", "数据表查询错误,错误信息\n"+qryModel->lastError().text());return;}//2. 设置字段显示标题QSqlRecord rec=qryModel->record(); //获取一个空记录,为了获取字段序号qryModel->setHeaderData(rec.indexOf("empNo"), Qt::Horizontal, "工号");qryModel->setHeaderData(rec.indexOf("Name"), Qt::Horizontal, "姓名");qryModel->setHeaderData(rec.indexOf("Gender"), Qt::Horizontal, "性别");qryModel->setHeaderData(rec.indexOf("Birthday"), Qt::Horizontal, "出生日期");qryModel->setHeaderData(rec.indexOf("Province"), Qt::Horizontal, "省份");qryModel->setHeaderData(rec.indexOf("Department"), Qt::Horizontal, "部门");qryModel->setHeaderData(rec.indexOf("Salary"), Qt::Horizontal, "工资");//3. 创建选择模型selModel=new QItemSelectionModel(qryModel,this);connect(selModel,&QItemSelectionModel::currentRowChanged,this, &MainWindow::do_currentRowChanged);ui->tableView->setModel(qryModel);//4. 创建数据映射dataMapper= new QDataWidgetMapper(this);dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);dataMapper->setModel(qryModel);//界面组件与数据模型的具体字段之间的映射dataMapper->addMapping(ui->dbSpinEmpNo, rec.indexOf("empNo"));dataMapper->addMapping(ui->dbEditName, rec.indexOf("Name"));dataMapper->addMapping(ui->dbComboSex, rec.indexOf("Gender"));dataMapper->addMapping(ui->dbEditBirth, rec.indexOf("Birthday"));dataMapper->addMapping(ui->dbComboProvince, rec.indexOf("Province"));dataMapper->addMapping(ui->dbComboDep, rec.indexOf("Department"));dataMapper->addMapping(ui->dbSpinSalary, rec.indexOf("Salary"));dataMapper->toFirst(); //移动到首记录
record函数不带参数可以获取字段名称,想要获取对应记录的字段对应值,可以参考以下:
QSqlRecord rec1=qryModel->record(2);QVariant vr = rec1.value("Name");QString qs = vr.toString();qDebug() << qs;
使用ui->tableView->setSelectionModel(selModel);语句将界面显示与模型绑定在一起。
dataMapper将UI中的一系列界面组件映射到一条记录的不同字段,便设置显示为第一条记录的数据内容。
ui->tableView->setSelectionModel(selModel);设置了选择模型,当选择的行发生改变时候会进入以下槽函数:
void MainWindow::do_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
{Q_UNUSED(previous);if (!current.isValid()){ui->dbLabPhoto->clear();ui->dbEditMemo->clear();return;}dataMapper->setCurrentModelIndex(current); //设置当前行// dataMapper->setCurrentIndex(current.row()); //这个也可以bool first=(current.row()==0); //是否首记录bool last=(current.row()==qryModel->rowCount()-1); //是否尾记录ui->actRecFirst->setEnabled(!first); //更新使能状态ui->actRecPrevious->setEnabled(!first);ui->actRecNext->setEnabled(!last);ui->actRecLast->setEnabled(!last);int curRecNo=selModel->currentIndex().row();QSqlRecord curRec=qryModel->record(curRecNo); //获取当前记录int empNo=curRec.value("EmpNo").toInt(); //主键字段QSqlQuery query(DB); //查询某个empNo的Memo和Photo字段的数据query.prepare("select EmpNo, Memo, Photo from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();query.first();QVariant va=query.value("Photo");if (!va.isValid()) //图片字段内容为空ui->dbLabPhoto->clear();else //显示图片{QByteArray data=va.toByteArray();QPixmap pic;pic.loadFromData(data);ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));}QVariant va2=query.value("Memo"); //显示备注ui->dbEditMemo->setPlainText(va2.toString());
}
在槽函数中获取当前选择的记录,并设置dataMapper,选择的记录条在其他组件中同步更新,获取该记录的一些数据,然后用一个 QSqlQuery 变量 query 运行查询语句,查询对应EmpNo号对应记录的BLOB类型数据,并转化显示为图片。
记录的移动需要根据 QDataWidgetMapper 对象的当前行设置选择模型的当前行,这样才能使
QTableView组件和数据感知组件的当前行是同步的。
void MainWindow::on_actRecFirst_triggered()
{ //首记录dataMapper->toFirst();refreshTableView();
}void MainWindow::on_actRecPrevious_triggered()
{ //前一记录dataMapper->toPrevious();refreshTableView();
}void MainWindow::on_actRecNext_triggered()
{//后一记录dataMapper->toNext();refreshTableView();
}void MainWindow::on_actRecLast_triggered()
{//尾记录dataMapper->toLast();refreshTableView();
}//刷新tableView的当前行
void MainWindow::refreshTableView()
{int index=dataMapper->currentIndex(); //dataMapper的当前行号QModelIndex curIndex=qryModel->index(index,1); //为当前行创建模型索引selModel->clearSelection(); //清空选择项selModel->setCurrentIndex(curIndex,QItemSelectionModel::Select); //设置当前行
}