Qt5 學習參考資料之--QSqlTableModel
源部落格地址:http://www.qter.org/portal.php?mod=view&aid=57
導語
在上一篇我們講到只讀的QSqlQueryModel模型其實也可以實現編輯功能的,但是實現起來很麻煩。而QSqlTableModel提供了一個一次只能操作單個SQL表的讀寫模型,它是QSqlQuery的更高層次的替代品,可以瀏覽和修改獨立的SQL表,並且只需編寫很少的程式碼,而且不需要了解SQL語法。
環境:Windows 7 + Qt 5.8.0(包含QtCreator 4.2.1
正文
一、建立資料庫
1.新建Qt Widgets應用,專案名稱為tablemodel,基類為QMainWindow,類名MainWindow。
2.完成後開啟tablemodel.pro檔案,將第一行程式碼更改為:
- QT += coregui sql
複製程式碼
然後儲存檔案。
3.向專案中新增新的C++標頭檔案,名稱為connection.h。完成後將其內容更改如下:
- #ifndef CONNECTION_H
- #define CONNECTION_H
- #include <QSqlDatabase>
- #include <QSqlQuery>
- static bool createConnection()
- {
- QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
- db.setDatabaseName("database.db");
- if(!db.open()) return false;
- QSqlQuery query;
- query.exec("create table student (id int primary key, name vchar)");
- query.exec("insert into student values (0,'劉明')");
- query.exec("insert into student values (1,'陳剛')");
- query.exec("insert into student values (2,'王紅')");
- return true;
- }
- #endif // CONNECTION_H
複製程式碼
4.下面將main.cpp檔案更改如下:
- #include "mainwindow.h"
- #include <QApplication>
- #include "connection.h"
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- if(!createConnection())
- return 1;
- MainWindow w;
- w.show();
- return a.exec();
- }
複製程式碼
5.下面進入設計模式,向視窗上拖入Label、Push Button、Line Edit和Table View等部件,進行介面設計,效果如下圖所示。
6.完成後到mainwindow.h檔案中,先包含標頭檔案:
- #include <QSqlTableModel>
複製程式碼
然後新增私有物件:
- QSqlTableModel *model;
複製程式碼
7.到mainwindow.cpp,在建構函式新增如下程式碼:
- model = new QSqlTableModel(this);
- model->setTable("student");
- model->setEditStrategy(QSqlTableModel::OnManualSubmit);
- model->select(); //選取整個表的所有行
- //不顯示name屬性列,如果這時新增記錄,則該屬性的值新增不上
- // model->removeColumn(1);
- ui->tableView->setModel(model);
- //使其不可編輯
- // ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
複製程式碼
這裡建立一個QSqlTableModel後,只需使用setTable()來為其指定資料表,然後使用select()函式進行查詢,呼叫這兩個函式就等價於執行了“select * from student”這個SQL語句。這裡還可以使用setFilter()來指定查詢時的條件,在後面會看到這個函式的使用。在使用該模型以前,一般還要設定其編輯策略,它由QSqlTableModel::EditStrategy列舉型別定義,一共有三個值,如下圖所示。用來說明當資料庫中的值被編輯後,什麼情況下提交修改。
執行程式,效果如下圖所示。
可以看到,這個模型已經完全脫離了SQL語句,我們只需要執行select()函式就能查詢整張表。上面有兩行程式碼被註釋掉了,你可以取消註釋,測試一下它們的作用。
二、修改操作
1.我們進入“提交修改”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_clicked()
- {
- model->database().transaction(); //開始事務操作
- if (model->submitAll()) {
- model->database().commit(); //提交
- } else {
- model->database().rollback(); //回滾
- QMessageBox::warning(this, tr("tableModel"),
- tr("資料庫錯誤: %1")
- .arg(model->lastError().text()));
- }
- }
複製程式碼
這裡用到了事務操作,真正起提交操作的是model->submitAll()一句,它提交所有更改。
2.進入“撤銷修改”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_2_clicked()
- {
- model->revertAll();
- }
複製程式碼
3.在mainwindow.cpp檔案中包含標頭檔案:
- #include <QMessageBox>
- #include <QSqlError>
複製程式碼
4.現在執行程式,我們將“陳剛”改為“李強”,如果我們點選“撤銷修改”,那麼它就會重新改為“陳剛”,而當我們點選“提交修改”後它就會儲存到資料庫,此時再點選“撤銷修改”就修改不回來了。
可以看到,這個模型可以將所有修改先儲存到model中,只有當我們執行提交修改後,才會真正寫入資料庫。當然這也是因為我們在最開始設定了它的儲存策略:
- model->setEditStrategy(QSqlTableModel::OnManualSubmit);
複製程式碼
這裡的OnManualSubmit表明我們要提交修改才能使其生效。
三、查詢操作
1.進入“查詢”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_5_clicked()
- {
- QString name = ui->lineEdit->text();
- //根據姓名進行篩選
- model->setFilter(QString("name = '%1'").arg(name));
- //顯示結果
- model->select();
- }
複製程式碼
使用setFilter()函式進行關鍵字篩選,這個函式是對整個結果集進行查詢。
2.進入“顯示全表”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_6_clicked()
- {
- model->setTable("student"); //重新關聯表
- model->select(); //這樣才能再次顯示整個表的內容
- }
複製程式碼
為了再次顯示整個表的內容,我們需要再次關聯這個表。
3.下面執行程式,輸入一個姓名,點選“查詢”按鈕後,就可以顯示該記錄了。再點選“顯示全表”按鈕則返回。如下圖所示。
四、排序操作
分別進入“按id升序排序”和“按id降序排序”按鈕的單擊訊號槽,更改如下:
- // 升序
- void MainWindow::on_pushButton_7_clicked()
- {
- //id屬性即第0列,升序排列
- model->setSort(0, Qt::AscendingOrder);
- model->select();
- }
- // 降序
- void MainWindow::on_pushButton_8_clicked()
- {
- model->setSort(0, Qt::DescendingOrder);
- model->select();
- }
複製程式碼
這裡使用了setSort()函式進行排序,它有兩個引數,第一個引數表示按第幾個欄位排序,表頭從左向右,最左邊是第0個欄位,這裡就是id欄位。第二個引數是排序方法,有升序和降序兩種。執行程式,效果如下圖所示。
五、刪除操作
我們進入“刪除選中行”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_4_clicked()
- {
- //獲取選中的行
- int curRow = ui->tableView->currentIndex().row();
- //刪除該行
- model->removeRow(curRow);
- int ok = QMessageBox::warning(this,tr("刪除當前行!"),
- tr("你確定刪除當前行嗎?"),
- QMessageBox::Yes,QMessageBox::No);
- if(ok == QMessageBox::No)
- {
- model->revertAll(); //如果不刪除,則撤銷
- }
- else model->submitAll(); //否則提交,在資料庫中刪除該行
- }
複製程式碼
刪除行的操作會先儲存在model中,當我們執行了submitAll()函式後才會真正的在資料庫中刪除該行。這裡我們使用了一個警告框來讓使用者選擇是否真得要刪除該行。執行程式,效果如下圖所示。
我們單擊第二行,然後單擊“刪除選中行”按鈕,出現了警告框。這時你會發現,表中的第二行前面出現了一個小感嘆號,表明該行已經被修改了,但是還沒有真正在資料庫中修改,這時的資料有個學名叫髒資料(Dirty Data)。當我們按鈕“Yes”按鈕後資料庫中的資料就會被刪除,如果按下“No”,那麼更改就會取消。
六、插入操作
我們進入“新增記錄”按鈕的單擊訊號槽,更改如下:
- void MainWindow::on_pushButton_3_clicked()
- {
- int rowNum = model->rowCount(); //獲得表的行數
- int id = 10;
- model->insertRow(rowNum); //新增一行
- model->setData(model->index(rowNum,0),id);
- //model->submitAll(); //可以直接提交
- }
複製程式碼
在表的最後新增一行,因為在student表中我們設定了id號是主鍵,所以這裡必須使用setData()函式給新加的行新增id欄位的值,不然新增行就不會成功。這裡可以直接呼叫submitAll()函式進行提交,也可以利用“提交修改”按鈕進行提交。執行程式,效果如下圖所示。
按下“新增記錄”按鈕後,就添加了一行,不過在該行的前面有個星號,如果我們按下“提交修改”按鈕,這個星號就會消失。當然,如果我們將上面程式碼裡的提交函式的註釋去掉,也就不會有這個星號了。
結語
可以看到這個模型很強大,而且完全脫離了SQL語句,就算你不怎麼懂資料庫知識,也可以利用它進行大部分常用的操作。我們也看到了,這個模型提供了緩衝區,可以先將修改儲存起來,當我們執行提交函式時,再去真正地修改資料庫。當然,這個模型比前面的模型更高階,前面講的所有操作,在這裡都能執行。