Qt實現(xiàn)SqlTableModel映射組件應(yīng)用小結(jié)
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點介紹SqlTableModule
組件的常用方法及靈活運用。
在多數(shù)情況下我們需要使用SQL的方法來維護(hù)數(shù)據(jù)庫,但此方式相對較為繁瑣對于表格等數(shù)據(jù)的編輯非常不友好,在Qt
中提供了QSqlTableModel
模型類,它為開發(fā)者提供了一種直觀的方式來與數(shù)據(jù)庫表格進(jìn)行交互。通過使用該組件可以將數(shù)據(jù)庫與特定的組件進(jìn)行關(guān)聯(lián),一旦關(guān)聯(lián)被建立那么用戶的所有操作均可以使用函數(shù)的方式而無需使用SQL
語句,該特性有點類似于ORM
對象關(guān)系映射機(jī)制。
在接下來的章節(jié)中,我們將學(xué)習(xí)如何配置 QSqlTableModel
、與數(shù)據(jù)庫進(jìn)行交互、實現(xiàn)數(shù)據(jù)的動態(tài)顯示和編輯,首先讀者應(yīng)繪制好UI界面,本次案例界面稍顯復(fù)雜,讀者可自行完成如下案例的繪制;
以下是 QSqlTableModel
類的一些常用方法,包括方法名、參數(shù)以及簡要說明。這里列舉的方法并非全部,而是一些常見的方法,更詳細(xì)的信息可以參考官方文檔。
方法 | 描述 |
---|---|
QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()) | 構(gòu)造函數(shù),創(chuàng)建 QSqlTableModel 對象。 |
setTable(const QString &tableName) | 設(shè)置要操作的數(shù)據(jù)庫表名。 |
select() | 執(zhí)行查詢操作,從數(shù)據(jù)庫中獲取數(shù)據(jù)。 |
rowCount(const QModelIndex &parent = QModelIndex()) const | 返回模型中的行數(shù)。 |
columnCount(const QModelIndex &parent = QModelIndex()) const | 返回模型中的列數(shù)。 |
record(int row) | 返回指定行的記錄。 |
setFilter(const QString &filter) | 設(shè)置用于過濾數(shù)據(jù)的條件。 |
setSort(int column, Qt::SortOrder order) | 設(shè)置排序的列和排序規(guī)則。 |
setEditStrategy(QSqlTableModel::EditStrategy strategy) | 設(shè)置編輯策略,決定何時將修改提交到數(shù)據(jù)庫。 |
setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) | 設(shè)置模型中指定索引的數(shù)據(jù)。 |
data(const QModelIndex &index, int role = Qt::DisplayRole) const | 返回模型中指定索引的數(shù)據(jù)。 |
addRecord(const QSqlRecord &values) | 添加一條記錄到模型中。 |
removeRow(int row) | 從模型中刪除指定行。 |
insertRecord(int row, const QSqlRecord &record) | 在指定位置插入一條記錄。 |
submitAll() | 提交所有對模型的修改到數(shù)據(jù)庫。 |
revertAll() | 撤銷對模型的所有修改。 |
setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) | 設(shè)置表頭數(shù)據(jù)。 |
indexInQuery(const QSqlQuery &query) const | 返回查詢中模型的索引。 |
這些方法提供了對 QSqlTableModel
進(jìn)行數(shù)據(jù)操作、過濾、排序以及提交修改的基本手段。通過這些方法,可以在應(yīng)用程序中方便地操作數(shù)據(jù)庫表格的數(shù)據(jù)。
1.1 初始化組件
首先我們來看一下MainWindow
初始化部分是如何工作的,主要實現(xiàn)了以下功能:
打開數(shù)據(jù)庫
首先使用SQLite
數(shù)據(jù)庫驅(qū)動連接名為"database.db"
的數(shù)據(jù)庫文件。如果數(shù)據(jù)庫連接失敗,函數(shù)直接返回。接著通過新建一個QSqlTableModel
類,并調(diào)用setTable
來打開一個數(shù)據(jù)表,設(shè)置編輯策略為 OnManualSubmit
,即手動提交修改。并通過setSort
函數(shù)來設(shè)置排序方式為根據(jù)ID
字段升序Qt::AscendingOrder
排列。
DB = QSqlDatabase::addDatabase("QSQLITE"); DB.setDatabaseName("./database.db"); if (!DB.open()) { return; } tabModel = new QSqlTableModel(this, DB); tabModel->setTable("Student"); tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); tabModel->setSort(tabModel->fieldIndex("id"), Qt::AscendingOrder); if (!(tabModel->select())) { return; }
設(shè)置字段名稱
此處我們數(shù)據(jù)庫中有6個字段,也就需要設(shè)置數(shù)據(jù)庫字段與表格關(guān)聯(lián),如下則是對字段的動態(tài)關(guān)聯(lián)。
tabModel->setHeaderData(tabModel->fieldIndex("id"),Qt::Horizontal,"Uid"); tabModel->setHeaderData(tabModel->fieldIndex("name"),Qt::Horizontal,"Uname"); tabModel->setHeaderData(tabModel->fieldIndex("sex"),Qt::Horizontal,"Usex"); tabModel->setHeaderData(tabModel->fieldIndex("age"),Qt::Horizontal,"Uage"); tabModel->setHeaderData(tabModel->fieldIndex("mobile"),Qt::Horizontal,"Umobile"); tabModel->setHeaderData(tabModel->fieldIndex("city"),Qt::Horizontal,"Ucity");
關(guān)聯(lián)選擇模型和數(shù)據(jù)模型
通過創(chuàng)建 QItemSelectionModel
對象 theSelection
并關(guān)聯(lián)到 tabModel
模型,將數(shù)據(jù)模型和選擇模型關(guān)聯(lián)到 ui->tableView
,并設(shè)置選擇模式為行選擇模式。
theSelection = new QItemSelectionModel(tabModel); ui->tableView->setModel(tabModel); ui->tableView->setSelectionModel(theSelection); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
創(chuàng)建數(shù)據(jù)映射
創(chuàng)建 QDataWidgetMapper
對象 dataMapper
,將數(shù)據(jù)模型設(shè)置為 tabModel
,設(shè)置提交策略為 AutoSubmit
,即自動提交修改。并將 “name” 字段映射到 ui->lineEdit_name
,默認(rèn)選中第一條映射記錄。
dataMapper = new QDataWidgetMapper(); dataMapper->setModel(tabModel); dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit); dataMapper->addMapping(ui->lineEdit_name, tabModel->fieldIndex("name")); dataMapper->toFirst();
信號和槽連接
當(dāng)選擇模型中的當(dāng)前行改變時,連接到槽函數(shù) on_currentRowChanged
,用于在右側(cè)編輯框中輸出當(dāng)前選擇的記錄。
connect(theSelection, SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), this, SLOT(on_currentRowChanged(QModelIndex, QModelIndex)));
這個槽函數(shù)的實現(xiàn)如下所示,當(dāng)行被點擊后執(zhí)行獲取name/mobile
字段,并放入映射數(shù)據(jù)集中的lineEdit
編輯框中,使其能夠動態(tài)的顯示數(shù)據(jù)列表。
void MainWindow::on_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_UNUSED(previous); dataMapper->setCurrentIndex(current.row()); // 更細(xì)數(shù)據(jù)映射的行號 int curRecNo=current.row(); // 獲取行號 QSqlRecord curRec=tabModel->record(curRecNo); // 獲取當(dāng)前記錄 QString uname = curRec.value("name").toString(); // 取出數(shù)據(jù) QString mobile = curRec.value("mobile").toString(); ui->lineEdit_name->setText(uname); // 設(shè)置到編輯框 ui->lineEdit_mobile->setText(mobile); }
最后在UI文件的底部有一個comboBox
組件,我們通過動態(tài)的查詢記錄,并將其賦值為第一個字段元素,其代碼如下所示;
QSqlRecord emptyRec=tabModel->record(); //獲取空記錄,只有字段名 for (int i=0;i<emptyRec.count();i++) { ui->comboBox->addItem(emptyRec.fieldName(i)); }
這段代碼實現(xiàn)了一個簡單的數(shù)據(jù)庫瀏覽和編輯界面,用戶可以通過表格展示的方式查看和編輯 “Student” 表格中的數(shù)據(jù)。當(dāng)程序運行后則可以看到如下圖所示的初始化部分;
1.2 數(shù)據(jù)處理
1.2.1 新增一條記錄
當(dāng)用戶按下on_pushButton_add_clicked
按鈕時,則會在表格中新增一條記錄,并設(shè)置默認(rèn)值的功能。下面是代碼的詳細(xì)解釋:
插入新行
在表格模型 tabModel
的末尾插入一行新記錄。QModelIndex()
是一個空的索引,表示插入到末尾。
tabModel->insertRow(tabModel->rowCount(), QModelIndex());
獲取最后一行的索引
獲取剛剛插入的行的索引,這里假設(shè) “name” 字段對應(yīng)的列索引是 1。
QModelIndex curIndex = tabModel->index(tabModel->rowCount() - 1, 1);
清空選擇項并設(shè)置新行為當(dāng)前選擇行
清空當(dāng)前選擇項,然后將剛剛插入的行設(shè)為當(dāng)前選擇行,并選擇該行。
theSelection->clearSelection(); theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
獲取當(dāng)前行號
獲取當(dāng)前行的行號。
int currow = curIndex.row();
設(shè)置自動生成的編號和默認(rèn)值
這段代碼的作用是在表格模型中插入一行新記錄,然后設(shè)置該行的默認(rèn)值,其中 “Uid” 字段會自動生成一個編號,“Usex” 字段默認(rèn)為 “M”,“Uage” 字段默認(rèn)為 “0”。
- 自動生成編號,假設(shè) “Uid” 字段對應(yīng)的列索引是 0。
- 將 “Usex” 字段設(shè)置為 “M”。
- 將 “Uage” 字段設(shè)置為 “0”。
tabModel->setData(tabModel->index(currow, 0), 1000 + tabModel->rowCount()); tabModel->setData(tabModel->index(currow, 2), "M"); tabModel->setData(tabModel->index(currow, 3), "0");
運行代碼,讀者可自行點擊增加記錄按鈕,每次點擊均會在表格中提供新行,當(dāng)讀者點擊on_pushButton_save_clicked
保存按鈕是則會調(diào)用submitAll()
該函數(shù)用于將數(shù)據(jù)提交到數(shù)據(jù)庫中存儲,如下圖所示;
1.2.2 插入一條記錄
在 TableView
中當(dāng)前選擇行的上方插入一行新記錄,并自動生成編號。下面是代碼的詳細(xì)解釋:
獲取當(dāng)前選擇行的索引和行號
獲取當(dāng)前選擇的單元格的索引和行號。
QModelIndex curIndex = ui->tableView->currentIndex(); int currow = curIndex.row();
在當(dāng)前行上方插入一行新記錄
在表格模型 tabModel
的當(dāng)前選擇行(curIndex.row()
)的上方插入一行新記錄。QModelIndex()
是一個空的索引,表示插入到指定行的上方。
tabModel->insertRow(curIndex.row(), QModelIndex());
設(shè)置自動生成的編號
自動生成編號,假設(shè) “Uid” 字段對應(yīng)的列索引是 0。
tabModel->setData(tabModel->index(currow, 0), 1000 + tabModel->rowCount());
清除已有選擇并將當(dāng)前選擇行設(shè)為新插入的行
清空已有選擇項,然后將當(dāng)前選擇行設(shè)為新插入的行,并選擇該行。
theSelection->clearSelection(); theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
當(dāng)上述代碼運行后則可以實現(xiàn)在指定行的上方插入一行新紀(jì)錄,并為新插入的行生成一個自增的編號,其效果如下圖所示;
對于刪除一條記錄來說則可以通過調(diào)用tabModel->removeRow(curIndex.row())
來實現(xiàn)刪除所選行,因為其實現(xiàn)起來很簡單此處就不再演示,具體實現(xiàn)細(xì)節(jié)可以參考附件。
1.2.3 修改表中記錄
如下所示代碼,用于批量修改表格中所有記錄的 “Uage” 字段值為某個固定的年齡。下面是代碼的詳細(xì)解釋:
檢查是否有記錄
如果表格中沒有記錄,則直接返回,不執(zhí)行后續(xù)的批量修改操作。
if (tabModel->rowCount() == 0) return;
循環(huán)遍歷每一行記錄并修改年齡
首先使用 tabModel->record(i)
獲取表格模型中的第 i
行記錄,接著使用 ui->lineEdit->text()
獲取用戶在 QLineEdit
中輸入的文本,作為新的年齡值,并通過 aRec.setValue("age", ...)
設(shè)置 “age” 字段的新值,最后使用 tabModel->setRecord(i, aRec)
將修改后的記錄設(shè)置回表格模型中的相應(yīng)行。
for (int i = 0; i < tabModel->rowCount(); i++) { QSqlRecord aRec = tabModel->record(i); // 獲取當(dāng)前記錄 aRec.setValue("age", ui->lineEdit->text()); // 設(shè)置數(shù)據(jù),使用 QLineEdit 中的文本作為新的年齡值 tabModel->setRecord(i, aRec); // 將修改后的記錄設(shè)置回表格模型中的相應(yīng)行 }
提交修改
使用 tabModel->submitAll()
提交對表格模型的所有修改,將修改保存到數(shù)據(jù)庫中。
tabModel->submitAll();
上述代碼實現(xiàn)了一個簡單的批量修改操作,將表格中所有記錄的 “Uage” 字段值設(shè)置為用戶在 QLineEdit
中輸入的年齡值。請注意,這里沒有對輸入的年齡值進(jìn)行驗證,確保輸入的是合法的數(shù)字。在實際應(yīng)用中,可能需要添加一些輸入驗證和錯誤處理的邏輯。
1.2.4 表記錄的排序
升序與降序排列
對表中記錄的排序可以使用模型提供的setSort
函數(shù)來實現(xiàn),通過對該字段第二個參數(shù)設(shè)置為Qt::AscendingOrder
則是升序排序,反之如果設(shè)置為Qt::DescendingOrder
則為降序排序。
如下所示代碼用于根據(jù)用戶選擇的字段對表格進(jìn)行排序,并重新執(zhí)行查詢以更新表格數(shù)據(jù)。下面是代碼的詳細(xì)解釋:
ui->comboBox->currentIndex()
獲取用戶在QComboBox
中選擇的字段的索引。Qt::AscendingOrder
表示升序排序。tabModel->select()
執(zhí)行對數(shù)據(jù)庫的查詢操作,重新獲取數(shù)據(jù)并應(yīng)用排序。
// 升序排序 tabModel->setSort(ui->comboBox->currentIndex(), Qt::AscendingOrder); // 降序排序 tabModel->setSort(ui->comboBox->currentIndex(),Qt::DescendingOrder); // 刷新查詢 tabModel->select();
上述代碼的作用是根據(jù)用戶在下拉框中選擇的字段進(jìn)行升序或降序排序,并將排序后的結(jié)果重新加載到表格中。在使用這段代碼之前,用戶需要在 QComboBox
中選擇一個字段,作為排序的依據(jù)。以升序排序為例,輸出效果如下圖所示;
到此這篇關(guān)于Qt實現(xiàn)SqlTableModel映射組件應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)Qt SqlTableModel映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別
本文主要介紹了C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08詳解C語言的exp()函數(shù)和ldexp()函數(shù)以及frexp()函數(shù)
這篇文章主要介紹了詳解C語言的exp()函數(shù)和ldexp()函數(shù)以及frexp()函數(shù),注意這三個函數(shù)雖然看起來相似但實際功能卻大相徑庭!需要的朋友可以參考下2015-08-08C語言實現(xiàn)順序表的基本操作指南(注釋很詳細(xì))
線性表是最簡單的數(shù)據(jù)結(jié)構(gòu),而順序表又是最簡單的線性表,其基本思想是用一段地址連續(xù)的儲存單元依次存儲線性表的數(shù)據(jù)元素,下面這篇文章主要給大家介紹了關(guān)于C語言實現(xiàn)順序表的基本操作,需要的朋友可以參考下2021-10-10