Qt SQL模块:
- Qt底子 | Qt SQL模块先容 | Qt SQL模块常用类及其常用函数先容
- Qt底子 | QSqlTableModel 的使用
- Qt底子 | QSqlQueryModel 的使用 | QSqlQuery的使用
- Qt底子 | QSqIRelationalTableModel 的使用
关于 QSqlTableModel 、QSqlDatabase 、QDataWidgetMapper 类的使用可参考:Qt底子 | Qt SQL模块先容 | Qt SQL模块常用类及其常用函数先容
一、QSqlTableModel 的使用
这一部分使用 QSqlTableModel 表实际例数据库 demodb 中 employee 数据表的内容,实现编辑、插入、删除记录的操作,实现数据的排序和记录过滤,还实现 BLOB 范例字段 Photo 中存储照片的表现、导入等操作。
1.主窗口MainWindow类界说
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
- #include <QMainWindow>
- #include <QLabel>
- #include <QString>
- #include <QtSql>
- #include <QDataWidgetMapper>
- #include "qwcomboboxdelegate.h"
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
- private:
- QSqlDatabase DB;//数据库连接
- QSqlTableModel *tabModel; //数据模型
- QItemSelectionModel *theSelection; //选择模型
- QDataWidgetMapper *dataMapper; //数据映射
- QWComboBoxDelegate delegateSex; //自定义数据代理,性别
- QWComboBoxDelegate delegateDepart; //自定义数据代理,部门
- void openTable();//打开数据表
- void getFieldNames();//获取字段名称,填充“排序字段”的comboBox
- public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
- private slots:
- void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
- // QTableView的SelectionModel的行发生了变化,进行处理
- void on_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
- void on_actOpenDB_triggered();
- void on_actRecAppend_triggered();
- void on_actRecInsert_triggered();
- void on_actRevert_triggered();
- void on_actSubmit_triggered();
- void on_actRecDelete_triggered();
- void on_actPhoto_triggered();
- void on_actPhotoClear_triggered();
- void on_radioBtnAscend_clicked();
- void on_radioBtnDescend_clicked();
- void on_radioBtnMan_clicked();
- void on_radioBtnWoman_clicked();
- void on_radioBtnBoth_clicked();
- void on_comboFields_currentIndexChanged(int index);
- void on_actScan_triggered();
- private:
- Ui::MainWindow *ui;
- };
- #endif // MAINWINDOW_H
复制代码 MainWindow 类中界说了几个私有变量:
- QSqlDatabase DB:用于加载数据库驱动和建立与数据库之间的连接
- QSqlTableModel *tabModel:用于指定某个数据表 ,作为数据表的数据模型
- QItemSelectionModel *theSelection:作为 tabModel 的选择模型,提供 currentChanged()、currentRowChanged()信号,在 tabModel 选择的字段发生厘革、当前记录发生厘革时发射信号,以便步调举行响应。
例如,在 currentChanged() 信号发射时,检查 tabModel 是否有数据被修改 ,从而更新界面上 “生存”和“取消“两个按钮的使能状态
- QDataWidgetMapper *dataMapper:用于实现界面组件与 tabModel 的字段之间的映射。
例如,界面上的 QLineEdit 型的 dbEditName 组件与数据表的 Name 字段映射,当前记录厘革时会自动更新表现当前记录 Name 段的数据。
- QWComboBoxDelegate delegateSex:是自界说的基于 QComboBox 的代理类,delegateSex 和 delegateDepart 用作 tableView 中“性别” 和 “部分” 字段的代理组件。
私有函数:
- openTable函数:用于打开数据表,包罗添加 SQLite 数据库驱动、打开数据库文件、连接 employee 数据表并设置表现属性,并创建 tableView 表现的代理组件,设置数据源与界面组件的映射等
- getFieldNames函数:用于获取数据表 employee 的所有字段的名称,并添补界面上 “排序字段” 后的 ComboBox 组件。
槽函数:
- on_currentChanged:用于检查数据表内容是否修改,根据是否有未提交的修改,更新工具栏按钮 “生存” 和 “取消” 两个按钮的使能状态。
- on_currentRowChanged:用于在当前行厘革时,从新的记录里提取 Photo 字段的内容,并将图片在 QLabel 组件里表现出来。
2.构造函数
MainWindow 的构造函数代码如下,重要是对 tableView 一些表现属性的设置。
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- this->setCentralWidget(ui->splitter);
- // tableView显示属性设置
- ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
- ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
- ui->tableView->setAlternatingRowColors(true);
- // ui->tableView->resizeColumnsToContents();
- // ui->tableView->horizontalHeader()->setStretchLastSection(true);
- }
复制代码
- setSelectionBehavior函数:用于界说视图(View)选择哪种选择行为
- void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
复制代码 QAbstractItemView::SelectionBehavior是一个枚举范例,有如下选择:
- QAbstractItemView::SelectItems:选择单个项
- QAbstractItemView::SelectRows:仅选择行
- QAbstractItemView::SelectColumns:仅选择列
- setSelectionMode函数:用于界说视图(view)的选择模式
- void setSelectionMode(QAbstractItemView::SelectionMode mode)
复制代码 QAbstractItemView::SelectionMode是一个枚举范例,有如下取值:
- QAbstractItemView::SingleSelection:单选模式,用户只能选择一个项目。
- QAbstractItemView::ContiguousSelection:连续选择模式,用户可以选择多个项目,但这些项目必须在视觉上是连续的。
- QAbstractItemView::ExtendedSelection:扩展选择模式,用户可以选择多个项目,而且可以选择非连续的项目。
- QAbstractItemView::MultiSelection:多选模式,用户可以选择多个项目。
- QAbstractItemView::NoSelection:无选择模式
- setAlternatingRowColors函数:用来控制当前是否启用交替行颜色绘制背景
- void setAlternatingRowColors(bool enable)
复制代码
- 当 alternatingRowColors 属性设置为 true 时,视图中的项背景将使用 QPalette::Base 和 QPalette::AlternateBase 颜色交替绘制。QPalette::Base 是默认的背景颜色,而 QPalette::AlternateBase 是用于交替行的背景颜色。
- 当 alternatingRowColors 属性设置为 false 时,所有项的背景将同一使用 QPalette::Base 颜色绘制。
- resizeColumnsToContents函数:用于根据列中每个项的代理组件的大小提示来调解所有列的宽度
- void QTableView::resizeColumnsToContents()
复制代码 - horizontalHeader函数:用于返回 QTableView 的水平表头
- QHeaderView *QTableView::horizontalHeader() const
复制代码 3.打开数据表
打开数据表这一部分重要包罗:
- 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
- 设置数据模型、选择模型、自界说代理组件、界面组件与模型数据字段间的数据映射
3.1 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
这一部分重要用到了 QSqlDatabase 类,该类用于处理与数据库的连接。
- void MainWindow::on_actOpenDB_triggered()
- {//打开数据表
- QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","",
- "SQL Lite数据库(*.db *.db3)");
- if (aFile.isEmpty()) //选择SQL Lite数据库文件
- 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();
- }
复制代码 补充:
- QSqlDatabase::addDatabase:该静态函数用于添加数据库驱动,其返回结果为 QSqlDatabase 类,该类可用于数据库操作,包罗建立数据库连接,设置登岸数据库的参数,打开数据库等。
其完整的函数声明如下:
- [static] QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatin1String(defaultConnection))
复制代码 示例:
- // 添加一个名为 "myConnection" 的 SQLite 数据库连接
- QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "myConnection");
- db.setDatabaseName("example.db"); // 设置数据库文件名
- db.setUserName("user"); // 设置用户名
- db.setPassword("password"); // 设置密码
- // 打开数据库连接
- if (db.open()) {
- QSqlQuery query;
- query.exec("SELECT * FROM table_name"); // 执行查询
- while (query.next()) {
- // 处理查询结果
- }
- db.close();
- } else {
- qDebug() << "Error: Unable to open database";
- }
复制代码 还有一个函数重载,参数指定的不是驱动名称,而是 QSqlDriver 类。
- [static] QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver *driver, const QString &connectionName = QLatin1String(defaultConnection))
复制代码 示例:
- PGconn *con = PQconnectdb("host=server user=bart password=simpson dbname=springfield");
- QPSQLDriver *drv = new QPSQLDriver(con);
- QSqlDatabase db = QSqlDatabase::addDatabase(drv); // becomes the new default connection
- QSqlQuery query;
- query.exec("SELECT NAME, ID FROM STAFF");
复制代码 - QSqlDatabase类的数据库连接操作:用于设置数据库连接与登岸参数
留意:对于 SQLite 数据库,只需用 setDatabaseName() 设置数据库文件即可。如果是网络型数据库,如 Oracle、MS SQL Server等,还需要使用 setHostName() 设置主机名,setUserName() 设置数据库用户名,setPassword() 设置数据库登岸密码。
- setDatabaseName:设置数据库名称
- setHostName:设置数据库主机名
- setUserName:设置数据库用户名
- setPassword:设置数据库登岸密码
- open()函数:打开数据库。如果成功打开数据库则返回true
3.2 数据模型设置、选择模型、自界说代理组件、界面组件与模型数据字段间的数据映射
这部分用到 3 个类:
- QSqlTableModel:
QSqlTableModel 是一个用于表现和编辑单个数据库表内容的模型
- QTableView:
二维数据表视图组件,有多个行和多个列,每个基本表现单位是一个单位格,通过 setModel() 函数设置一个 QSqlTableModel 类的数据模型之后,一个单位格表现 QSqlTableModel 数据模型中的一个项
- QItemSelectionModel:
一个用于跟踪视图组件的单位格选择状态的类,当在 QTableView 选择某个单位格,或多个单位格时,通过 QItemSelectionModel 可以获得选中的单位格的模型索引,为单位格的选择操作提供方便。
这几个类之间的关系是:QTableView是界面视图组件,其关联的数据模型是 QSqlTableModel,关联的项选择模型是 QItemSelectionModel。
数据模型创建与属性设置:
- tabModel=new QSqlTableModel(this,DB);//数据表
- tabModel->setTable("employee"); //设置数据表
- tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//数据保存方式,OnManualSubmit , OnRowChange
- tabModel->setSort(tabModel->fieldIndex("empNo"),Qt::AscendingOrder); //排序
- if (!(tabModel->select()))//查询数据
- {
- QMessageBox::critical(this, "错误信息",
- "打开数据表错误,错误信息\n"+tabModel->lastError().text(),
- QMessageBox::Ok,QMessageBox::NoButton);
- return;
- }
复制代码
- 创建数据库模型且指定命据库的连接
通过往 QSqlTableModel 构造函数中传入参数来指定命据库连接
构造函数为:
- QSqlTableModel::QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())
复制代码 在本案例中为
- tabModel=new QSqlTableModel(this,DB);//数据表
复制代码 - 使用 setTable() 函数来指定命据表,此时不会立即读取记录,但会提取字段信息
- [virtual] void QSqlTableModel::setTable(const QString &tableName)
复制代码 在本案例中为
- tabModel->setTable("employee"); //设置数据表
复制代码 - 使用 setSort() 函数设置排序字段与排序规则,需调用 select() 函数才生效
- [virtual] void QSqlTableModel::setSort(int column, Qt::SortOrder order)
复制代码
- 第一个参数 column 是排序字段的列号
- 第二个参数 order 是枚举范例Qt::SortOrder,表示排序方式,此中,Qt::AscendingOrder表示升序,Qt:escendingOrder表示降序
在本案例中为
- tabModel->setSort(tabModel->fieldIndex("empNo"),Qt::AscendingOrder); //排序
复制代码
- 使用 setEditStrategy() 函数用于设置编辑计谋
- [virtual] void QSqlTableModel::setEditStrategy(QSqlTableModel::EditStrategy strategy)
复制代码
- 参数 strategy 是枚举范例 QSqlTableModel::EditStrategy,各取值的意义如下:
- QSqlTableModel::OnFieldChange:字段值厘革时立即更新到数据库
- QSqlTableModel::OnRowChange:当前行(记录)变更时更新到数据库
- QSqlTableModel::OnManualSubmit:所有修改暂时缓存,手动调用 submitAll() 生存所有修改,或调用 revertAll() 函数取消所有未生存的修改。
- 使用 select() 函数查询数据表的数据,并使用设置的排序和过滤规则
- [virtual slot] bool QSqlTableModel::select()
复制代码 在本案例中为:
表头设置:
使用 setHeaderData() 函数设置表头,即设置数据库表的字段在 tableView 中表现时的字段名称。为此,将每个字段的表现设置为相应的中文标题。
- [override virtual] bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole)
复制代码
- 参数 section 是字段的序号,通过 fieldIndex() 函数可以获取某个字段名在数据模型里的序号
- 参数 orientation 是字段的方向,此中,Qt::Horizontal表示是水平方向标题,Qt::Vertical表示是竖直方向标题
- 参数 value 是要设置的值
表头设置部分代码为:
- tabModel->setHeaderData(tabModel->fieldIndex("empNo"),Qt::Horizontal,"工号");
- tabModel->setHeaderData(tabModel->fieldIndex("Name"),Qt::Horizontal,"姓名");
- tabModel->setHeaderData(tabModel->fieldIndex("Gender"),Qt::Horizontal,"性别");
- tabModel->setHeaderData(tabModel->fieldIndex("Height"),Qt::Horizontal,"身高");
- tabModel->setHeaderData(tabModel->fieldIndex("Birthday"),Qt::Horizontal,"出生日期");
- tabModel->setHeaderData(tabModel->fieldIndex("Mobile"),Qt::Horizontal,"手机");
- tabModel->setHeaderData(tabModel->fieldIndex("Province"),Qt::Horizontal,"省份");
- tabModel->setHeaderData(tabModel->fieldIndex("City"),Qt::Horizontal,"城市");
- tabModel->setHeaderData(tabModel->fieldIndex("Department"),Qt::Horizontal,"部门");
- tabModel->setHeaderData(tabModel->fieldIndex("Education"),Qt::Horizontal,"学历");
- tabModel->setHeaderData(tabModel->fieldIndex("Salary"),Qt::Horizontal,"工资");
- tabModel->setHeaderData(tabModel->fieldIndex("Memo"),Qt::Horizontal,"备注"); //这两个字段不再tableView中显示
- tabModel->setHeaderData(tabModel->fieldIndex("Photo"),Qt::Horizontal,"照片");
复制代码 创建选择模型及信号的作用:
选择模型的作用是当用户在 TableView 组件上操作时,获取当前选择的行 、列信息,而且在选择的单位格厘革时发射 currentChanged() 信号,在当前行厘革时发射 currentRowChanged() 信号。
- theSelection=new QItemSelectionModel(tabModel);//关联选择模型
- //theSelection当前项变化时触发currentChanged信号
- connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
- //选择行变化时
- connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));
复制代码 对应的槽函数为:
- void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
- {//更新actPost和actCancel 的状态
- Q_UNUSED(current);
- Q_UNUSED(previous);
- ui->actSubmit->setEnabled(tabModel->isDirty()); //有未保存修改时可用
- ui->actRevert->setEnabled(tabModel->isDirty());
- }
- void MainWindow::on_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
- {
- Q_UNUSED(previous);
- // 行切换时的状态控制
- ui->actRecDelete->setEnabled(current.isValid());
- ui->actPhoto->setEnabled(current.isValid());
- ui->actPhotoClear->setEnabled(current.isValid());
- if (!current.isValid())
- {
- ui->dbLabPhoto->clear(); //清除图片显示
- return;
- }
- dataMapper->setCurrentIndex(current.row()); //更新数据映射到当前行,使界面上的编辑框、下拉列表框等与字段关联的界面组件显示当前记录的内容
- int curRecNo=current.row();//获取行号
- QSqlRecord curRec=tabModel->record(curRecNo); //获取当前记录
- if (curRec.isNull("Photo")) //图片字段内容为空
- ui->dbLabPhoto->clear();
- else
- {
- QByteArray data=curRec.value("Photo").toByteArray();
- QPixmap pic;
- pic.loadFromData(data);
- ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));
- }
- }
复制代码 tableView的设置:
用 QTableView 组件表现 tabModel 的表格数据内容时,需要设置其数据模型和关联选择模型,而且将 “Memo” 和 “Photo” 两个字段的列设置为隐藏,由于在表格里难以表现备注文件和图片。
- ui->tableView->setModel(tabModel);//设置数据模型
- ui->tableView->setSelectionModel(theSelection); //设置选择模型
- ui->tableView->setColumnHidden(tabModel->fieldIndex("Memo"),true);//隐藏列
- ui->tableView->setColumnHidden(tabModel->fieldIndex("Photo"),true);//隐藏列
复制代码 自界说基于 QComboBox 的代理组件类 QWComboBoxDelegate,组件类中有一个函数 setItems() ,用于初始化下拉列表框和设置是都可以编辑,
qwcombocoxdelegate.h:
- #ifndef QWCOMBOBOXDELEGATE_H
- #define QWCOMBOBOXDELEGATE_H
- #include <QStyledItemDelegate>
- #include <QComboBox>
- class QWComboBoxDelegate : public QStyledItemDelegate
- {
- Q_OBJECT
- private:
- QStringList m_ItemList;//选择列表
- bool m_isEdit; //是否可编辑
- public:
- QWComboBoxDelegate(QObject *parent=0);
- void setItems(QStringList items, bool isEdit);//初始化设置列表内容,是否可编辑
- //自定义代理组件必须继承以下4个函数
- QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
- const QModelIndex &index) const Q_DECL_OVERRIDE;
- void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
- void setModelData(QWidget *editor, QAbstractItemModel *model,
- const QModelIndex &index) const Q_DECL_OVERRIDE;
- void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
- const QModelIndex &index) const Q_DECL_OVERRIDE;
- };
- #endif // QWCOMBOBOXDELEGATE_H
复制代码 qwcombocoxdelegate.cpp:
- #include "qwcomboboxdelegate.h"
- #include <QComboBox>
- QWComboBoxDelegate::QWComboBoxDelegate(QObject *parent):QStyledItemDelegate(parent)
- {
- }
- void QWComboBoxDelegate::setItems(QStringList items, bool isEdit)
- {
- m_ItemList=items;
- m_isEdit=isEdit;
- }
- QWidget *QWComboBoxDelegate::createEditor(QWidget *parent,
- const QStyleOptionViewItem &option, const QModelIndex &index) const
- {
- Q_UNUSED(option);
- Q_UNUSED(index);
- QComboBox *editor = new QComboBox(parent);
- for (int i=0;i<m_ItemList.count();i++) //从字符串列表初始下拉列表
- editor->addItem(m_ItemList.at(i));
- editor->setEditable(m_isEdit); //是否可编辑
- return editor;
- }
- void QWComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
- {
- QString str = index.model()->data(index, Qt::EditRole).toString();
- QComboBox *comboBox = static_cast<QComboBox*>(editor);
- comboBox->setCurrentText(str);
- }
- void QWComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
- {
- QComboBox *comboBox = static_cast<QComboBox*>(editor);
- QString str = comboBox->currentText();
- model->setData(index, str, Qt::EditRole);
- }
- void QWComboBoxDelegate::updateEditorGeometry(QWidget *editor,
- const QStyleOptionViewItem &option, const QModelIndex &index) const
- {
- Q_UNUSED(index);
- editor->setGeometry(option.rect);
- }
复制代码 创建多个代理组件实例,分别用于“性别” 和 “部分” 两个字段。
- //tableView上为“性别”和“部门”两个字段设置自定义代理组件
- QStringList strList;
- strList<<"男"<<"女";
- bool isEditable=false;
- delegateSex.setItems(strList,isEditable);
- ui->tableView->setItemDelegateForColumn(
- tabModel->fieldIndex("Gender"),&delegateSex); //Combbox选择型
- strList.clear();
- strList<<"销售部"<<"技术部"<<"生产部"<<"行政部";
- isEditable=true;
- delegateDepart.setItems(strList,isEditable);
- ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("Department"),&delegateDepart); //Combbox选择型
复制代码 数据映射:
QDataWidgetMapper 用于建立界面组件与数据模型之间的映射,可以将界面的 QLineEdit、QCombobox 等组件与数据模型的一个字段关联起来。当数据模型关联的字段内容发生厘革时,自动更新组件的表现内容。
- //创建界面组件与数据模型的字段之间的数据映射
- dataMapper= new QDataWidgetMapper();
- dataMapper->setModel(tabModel);//设置数据模型
- dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);//
- // dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); //含有外键的
- //界面组件与tabModel的具体字段之间的联系
- dataMapper->addMapping(ui->dbSpinEmpNo,tabModel->fieldIndex("empNo"));
- dataMapper->addMapping(ui->dbEditName,tabModel->fieldIndex("Name"));
- dataMapper->addMapping(ui->dbComboSex,tabModel->fieldIndex("Gender"));
- dataMapper->addMapping(ui->dbSpinHeight,tabModel->fieldIndex("Height"));
- dataMapper->addMapping(ui->dbEditBirth,tabModel->fieldIndex("Birthday"));
- dataMapper->addMapping(ui->dbEditMobile,tabModel->fieldIndex("Mobile"));
- dataMapper->addMapping(ui->dbComboProvince,tabModel->fieldIndex("Province"));
- dataMapper->addMapping(ui->dbEditCity,tabModel->fieldIndex("City"));
- dataMapper->addMapping(ui->dbComboDep,tabModel->fieldIndex("Department"));
- dataMapper->addMapping(ui->dbComboEdu,tabModel->fieldIndex("Education"));
- dataMapper->addMapping(ui->dbSpinSalary,tabModel->fieldIndex("Salary"));
- dataMapper->addMapping(ui->dbEditMemo,tabModel->fieldIndex("Memo"));
- // dataMapper->addMapping(ui->dbPhoto,tabModel->fieldIndex("Photo")); //图片无法直接映射
- dataMapper->toFirst();//移动到首记录
- getFieldNames();//获取字段名称列表,填充ui->groupBoxSort组件
- //更新actions和界面组件的使能状态
- ui->actOpenDB->setEnabled(false);
- ui->actRecAppend->setEnabled(true);
- ui->actRecInsert->setEnabled(true);
- ui->actRecDelete->setEnabled(true);
- ui->actScan->setEnabled(true);
- ui->groupBoxSort->setEnabled(true);
- ui->groupBoxFilter->setEnabled(true);
复制代码
- setModel() 函数–设置关联的数据模型
- void QDataWidgetMapper::setModel(QAbstractItemModel *model)
复制代码 用于设置 QDataWidgetMapper 将要使用的数据模型。参数 model 是一个指向 QAbstractItemModel 范例的指针
- setSubmitPolicy() 函数–设置数据提交计谋
- void setSubmitPolicy(QDataWidgetMapper::SubmitPolicy policy)
复制代码 其参数policy是一个枚举范例QDataWidgetMapper::SubmitPolicy。取值如下:
- QDataWidgetMapper::AutoSubmit:自动,行切换时将自动提交修改。
- QDataWidgetMapper::ManualSubmit:手动,需调用 submit() 方法,手工提交当前记录的修改。
- addMapping() 函数 – 用于设置界面组件与数据模型的列的映射,这种映射关系使得控件的值可以与数据模型中的特定项关联起来
- void QDataWidgetMapper::addMapping(QWidget *widget, int section)
复制代码 参数 widget 是指向 UI 控件的指针,section 指定了数据模型中的列(如果方向是水平的)或行(如果方向是垂直的)
- setCurrentIndex() 函数 – 将当前行数据映射到界面组件, 使界面上的编辑框、下拉列表框等与字段关联的界面组件表现当前记录的内容
- virtual void setCurrentIndex(int index)
复制代码 例如:
- dataMapper->setCurrentIndex(current.row()); //更新当前行数据映射
复制代码 - setCurrentModelIndex() 函数–当用户在视图中选择不同的行或列时,自动更新与之关联的表单或控件的数据。
- [slot] void QDataWidgetMapper::setCurrentModelIndex(const QModelIndex &index)
复制代码 - revert() 和 submit() 函数用于手工取消或提交当前记录的修改。
- toFirst()、toPrevious()、toNext() 和 toLast() 函数用于在记录间移动
如:toFirst()函数用于移动到首记录
获取数据表的所有字段名称:
使用不带参数的 record() 函数获取数据表的所有字段名称,并添补到排序的下拉列表框中
- void MainWindow::getFieldNames()
- { //获取所有字段名称
- QSqlRecord emptyRec=tabModel->record();//获取空记录,只有字段名
- for (int i=0;i<emptyRec.count();i++)
- ui->comboFields->addItem(emptyRec.fieldName(i));
- }
复制代码 4.添加、插入与删除记录
使用 insertRow() 函数在数据模型的 row 行前面插入一行记录,如果 row 大于或即是数据模型的总行数,则在末了添加一行记录。末了,选中刚插入的那一行记录。
- 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);//设置刚插入的行为当前选择行
- int currow=curIndex.row(); //获得当前行
- tabModel->setData(tabModel->index(currow,0),2000+tabModel->rowCount()); //自动生成编号
- tabModel->setData(tabModel->index(currow,2),"男");
- // 插入行时设置缺省值,需要在primeInsert()信号里去处理
- }
- void MainWindow::on_actRecInsert_triggered()
- {//插入记录
- QModelIndex curIndex=ui->tableView->currentIndex();
- tabModel->insertRow(curIndex.row(),QModelIndex());
- theSelection->clearSelection();//清除已有选择
- theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
- }
复制代码 使用 removeRow() 函数删除选中的那一行记录。
- void MainWindow::on_actRecDelete_triggered()
- {//删除当前记录
- QModelIndex curIndex=theSelection->currentIndex();//获取当前选择单元格的模型索引
- tabModel->removeRow(curIndex.row()); //删除最后一行
- }
复制代码 在插入或删除记录操作,未提交生存之前, tableView 的左侧表头会以标记表示记录编辑状态,"*"表示新插入的记录,”!” 表示删除的记录 。在生存或取消修改,这些标记就消失,删除的记录行也从 tableView 里删除。
5.生存与取消修改
在打开数据表初始化时,设置数据模型的编辑计谋为 OnManualSubmit,即手动提交修改。当数据模型的数据被修改后,不管是直接修改字段值,照旧插入或删除记录,在未提交修改前,QSqlTableModel::isDirty() 函数返回 true,就是使用这个函数在槽函数 on_currentChanged() 里设置 ”生存修改“和”取消修改“ 按钮的使能状态。
使用 submitAll() 函数用于将数据表所有未提交的修改生存到数据库中;使用 revertAll() 函数来取消所有修改。
- void MainWindow::on_actRevert_triggered()
- {//取消修改
- tabModel->revertAll();
- ui->actSubmit->setEnabled(false);
- ui->actRevert->setEnabled(false);
- }
- 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);
- }
- }
复制代码 6.设置和清除照片
设置照片功能是用文件对话框选择一个图片文件,读取文件内容到 QByteArray 范例的变量data里,获取当前记录到变量 curRec 后,用 QSqlRecord 的 setValue() 函数为 Photo 字段设置数据为 data,然后用 setRecord() 函数更新当前记录的数据到数据模型,并在界面组件上表现。
留意:这里的更新只是更新到数据模型,并没有更新到数据库。
- void MainWindow::on_actPhoto_triggered()
- {
- //设置照片
- QString aFile=QFileDialog::getOpenFileName(this,"选择图片文件","","照片(*.jpg)");
- if (aFile.isEmpty())
- return;
- QByteArray data;
- QFile* file=new QFile(aFile); //fileName为二进制数据文件名
- file->open(QIODevice::ReadOnly);
- data = file->readAll();
- file->close();
- int curRecNo=theSelection->currentIndex().row();
- QSqlRecord curRec=tabModel->record(curRecNo); //获取当前记录
- curRec.setValue("Photo",data); //设置字段数据
- tabModel->setRecord(curRecNo,curRec);
- QPixmap pic;
- pic.load(aFile); //在界面上显示
- ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->width()));
- }
复制代码 清楚照片的功能是获取当前记录到变量 curRec 后,调用 setNull () 函数将 Photo 字段设置为 NULL,就是清除了字段的内容,然后更新记录到数据模型,并清除界面组件的表现。
- void MainWindow::on_actPhotoClear_triggered()
- {
- int curRecNo=theSelection->currentIndex().row();
- QSqlRecord curRec=tabModel->record(curRecNo); //获取当前记录
- curRec.setNull("Photo");//设置为空值
- tabModel->setRecord(curRecNo,curRec);
- ui->dbLabPhoto->clear();
- }
复制代码 7.数据记录的遍历
使用 record(int index) 函数获取每一行记录,并对该行记录的值举行修改。
- void MainWindow::on_actScan_triggered()
- {//涨工资,记录遍历
- if (tabModel->rowCount()==0)
- return;
- for (int i=0;i<tabModel->rowCount();i++)
- {
- QSqlRecord aRec=tabModel->record(i); //获取当前记录
- float salary=aRec.value("Salary").toFloat();
- salary=salary*1.1;
- aRec.setValue("Salary",salary);
- tabModel->setRecord(i,aRec);
- }
- // 索引方式刷新记录,速度一样
- // float salary;
- // for (int i=0;i<tabModel->rowCount();i++)
- // {
- // salary=tabModel->data(tabModel->index(i,10)).toFloat();
- // salary=salary*1.1;
- // tabModel->setData(tabModel->index(i,10),salary);
- // }
- if (tabModel->submitAll())
- QMessageBox::information(this, "消息", "涨工资计算完毕",
- QMessageBox::Ok,QMessageBox::NoButton);
- }
复制代码 8.记录排序
使用 setSort() 函数设置数据表根据某个字段按照升序或降序排列,实际上就是设置 SQL 语句里的 ORDER BY 子句。在调用 setSort() 函数设置排序规则后,需要调用 QSqITableModel::select() 重新读取数据表的数据才会使排序规则生效。
- void MainWindow::on_comboFields_currentIndexChanged(int index){//选择字段举行排序 if (ui->radioBtnAscend->isChecked()) tabModel->setSort(index,Qt::AscendingOrder); else tabModel->setSort(index,Qt::DescendingOrder); tabModel->select()
- ;}void MainWindow::on_radioBtnAscend_clicked(){//升序 tabModel->setSort(ui->comboFields->currentIndex(),Qt::AscendingOrder); tabModel->select()
- ;}void MainWindow::on_radioBtnDescend_clicked(){//降序 tabModel->setSort(ui->comboFields->currentIndex(),Qt::DescendingOrder); tabModel->select()
- ;}
复制代码 9.记录过滤
使用 setFilter() 函数设置记录的过滤条件,实际上就是设置 SQL 语句里的 WHERE 子句。调用 setFilter() 后无需调用 select() 函数就可以立即刷新记录,若要取消过滤条件,只需在 setFilter() 函数里传递一个空字符串。
- void MainWindow::on_radioBtnMan_clicked(){ tabModel->setFilter(" Gender='男' ");// tabModel->select()
- ;}void MainWindow::on_radioBtnWoman_clicked(){ tabModel->setFilter(" Gender='女' ");// tabModel->select()
- ;}void MainWindow::on_radioBtnBoth_clicked(){ tabModel->setFilter("");}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |