本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78615800
Qt實用技巧:使用QTableView、QSqlTableMode與QSqlDatabase對數據庫數據進行操作
需求
編寫應用軟件的過程中,需要對保存的數據進行動態的設置,當程序運行的時查詢數據庫獲取相關配置項進行設置。
原理
使用時,將QSqlTableModel與QSqlDatabase綁定即model與sql綁定,然后將model與QTableView綁定,實現修改QTableView時,自動更新對數據庫的操作,基本的數據庫操作語句都省了。
Demo
Demo下載地址:http://download.csdn.net/download/qq21497936/10130238
Demo包含

Demo截圖

關鍵代碼
對於數據庫的操作:打開數據庫
- _db = QSqlDatabase::addDatabase("QSQLITE");
- _db.setDatabaseName("demo.db");
- // 數據庫文件是否在應用程序目錄下,因為在編碼時,應用程序默認路徑在.pro文件夾下,但是實際exe路徑在的其debug或者release文件夾下
- // 補充:不論linux還是windows,統一使用單斜杠作為分隔,在linux和windows下都能識別,能更好的跨平台
- #if 0
- // 發布時
- QString path = qApp->applicationDirPath()+"/"+"demo.db";
- #else
- // 編譯時
- QString path = qApp->applicationDirPath()+"/../"+"demo.db";
- #endif
- if(QFile::exists(path))
- {
- // 存在則打開
- _db.open();
- }else{
- // 不存在打開並創建數據庫表 補充:SQLite是基於文件的數據庫,當打開時如果數據庫文件不存在將自動創建一個
- _db.open();
- QSqlQuery query;
- // set為sqlite關鍵字,不能使用
- bool bRet = query.exec("create table init(" \
- "no INT PRIMARY KEY NOT NULL,"\
- "name TEXT NOT NULL,"\
- "content TEXT,"\
- "description TEXT"\
- ");");
- if(!bRet) {
- _db.close();
- QFile::remove(path);
- }else{
- // 此處演示了三種不同insert插入方法
- query.exec("insert into init values" \
- "(1, '啟動界面背景', 'images/background.jpg', '請使用1920*1080的圖片,圖片格式可以為png、jpg。');");
- query.exec("insert into init " \
- "(no,name,content,description) values(2, '歡迎視頻', '','進入啟動界面后,循環播放的視頻,必須為mp4格式,如果為空則循環播放歡迎音樂');");
- query.exec("insert into init " \
- "(no,name,description) values (3, '歡迎音樂','進去啟動界面后,循環播放的音頻文件,可選擇mp3,wav格式');");
- }
- }
QSqlTableMode與數據庫綁定
- // 如果使用MySqlTableModel,重寫了data,但是導致直接點擊數據修改的時候,沒有更新TableView,不知原因
- // 如果使用QSqlTableMode,則無法通過重載實現每一行自動居中等一些單元格的統一操作,只能遍歷單元格設置
- QSqlTableModel *pModel = new QSqlTableModel(this, _db);
- pModel->setTable("init");
- // 三種提交方式,改動即提交,選擇其他行時提交,手動提交;經實際測試,其中只有手動提交在顯示效果上是最好的
- pModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
- pModel->select();
- pModel->setHeaderData(0, Qt::Horizontal, "序號");
- pModel->setHeaderData(1, Qt::Horizontal, "名稱");
- pModel->setHeaderData(2, Qt::Horizontal, "內容");
- pModel->setHeaderData(3, Qt::Horizontal, "描述");
- pModel->sort(0, Qt::AscendingOrder); // 第0列升序排序
QTableView與QSqlTableMode綁定
- ui->tableView->setModel(pModel);
QTableView的初始化設置
- // grid原本就是有多少格顯示多少格,
- ui->tableView->setShowGrid(false); // 可隱藏grid
- // 只能單選
- ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
- // 以行作為選擇標准
- ui->tableView->setSelectionBehavior(QAbstractItemView::QAbstractItemView::SelectRows);
- // 行頭隱藏
- ui->tableView->verticalHeader()->hide();
- // 讓列頭可被點擊,觸發點擊事件
- ui->tableView->horizontalHeader()->setSectionsClickable(true);
- // 去掉選中表格時,列頭的文字高亮
- ui->tableView->horizontalHeader()->setHighlightSections(false);
- ui->tableView->horizontalHeader()->setBackgroundRole(QPalette::Background);
- // 列頭灰色
- ui->tableView->horizontalHeader()->setStyleSheet("QHeaderView::section{background-color:rgb(225,225,225)};");
- connect(ui->tableView->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(sortByColumn(int)));
QTableView點擊列頭的排序操作(初始化時,開啟了列頭clicked和關聯信號槽)
- void MainWindow::sortByColumn(int col)
- {
- QSqlTableModel *pMode = dynamic_cast<QSqlTableModel *>(ui->tableView->model());
- bool ascending = (ui->tableView->horizontalHeader()->sortIndicatorSection()==col
- && ui->tableView->horizontalHeader()->sortIndicatorOrder()==Qt::DescendingOrder);
- Qt::SortOrder order = ascending ? Qt::AscendingOrder : Qt::DescendingOrder;
- pMode->sort(col, order);
- }
QTableView修改一行的保存操作
- void MainWindow::on_pushButton_save_clicked()
- {
- QSqlTableModel *pMode = dynamic_cast<QSqlTableModel *>(ui->tableView->model());
- pMode->database().transaction(); //開始事務操作
- if (pMode->submitAll()) // 提交所有被修改的數據到數據庫中
- {
- pMode->database().commit(); //提交成功,事務將真正修改數據庫數據
- } else {
- pMode->database().rollback(); //提交失敗,事務回滾
- QMessageBox::warning(this, tr("tableModel"),tr("數據庫錯誤: %1").arg(pMode->lastError().text()));
- }
- pMode->revertAll(); //撤銷修改
- }
QTableView新增一行的操作
- void MainWindow::on_pushButton_add_clicked()
- {
- QSqlTableModel *pMode = dynamic_cast<QSqlTableModel *>(ui->tableView->model());
- // pMode->insertRow(pMode->rowCount());
- QSqlRecord record = pMode->record();
- int number;
- // 從1開始遍歷,遇到相同的,自增再遍歷,直到沒有相同的作為number插入
- // 防止唯一主鍵重復導致提交失敗,因為提交失敗tableview還是會更新修改后的(視圖)
- for(number = 1; ; number++)
- {
- bool bFlag = false;
- for(int index = 0; index < pMode->rowCount(); index++) {
- if(pMode->index(index, 0).data().toInt() == number) {
- bFlag = true;
- break;
- }
- }
- if(!bFlag) {
- break;
- }
- }
- record.setValue(0, number);
- record.setValue(1, "未命令");
- record.setValue(2, "空");
- record.setValue(3, "空");
- pMode->insertRecord(pMode->rowCount(), record);
- // 每次手動提交,都會重新刷新tableView,保持mode和tableView一致
- pMode->submitAll();
- }
QTableView刪除一行的操作
- void MainWindow::on_pushButton_del_clicked()
- {
- QSqlTableModel *pMode = dynamic_cast<QSqlTableModel *>(ui->tableView->model());
- // 當QSqlTableModel::EditStrategy 選擇 非QSqlTableModel::OnManualSubmit 時,
- // 每次刪除都可刪除掉model,但是tableview那一列為空,一直在,只好設置為 QSqlTableModel::OnManualSubmit
- pMode->removeRow(ui->tableView->currentIndex().row());
- // 每次手動提交,都會重新刷新tableView,保持mode和tableView一致
- pMode->submitAll();
- }
拓展
整個應用,可只打開一次QSqlDatabase,程序中第一次使用了QDatabase,打開后不關閉且不再打開新的數據庫,其他類中可直接聲明QSqlDatabase對象db,然后使用QSqlQuery進行查詢操作。(正常以為是需要傳遞,但Qt機制中,此處可不第二次打開,只要第一次不關閉,但是都必須在一個應用中)。
http://blog.csdn.net/qq21497936/article/details/78615800
