本文章原創於www.yafeilinux.com 轉載請註明出處。
在上一篇我們講到唯讀QSqlQueryModel也可以使其可編輯,但是很麻煩。Qt提供了操作單表的QSqlTableModel,如果我們需要對錶的內容進行修改,那麼我們就可以直接使用這個類。
QSqlTableModel,該類提供了一個可讀寫單張SQL表的可編輯資料模型。我們下面就對其的幾個常用功能進行介紹,分別是修改,插入,刪除,查詢,和排序。
在開始講之前,我們還是建立Qt4 Gui Application工程,我這裡工程名為tableModel ,然後選中QtSql模組,Base class選QWidget。工程建好後,添加C++ Header File ,命名為database.h,更改其內容如下:
#ifndef DATABASE_H
#define DATABASE_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QObject>
static bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase(“QSQLITE”);
db.setDatabaseName(“database.db”);
if(!db.open()) return false;
QSqlQuery query;
query.exec(QObject::tr(“create table student (id int primary key, name vchar)”));
query.exec(QObject::tr(“insert into student values (0,’劉明’)”));
query.exec(QObject::tr(“insert into student values (1,’陳剛’)”));
query.exec(QObject::tr(“insert into student values (2,’王紅’)”));
return true;
}
#endif // DATABASE_H
為了在資料庫中能使用中文,我們使用了QObject類的tr()函數。而在下面的main()函數中我們也需要添加相應的代碼來支援中文。
然後將main.cpp的檔案更改如下:
#include <QtGui/QApplication>
#include “widget.h”
#include “database.h”
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
if(!createConnection())
return 1;
Widget w;
w.show();
return a.exec();
}
下面我們開啟widget.ui,設計介面如下:
其中的組件有Table View 和 Line Edit,其餘是幾個按鈕組件。
然後在widget.h中加入標頭檔: #include <QSqlTableModel>
在private中聲明對象:QSqlTableModel *model;
因為我們要在不同的函數中使用model對象,所以我們在這裡聲明它。
我們到widget.cpp檔案中的建構函式裡添加如下代碼:
model = new QSqlTableModel(this);
model->setTable(“student”);
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select(); //選取整個表的所有行
// model->removeColumn(1); //不顯示name屬性列,如果這時添加記錄,則該屬性的值添加不上
ui->tableView->setModel(model);
// ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); //使其不可編輯
此時運行程式,效果如下:
可以看到,這個模型已經完全脫離了SQL語句,我們只需要執行select()函數就能查詢整張表。上面有兩行代碼被注釋掉了,你可以取消注釋,測試一下它們的作用。
第一,修改操作。
1.我們進入“提交修改”按鈕的單擊事件槽函數,修改如下:
void Widget::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 Widget::on_pushButton_2_clicked() //撤銷修改
{
model->revertAll();
}
它只有簡單的一行代碼。
我們需要在widget.cpp檔案中添加標頭檔:
#include <QMessageBox>
#include <QSqlError>
此時運行程式,效果如下:
我們將“陳剛”改為“李強”,如果我們點擊“撤銷修改”,那麼它就會重新改為“陳剛”,而當我們點擊“提交修改”後它就會儲存到資料庫,此時再點擊“撤銷修改”就修改不回來了。
可以看到,這個模型可以將所有修改先儲存到model中,只有當我們執行提交修改後,才會真正寫入資料庫。當然這也是因為我們在最開始設定了它的儲存策略:
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
OnManualSubmit表明我們要提交修改才能使其生效。
第二,查詢操作。
1.我們進入“查詢”按鈕的單擊事件槽函數,更改如下:
void Widget::on_pushButton_7_clicked() //查詢
{
QString name = ui->lineEdit->text();
model->setFilter(QObject::tr(“name = ‘%1′”).arg(name)); //根據姓名進行篩選
model->select(); //顯示結果
}
我們使用setFilter()函數進行關鍵字篩選,這個函數是對整個結果集進行查詢。為了使用變數,我們使用了QObject類的tr()函數。
2.我們進入“返回全表”按鈕的單擊事件槽函數,更改如下:
void Widget::on_pushButton_8_clicked() //返回全表
{
model->setTable(“student”); //重新關聯表
model->select(); //這樣才能再次顯示整個表的內容
}
為了再次顯示整個表的內容,我們需要再次關聯這個表。
運行效果如下:
我們輸入一個姓名,點擊“查詢”按鈕後,就可以顯示該記錄了。再點擊“返回全表”按鈕則返回。
第三,排序操作。
我們分別進入“按id升序排列”和“按id降序排列”按鈕的單擊事件槽函數,更改如下:
void Widget::on_pushButton_5_clicked() //升序
{
model->setSort(0,Qt::AscendingOrder); //id屬性,即第0列,升序排列
model->select();
}
void Widget::on_pushButton_6_clicked() //降序
{
model->setSort(0,Qt::DescendingOrder);
model->select();
}
我們這裡使用了setSort()函數進行排序,它有兩個參數,第一個參數表示按第幾個屬性排序,表頭從左向右,最左邊是第0個屬性,這裡就是id屬性。第二個參數是排序方法,有升序和降序兩種。
運行程式,效果如下:
這是按下“按id降序排列”按鈕後的效果。
第四,刪除操作。
我們進入“刪除選中行”按鈕單擊事件槽函數,進行如下更改:
void Widget::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 Widget::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語句,就算你不怎麼懂資料庫,也可以利用它進行大部分常用的操作。我們也看到了,這個模型提供了緩衝區,可以先將修改儲存起來,當我們執行提交函數時,再去真正地修改資料庫。當然,這個模型比前面的模型更進階,前面講的所有操作,在這裡都能執行。