Qt實(shí)現(xiàn)SqlRelationalTable關(guān)聯(lián)表組件
Qt 是一個(gè)跨平臺(tái)C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺(tái)窗體應(yīng)用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實(shí)現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點(diǎn)介紹SqlRelationalTable
關(guān)聯(lián)表組件的常用方法及靈活運(yùn)用。
在上一篇文章中詳細(xì)介紹了SqlTableModle
組件是如何使用的,本篇文章將介紹SqlRelationalTable
關(guān)聯(lián)表組件,該該組件其實(shí)是SqlTableModle
組件的擴(kuò)展類,其提供了一個(gè)帶關(guān)系的數(shù)據(jù)模型,用于處理數(shù)據(jù)庫中的表與表之間的關(guān)系。通過這個(gè)類,你可以在一個(gè)表中使用外鍵關(guān)聯(lián)到另一個(gè)表的數(shù)據(jù)上。例如將主表中的某個(gè)字段與附加表中的特定字段相關(guān)聯(lián)起來,QSqlRelation(關(guān)聯(lián)表名,關(guān)聯(lián)ID,名稱)
就是用來實(shí)現(xiàn)多表之間快速關(guān)聯(lián)的。
1.1 ComboBox
首先我們來實(shí)現(xiàn)一個(gè)簡單的聯(lián)動(dòng)效果,數(shù)據(jù)庫組件可以與ComboBox
組件形成多級(jí)聯(lián)動(dòng)效果,在日常開發(fā)中多級(jí)聯(lián)動(dòng)效果應(yīng)用非常廣泛,例如當(dāng)我們選擇指定用戶時(shí),讓其在另一個(gè)ComboBox
組件中列舉出該用戶所維護(hù)的主機(jī)列表,又或者當(dāng)用戶選擇省份時(shí),自動(dòng)列舉出該省份下面的城市列表等。
在進(jìn)行聯(lián)動(dòng)之前需要?jiǎng)?chuàng)建兩張表,表結(jié)構(gòu)內(nèi)容介紹如下:
- User(id,name)表:存儲(chǔ)指定用戶的ID號(hào)與用戶名
- UserAddressList(id,name,address)表:與User表中的用戶名相關(guān)聯(lián),存儲(chǔ)該用戶所管理的主機(jī)列表信息
通過數(shù)據(jù)庫組件實(shí)現(xiàn)的聯(lián)動(dòng)非常簡單,初始化表結(jié)構(gòu)得到了兩張表,當(dāng)程序運(yùn)行時(shí)默認(rèn)在MainWindow
構(gòu)造函數(shù)處填充第一個(gè)ComboBox
組件,也就是執(zhí)行一次數(shù)據(jù)庫查詢,并將結(jié)果通過addItem()
放入到第一個(gè)組件內(nèi)。
QSqlDatabase db; MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); InitMultipleSQL(); db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("./database.db"); if (!db.open()) { std::cout << db.lastError().text().toStdString()<< std::endl; return; } QSqlQuery query; query.exec("select * from User;"); QSqlRecord rec = query.record(); while(query.next()) { int index_name = rec.indexOf("name"); QString data_name = query.value(index_name).toString(); ui->comboBox_user->addItem(data_name); } }
而當(dāng)用戶選中了第一個(gè)ComboBox
組件時(shí),則讓其轉(zhuǎn)到槽函數(shù)on_comboBox_activated(const QString &arg1)
上面,如下圖所示;
該槽函數(shù)需要一個(gè)傳入?yún)?shù),此參數(shù)代表組件選中的文本內(nèi)容,通過利用該文本內(nèi)容在數(shù)據(jù)庫內(nèi)執(zhí)行二次查詢并將查詢結(jié)果填充之對(duì)應(yīng)的第二個(gè)ComboBox
組件內(nèi)即可實(shí)現(xiàn)組件的聯(lián)動(dòng)選擇效果,其槽函數(shù)代碼如下所示;
void MainWindow::on_comboBox_user_activated(const QString &arg1) { if(db.open()) { QSqlQuery query; query.prepare("select * from UserAddressList where name = :x"); query.bindValue(":x",arg1); query.exec(); QSqlRecord rec = query.record(); ui->comboBox_address->clear(); while(query.next()) { int index = rec.indexOf("address"); QString data_ = query.value(index).toString(); ui->comboBox_address->addItem(data_); } } }
讀者可自行運(yùn)行案例中的SqlComboBox
案例,運(yùn)行后可自行選擇不同的用戶名,則此時(shí)會(huì)輸出該用戶名所對(duì)應(yīng)的地址表,如下圖所示;
1.2 TableView
接著,我們繼續(xù)以TableView
組件為例,簡單介紹一下如何實(shí)現(xiàn)組件與數(shù)據(jù)的綁定,首先我們需要?jiǎng)?chuàng)建一個(gè)表并插入幾條測(cè)試記錄,運(yùn)行如下代碼實(shí)現(xiàn)建庫建表.
創(chuàng)建一張新表,表結(jié)構(gòu)內(nèi)容介紹如下:
- LyShark(name,age)表:存儲(chǔ)指定用戶名與用戶年齡
在主構(gòu)造函數(shù)中我們可以直接通過QSqlQueryModel
來得到特定表中的記錄,并通過setHeaderData
將表中的數(shù)據(jù)關(guān)聯(lián)到對(duì)應(yīng)的數(shù)據(jù)模型內(nèi),最后通過setModel
方法即可將對(duì)應(yīng)的表數(shù)據(jù)關(guān)聯(lián)到前端顯示,其核心代碼如下所示;
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); Init(); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("./database.db"); if (!db.open()) { std::cout << db.lastError().text().toStdString()<< std::endl; return; } // 查詢數(shù)據(jù)表中記錄 qryModel=new QSqlQueryModel(this); qryModel->setQuery("SELECT * FROM LyShark ORDER BY id"); if (qryModel->lastError().isValid()) { return; } // 設(shè)置TableView表頭數(shù)據(jù) qryModel->setHeaderData(0,Qt::Horizontal,"ID"); qryModel->setHeaderData(1,Qt::Horizontal,"Name"); qryModel->setHeaderData(2,Qt::Horizontal,"Age"); // 將數(shù)據(jù)綁定到模型上 theSelection=new QItemSelectionModel(qryModel); ui->tableView->setModel(qryModel); ui->tableView->setSelectionModel(theSelection); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); }
運(yùn)行代碼后,程序會(huì)從數(shù)據(jù)庫內(nèi)取出結(jié)果并輸出到tableView
組件上,如下圖所示;
1.3 SqlRelationalTable
在最開始我們也說過,SqlRelationalTable
并不是Qt中標(biāo)準(zhǔn)的類或方法。它僅僅只是QSqlTableModel
的一個(gè)子類,其支持在關(guān)系數(shù)據(jù)庫表之間建立關(guān)系,建立關(guān)聯(lián)時(shí)我們只需要使用setRelation
方法即可。
setRelation
是 QSqlRelationalTableModel
類中的一個(gè)方法,用于設(shè)置模型中某一列的關(guān)聯(lián)關(guān)系。這個(gè)方法的目的是告訴模型某一列的值在另一個(gè)表中有關(guān)聯(lián),并提供相關(guān)的信息,以便在視圖中顯示更有意義的數(shù)據(jù)而不是外鍵的原始值。
以下是 setRelation
方法的簡單說明:
void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation);
- column: 要設(shè)置關(guān)聯(lián)關(guān)系的列的索引。
- relation: 包含關(guān)聯(lián)信息的 QSqlRelation 對(duì)象。
QSqlRelation
的構(gòu)造函數(shù)如下:
QSqlRelation::QSqlRelation(const QString &tableName, const QString &indexColumn, const QString &displayColumn);
- tableName: 關(guān)聯(lián)的表的名稱。
- indexColumn: 關(guān)聯(lián)表中與當(dāng)前表關(guān)聯(lián)的列的名稱,通常是外鍵列。
- displayColumn: 關(guān)聯(lián)表中要顯示的列的名稱,通常是與外鍵列相關(guān)的實(shí)際數(shù)據(jù)。
示例:
QSqlRelationalTableModel model; model.setTable("orders"); model.setRelation(2, QSqlRelation("customers", "customer_id", "customer_name")); model.select();
在這個(gè)例子中,第二列(索引為2的列)的數(shù)據(jù)將從名為 “customers” 的表中獲取,該表的外鍵列為 “customer_id”,并且在視圖中顯示的是該關(guān)聯(lián)表的 “customer_name” 列的值。使用 setRelation
方法可以使得在表格中更容易地顯示和編輯關(guān)聯(lián)數(shù)據(jù),而不是直接顯示外鍵的值。
在關(guān)聯(lián)表之前,我們需要設(shè)置初始化數(shù)據(jù),此處我們提供兩個(gè)表結(jié)構(gòu),表Student
用于存儲(chǔ)學(xué)生名字以及學(xué)生課程號(hào),另一張Departments
則用于存儲(chǔ)每個(gè)編號(hào)所對(duì)應(yīng)的系名稱,運(yùn)行代碼完成創(chuàng)建。
// 初始化數(shù)據(jù)表 void MainWindow::InitSQL() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("./database.db"); if (!db.open()) return; // 執(zhí)行SQL創(chuàng)建表 db.exec("DROP TABLE Student"); db.exec("CREATE TABLE Student (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "name VARCHAR(40) NOT NULL, " "departID INTEGER NOT NULL)" ); // 逐條插入數(shù)據(jù) db.exec("INSERT INTO Student(name,departID) VALUES('zhangsan',10)"); db.exec("INSERT INTO Student(name,departID) VALUES('lisi',20)"); db.exec("INSERT INTO Student(name,departID) VALUES('wangwu',30)"); db.exec("INSERT INTO Student(name,departID) VALUES('wangmazi',40)"); db.exec("DROP TABLE Departments"); db.exec("CREATE TABLE Departments(" "departID INTEGER NOT NULL," "department VARCHAR(40) NOT NULL)" ); db.exec("INSERT INTO Departments(departID,department) VALUES (10,'數(shù)學(xué)學(xué)院')"); db.exec("INSERT INTO Departments(departID,department) VALUES (20,'物理學(xué)院')"); db.exec("INSERT INTO Departments(departID,department) VALUES (30,'計(jì)算機(jī)學(xué)院')"); }
接著我們來看下在MainWindow
構(gòu)造函數(shù)中是如何進(jìn)行初始化和表關(guān)聯(lián)的,以下是對(duì)代碼的簡要說明:
打開數(shù)據(jù)庫連接
創(chuàng)建一個(gè) SQLite 數(shù)據(jù)庫連接,并指定了數(shù)據(jù)庫文件的路徑。如果數(shù)據(jù)庫連接成功打開,就繼續(xù)執(zhí)行后面的代碼。
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("./database.db"); if (!db.open()) return;
設(shè)置主窗口的布局和屬性
將主窗口的中央部件設(shè)置為一個(gè) QTableView
,同時(shí)對(duì)表格的選擇行為和外觀進(jìn)行了設(shè)置。
this->setCentralWidget(ui->tableView); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems); ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableView->setAlternatingRowColors(true);
打開數(shù)據(jù)表并設(shè)置模型
創(chuàng)建一個(gè) QSqlRelationalTableModel
并設(shè)置了一些表格的屬性,包括表名、編輯策略、排序等。
tabModel = new QSqlRelationalTableModel(this, db); tabModel->setTable("Student"); tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); tabModel->setSort(0, Qt::AscendingOrder); tabModel->setHeaderData(0, Qt::Horizontal, "學(xué)號(hào)"); tabModel->setHeaderData(1, Qt::Horizontal, "姓名"); tabModel->setHeaderData(2, Qt::Horizontal, "學(xué)院");
設(shè)置查詢關(guān)系數(shù)據(jù)表
設(shè)置關(guān)系型字段,將 “學(xué)院” 列與 “Departments” 表中的 “departID” 列關(guān)聯(lián)起來,并在表格中顯示 “department” 列的數(shù)據(jù)。
tabModel->setRelation(2, QSqlRelation("Departments", "departID", "department"));
設(shè)置表格的選擇模型和代理
代碼設(shè)置了表格的選擇模型,并為表格設(shè)置了一個(gè)關(guān)系型代理(QSqlRelationalDelegate
),以便在表格中顯示關(guān)聯(lián)表的數(shù)據(jù)而不是外鍵的值。
theSelection = new QItemSelectionModel(tabModel); ui->tableView->setModel(tabModel); ui->tableView->setSelectionModel(theSelection); ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));
選擇并顯示數(shù)據(jù)表
最后,通過調(diào)用 select
方法來選擇和顯示數(shù)據(jù)表的內(nèi)容。
tabModel->select();
其實(shí)代碼中最重要的部分就是setRelation
,我們只要確保數(shù)據(jù)庫文件正確,并且 Student
表和 Departments
表存在,并且在 Student
表中的 “學(xué)院” 列與 Departments
表中的 "departID"
列正確關(guān)聯(lián)即可,其他的就交給組件來處理,如下圖所示;
到此這篇關(guān)于Qt實(shí)現(xiàn)SqlRelationalTable關(guān)聯(lián)表組件的文章就介紹到這了,更多相關(guān)Qt SqlRelationalTable關(guān)聯(lián)表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++課程設(shè)計(jì)之學(xué)生成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++課程設(shè)計(jì)之學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12學(xué)習(xí)二維動(dòng)態(tài)數(shù)組指針做矩陣運(yùn)算的方法
這片文章介紹了如何利用二維動(dòng)態(tài)數(shù)組指針做矩陣運(yùn)算,需要的朋友可以參考下2015-07-07淺談C++日志系統(tǒng)log4cxx的使用小結(jié)詳解
本篇文章是對(duì)C++日志系統(tǒng)log4cxx的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C語言實(shí)現(xiàn)個(gè)人通訊錄管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)個(gè)人通訊錄管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12C++中HTTP?代理服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)詳解
代理服務(wù)器,即允許一個(gè)網(wǎng)絡(luò)終端(一般為客戶端)通過這個(gè)服務(wù)與另一?個(gè)網(wǎng)絡(luò)終端(一般為服務(wù)器)進(jìn)行非直接的連接,下面我們就來看看如何使用C++設(shè)計(jì)與實(shí)現(xiàn)一個(gè)HTTP?代理服務(wù)器吧2024-01-01QT使用QComBox和QLineEdit實(shí)現(xiàn)模糊查詢功能
模糊查詢是指根據(jù)用戶輸入的文本,在下拉框的選項(xiàng)中進(jìn)行模糊匹配,并動(dòng)態(tài)地顯示匹配的選項(xiàng),本文將使用QComBox和QLineEdit實(shí)現(xiàn)模糊查詢功能,需要的可以參考下2023-11-11