C/C++中的?Qt?StandardItemModel?數(shù)據(jù)模型應(yīng)用解析
QStandardItemModel 是標(biāo)準(zhǔn)的以項(xiàng)數(shù)據(jù)為單位的基于M/V模型的一種標(biāo)準(zhǔn)數(shù)據(jù)管理方式,Model/View 是Qt中的一種數(shù)據(jù)編排結(jié)構(gòu),其中Model代表模型,View代表視圖,視圖是顯示和編輯數(shù)據(jù)的界面組件,而模型則是視圖與原始數(shù)據(jù)之間的接口,通常該類結(jié)構(gòu)都是用在數(shù)據(jù)庫(kù)中較多,例如模型結(jié)構(gòu)負(fù)責(zé)讀取或?qū)懭霐?shù)據(jù)庫(kù),視圖結(jié)構(gòu)則負(fù)責(zé)展示數(shù)據(jù),其條理清晰,編寫代碼便于維護(hù)。
QStandardItemModel組件通常會(huì)配合TableView組件一起使用,當(dāng)數(shù)據(jù)庫(kù)或文本中的記錄發(fā)生變化時(shí)會(huì)自動(dòng)同步到組件中,首先繪制UI界面。

其次綁定頂部ToolBar菜單,分別對(duì)菜單增加對(duì)應(yīng)的功能屬性的描述等。

初始化構(gòu)造函數(shù): 當(dāng)程序運(yùn)行時(shí),我們需要對(duì)頁(yè)面中的控件逐一初始化,并將Table表格與模型通過(guò)調(diào)用ui->tableView->setModel(model)進(jìn)行綁定。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <QLabel>
#include <QStandardItem>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QTextStream>
#include <QList>
// 默認(rèn)構(gòu)造函數(shù)
// https://www.cnblogs.com/lyshark
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化部分
model = new QStandardItemModel(3,FixedColumnCount,this); // 數(shù)據(jù)模型初始化
selection = new QItemSelectionModel(model); // Item選擇模型
// 為TableView設(shè)置數(shù)據(jù)模型
ui->tableView->setModel(model); // 設(shè)置數(shù)據(jù)模型
ui->tableView->setSelectionModel(selection); // 設(shè)置選擇模型
// 默認(rèn)禁用所有Action選項(xiàng),只保留打開(kāi)
ui->actionSave->setEnabled(false);
ui->actionView->setEnabled(false);
ui->actionAppend->setEnabled(false);
ui->actionDelete->setEnabled(false);
ui->actionInsert->setEnabled(false);
// 創(chuàng)建狀態(tài)欄組件,主要來(lái)顯示單元格位置
LabCurFile = new QLabel("當(dāng)前文件:",this);
LabCurFile->setMinimumWidth(200);
LabCellPos = new QLabel("當(dāng)前單元格:",this);
LabCellPos->setMinimumWidth(180);
LabCellPos->setAlignment(Qt::AlignHCenter);
LabCellText = new QLabel("單元格內(nèi)容:",this);
LabCellText->setMinimumWidth(150);
ui->statusbar->addWidget(LabCurFile);
ui->statusbar->addWidget(LabCellPos);
ui->statusbar->addWidget(LabCellText);
//選擇當(dāng)前單元格變化時(shí)的信號(hào)與槽
connect(selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
初始化時(shí)同時(shí)需要綁定一個(gè)on_currentChanged(QModelIndex,QModelIndex)信號(hào),當(dāng)用戶選中指定單元格時(shí)相應(yīng)用戶。
// 選擇單元格變化時(shí)的響應(yīng),通過(guò)在構(gòu)造函數(shù)中綁定信號(hào)和槽函數(shù)實(shí)現(xiàn)觸發(fā)
// https://www.cnblogs.com/lyshark
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
Q_UNUSED(previous);
if (current.isValid()) //當(dāng)前模型索引有效
{
LabCellPos->setText(QString::asprintf("當(dāng)前單元格:%d行,%d列",current.row(),current.column())); //顯示模型索引的行和列號(hào)
QStandardItem *aItem;
aItem=model->itemFromIndex(current); //從模型索引獲得Item
this->LabCellText->setText("單元格內(nèi)容:"+aItem->text()); //顯示item的文字內(nèi)容
}
}
當(dāng)頁(yè)面被初始化時(shí),默認(rèn)界面如下:

打開(kāi)并填充組件: 當(dāng)工具欄中打開(kāi)文件被點(diǎn)擊后則觸發(fā),打開(kāi)文件時(shí)通過(guò)aFile.open打開(kāi),循環(huán)讀入文件,并將文件中的內(nèi)容逐行追加到QStringList fFileContent中,當(dāng)追加完畢后,直接調(diào)用iniModelFromStringList(fFileContent);完成對(duì)頁(yè)面TableView組件的初始化,并設(shè)置其他控件狀態(tài)為可點(diǎn)擊。
void MainWindow::on_actionOpen_triggered()
{
QString curPath=QCoreApplication::applicationDirPath(); // 獲取應(yīng)用程序的路徑
// 調(diào)用打開(kāi)文件對(duì)話框打開(kāi)一個(gè)文件
// https://www.cnblogs.com/lyshark
QString aFileName=QFileDialog::getOpenFileName(this,"打開(kāi)一個(gè)文件",curPath,"數(shù)據(jù)文件(*.txt);;所有文件(*.*)");
if (aFileName.isEmpty())
{
return; // 如果未選擇文件則退出
}
QStringList fFileContent; // 文件內(nèi)容字符串列表
QFile aFile(aFileName); // 以文件方式讀出
if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) // 以只讀文本方式打開(kāi)文件
{
QTextStream aStream(&aFile); // 用文本流讀取文件
ui->plainTextEdit->clear(); // 清空列表
// 循環(huán)讀取只要不為空
while (!aStream.atEnd())
{
QString str=aStream.readLine(); // 讀取文件的一行
ui->plainTextEdit->appendPlainText(str); // 添加到文本框顯示
fFileContent.append(str); // 添加到StringList
}
aFile.close(); // 關(guān)閉文件
iniModelFromStringList(fFileContent); // 從StringList的內(nèi)容初始化數(shù)據(jù)模型
}
// 打開(kāi)文件完成后,就可以將Action全部開(kāi)啟了
ui->actionSave->setEnabled(true);
ui->actionView->setEnabled(true);
ui->actionAppend->setEnabled(true);
ui->actionDelete->setEnabled(true);
ui->actionInsert->setEnabled(true);
// 打開(kāi)文件成功后,設(shè)置狀態(tài)欄當(dāng)前文件列
this->LabCurFile->setText("當(dāng)前文件:"+aFileName);//狀態(tài)欄顯示
}
如上iniModelFromStringList(fFileContent);函數(shù)是后期增加的,我們需要自己實(shí)現(xiàn),該函數(shù)的作用是從傳入的StringList中獲取數(shù)據(jù),并將數(shù)據(jù)初始化到TableView模型中,實(shí)現(xiàn)代碼如下。
void MainWindow::iniModelFromStringList(QStringList& aFileContent)
{
int rowCnt=aFileContent.count(); // 文本行數(shù),第1行是標(biāo)題
model->setRowCount(rowCnt-1); // 實(shí)際數(shù)據(jù)行數(shù),要在標(biāo)題上減去1
// 設(shè)置表頭
QString header=aFileContent.at(0); // 第1行是表頭
// 一個(gè)或多個(gè)空格、TAB等分隔符隔開(kāi)的字符串、分解為一個(gè)StringList
// https://www.cnblogs.com/lyshark
QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts);
model->setHorizontalHeaderLabels(headerList); // 設(shè)置表頭文字
// 設(shè)置表格中的數(shù)據(jù)
int x = 0,y = 0;
QStandardItem *Item;
// 有多少列數(shù)據(jù)就循環(huán)多少次
// https://www.cnblogs.com/lyshark
for(x=1; x < rowCnt; x++)
{
QString LineText = aFileContent.at(x); // 獲取數(shù)據(jù)區(qū)的一行
// 一個(gè)或多個(gè)空格、TAB等分隔符隔開(kāi)的字符串、分解為一個(gè)StringList
QStringList tmpList=LineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);
// 循環(huán)列數(shù),也就是循環(huán)FixedColumnCount,其中tmpList中的內(nèi)容也是.
for(y=0; y < FixedColumnCount-1; y++)
{
Item = new QStandardItem(tmpList.at(y)); // 創(chuàng)建item
model->setItem(x-1,y,Item); // 為模型的某個(gè)行列位置設(shè)置Item
}
// 最后一個(gè)數(shù)據(jù)需要取出來(lái)判斷,并單獨(dú)設(shè)置狀態(tài)
Item=new QStandardItem(headerList.at(y)); // 最后一列是Checkable,需要設(shè)置
Item->setCheckable(true); // 設(shè)置為Checkable
// 判斷最后一個(gè)數(shù)值是否為0
if (tmpList.at(y) == "0")
Item->setCheckState(Qt::Unchecked); // 根據(jù)數(shù)據(jù)設(shè)置check狀態(tài)
else
Item->setCheckState(Qt::Checked);
model->setItem(x-1,y,Item); //為模型的某個(gè)行列位置設(shè)置Item
}
}
初始化組件后效果如下:

實(shí)現(xiàn)添加一行數(shù)據(jù): 為TableView添加一行數(shù)據(jù),在文件末尾插入。
void MainWindow::on_actionAppend_triggered()
{
QList<QStandardItem *> ItemList; // 創(chuàng)建臨時(shí)容器
QStandardItem *Item;
// 模擬添加一列的數(shù)據(jù)
for(int x=0; x<FixedColumnCount-1; x++)
{
Item = new QStandardItem("測(cè)試(追加行)"); // 循環(huán)創(chuàng)建每一列
ItemList << Item; // 添加到鏈表中
}
// 創(chuàng)建最后一個(gè)列元素,由于是選擇框所以需要單獨(dú)創(chuàng)建
// https://www.cnblogs.com/lyshark
// 1.獲取到最后一列的表頭下標(biāo),最后下標(biāo)為6
QString str = model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
Item=new QStandardItem(str); // 創(chuàng)建 "是否合格" 字段
Item->setCheckable(true); // 設(shè)置狀態(tài)為真
ItemList << Item; // 最后一個(gè)選項(xiàng)追加進(jìn)去
model->insertRow(model->rowCount(),ItemList); // 插入一行,需要每個(gè)Cell的Item
QModelIndex curIndex=model->index(model->rowCount()-1,0); // 創(chuàng)建最后一行的ModelIndex
selection->clearSelection(); // 清空當(dāng)前選中項(xiàng)
selection->setCurrentIndex(curIndex,QItemSelectionModel::Select); // 設(shè)置當(dāng)前選中項(xiàng)為當(dāng)前選擇行
}
插入代碼演示效果:

實(shí)現(xiàn)插入一行數(shù)據(jù): 為TableView插入一行數(shù)據(jù)(在文件任意位置插入數(shù)據(jù))
// https://www.cnblogs.com/lyshark
void MainWindow::on_actionInsert_triggered()
{
QList<QStandardItem*> ItemList; // QStandardItem的列表類
QStandardItem *Item;
// 模擬插入前五列數(shù)據(jù)
for(int i=0;i<FixedColumnCount-1;i++)
{
Item= new QStandardItem("測(cè)試(插入行)"); // 新建一個(gè)QStandardItem
ItemList << Item; // 添加到列表類
}
QString str; // 獲取表頭文字
str=model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
Item=new QStandardItem(str); // 創(chuàng)建Item
Item->setCheckable(true); // 設(shè)置為可使用CheckBox
ItemList<<Item; // 添加到列表類
QModelIndex curIndex=selection->currentIndex(); // 獲取當(dāng)前選中項(xiàng)的索引
model->insertRow(curIndex.row(),ItemList); // 在當(dāng)前行的前面插入一行
selection->clearSelection(); // 清除當(dāng)前選中項(xiàng)
selection->setCurrentIndex(curIndex,QItemSelectionModel::Select); // 設(shè)置當(dāng)前選中項(xiàng)為當(dāng)前選擇行
}
插入代碼演示效果:

實(shí)現(xiàn)刪除一行數(shù)據(jù): 刪除數(shù)據(jù)之前需要通過(guò)selection->currentIndex()確定當(dāng)前選中行,并通過(guò)model->removeRow()移除即可。
// https://www.cnblogs.com/lyshark
void MainWindow::on_actionDelete_triggered()
{
QModelIndex curIndex = selection->currentIndex(); // 獲取當(dāng)前選擇單元格的模型索引
// 先判斷是不是最后一行
if (curIndex.row()==model->rowCount()-1)
{
model->removeRow(curIndex.row()); //刪除最后一行
}
else
{
model->removeRow(curIndex.row());//刪除一行,并重新設(shè)置當(dāng)前選擇行
selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}
}
刪除代碼效果演示:

實(shí)現(xiàn)字體數(shù)據(jù)對(duì)齊: 表格中的字體可以實(shí)現(xiàn)多種對(duì)其方式,對(duì)齊方式分為 居中對(duì)齊,左對(duì)齊,右對(duì)齊 三種。
// 設(shè)置表格居中對(duì)齊
void MainWindow::on_pushButton_clicked()
{
if (!selection->hasSelection())
return;
QModelIndexList selectedIndex=selection->selectedIndexes();
QModelIndex Index;
QStandardItem *Item;
for (int i=0; i<selectedIndex.count(); i++)
{
Index=selectedIndex.at(i);
Item=model->itemFromIndex(Index);
Item->setTextAlignment(Qt::AlignHCenter);
}
}
// 設(shè)置表格左對(duì)齊
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_2_clicked()
{
if (!selection->hasSelection()) //沒(méi)有選擇的項(xiàng)
return;
//獲取選擇的單元格的模型索引列表,可以是多選
QModelIndexList selectedIndex=selection->selectedIndexes();
for (int i=0;i<selectedIndex.count();i++)
{
QModelIndex aIndex=selectedIndex.at(i); //獲取其中的一個(gè)模型索引
QStandardItem* aItem=model->itemFromIndex(aIndex);//獲取一個(gè)單元格的項(xiàng)數(shù)據(jù)對(duì)象
aItem->setTextAlignment(Qt::AlignLeft);//設(shè)置文字對(duì)齊方式
}
}
// 設(shè)置表格右對(duì)齊
void MainWindow::on_pushButton_3_clicked()
{
if (!selection->hasSelection())
return;
QModelIndexList selectedIndex=selection->selectedIndexes();
QModelIndex aIndex;
QStandardItem *aItem;
for (int i=0;i<selectedIndex.count();i++)
{
aIndex=selectedIndex.at(i);
aItem=model->itemFromIndex(aIndex);
aItem->setTextAlignment(Qt::AlignRight);
}
}
對(duì)齊代碼效果演示:

實(shí)現(xiàn)字體數(shù)據(jù)加粗: 將選中行的字體進(jìn)行加粗顯示。
// 設(shè)置字體加粗顯示
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_4_clicked()
{
if (!selection->hasSelection())
return;
//獲取選擇單元格的模型索引列表
QModelIndexList selectedIndex=selection->selectedIndexes();
for (int i=0;i<selectedIndex.count();i++)
{
QModelIndex aIndex=selectedIndex.at(i); //獲取一個(gè)模型索引
QStandardItem* aItem=model->itemFromIndex(aIndex);//獲取項(xiàng)數(shù)據(jù)
QFont font=aItem->font(); //獲取字體
font.setBold(true); //設(shè)置字體是否粗體
aItem->setFont(font); //重新設(shè)置字體
}
加粗代碼效果演示:

實(shí)現(xiàn)保存文件: 當(dāng)保存文件被點(diǎn)擊后觸發(fā),通過(guò)便利TableWidget模型組件中的數(shù)據(jù),并將數(shù)據(jù)通過(guò)aStream << str << "\n";寫出到記事本中。
// https://www.cnblogs.com/lyshark
// 【保存文件】
void MainWindow::on_actionSave_triggered()
{
QString curPath=QCoreApplication::applicationDirPath(); // 獲取應(yīng)用程序的路徑
// 調(diào)用打開(kāi)文件對(duì)話框選擇一個(gè)文件
QString aFileName=QFileDialog::getSaveFileName(this,tr("選擇一個(gè)文件"),curPath,"數(shù)據(jù)文件(*.txt);;所有文件(*.*)");
if (aFileName.isEmpty()) // 未選擇文件則直接退出
return;
QFile aFile(aFileName);
// 以讀寫、覆蓋原有內(nèi)容方式打開(kāi)文件
if (!(aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)))
return;
QTextStream aStream(&aFile); // 用文本流讀取文件
QStandardItem *Item;
QString str;
int x = 0,y = 0;
ui->plainTextEdit->clear();
// 獲取表頭文字
for (x=0; x<model->columnCount(); x++)
{
Item=model->horizontalHeaderItem(x); // 獲取表頭的項(xiàng)數(shù)據(jù)
str= str + Item->text() + "\t\t"; // 以TAB制表符隔開(kāi)
}
aStream << str << "\n"; // 文件里需要加入換行符\n
ui->plainTextEdit->appendPlainText(str);
// 獲取數(shù)據(jù)區(qū)文字
for ( x=0; x < model->rowCount(); x++)
{
str = "";
for( y=0; y < model->columnCount()-1; y++)
{
Item=model->item(x,y);
str=str + Item->text() + QString::asprintf("\t\t");
}
// 對(duì)最后一列需要轉(zhuǎn)換一下,如果判斷為選中則寫1否則寫0
Item=model->item(x,y);
if (Item->checkState()==Qt::Checked)
str= str + "1";
else
str= str + "0";
ui->plainTextEdit->appendPlainText(str);
aStream << str << "\n";
}
}
// 【導(dǎo)出Txt文件】:將TableView中的數(shù)據(jù)導(dǎo)出到PlainTextEdit顯示
void MainWindow::on_actionView_triggered()
{
ui->plainTextEdit->clear();
QStandardItem *Item;
QString str;
//獲取表頭文字
int x=0,y=0;
for (x=0; x<model->columnCount(); x++)
{ //
Item=model->horizontalHeaderItem(x);
str= str + Item->text() + "\t";
}
ui->plainTextEdit->appendPlainText(str);
//獲取數(shù)據(jù)區(qū)的每行
for (x=0; x<model->rowCount(); x++)
{
str="";
for(y=0; y<model->columnCount()-1; y++)
{
Item=model->item(x,y);
str= str + Item->text() + QString::asprintf("\t");
}
Item=model->item(x,y);
if (Item->checkState()==Qt::Checked)
str= str + "1";
else
str= str + "0";
ui->plainTextEdit->appendPlainText(str);
}
}
文件保存后如下:

到此這篇關(guān)于C/C++中的?Qt?StandardItemModel?數(shù)據(jù)模型應(yīng)用解析的文章就介紹到這了,更多相關(guān)C++?Qt?StandardItemModel?數(shù)據(jù)模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言中#define預(yù)處理語(yǔ)法總結(jié)
C語(yǔ)言里可以用#define定義一個(gè)標(biāo)識(shí)符來(lái)表示一個(gè)常量。特點(diǎn)是:定義的標(biāo)識(shí)符不占內(nèi)存,只是一個(gè)臨時(shí)的符號(hào),預(yù)編譯后這個(gè)符號(hào)就不存在了,也不做類型定義。預(yù)編譯又叫預(yù)處理2021-11-11
Qt+QWidget實(shí)現(xiàn)簡(jiǎn)約美觀的加載動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了Qt如何結(jié)合QWidget實(shí)現(xiàn)簡(jiǎn)約美觀的加載動(dòng)畫,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-02-02
??C++11系列學(xué)習(xí)之Lambda表達(dá)式
這篇文章主要介紹了??C++11系列學(xué)習(xí)之Lambda表達(dá)式,C++11終于也引入了lambda表達(dá)式,lambda最早來(lái)源于函數(shù)式編程,現(xiàn)代語(yǔ)言慢慢都引入了這個(gè)語(yǔ)法,下文關(guān)于??C++11Lambda表達(dá)式相關(guān)內(nèi)容需要的小伙伴可以參考一下2022-04-04
c++中為什么可以通過(guò)指針或引用實(shí)現(xiàn)多態(tài)詳解
這篇文章主要給大家介紹了關(guān)于c++中為何可以通過(guò)指針或引用實(shí)現(xiàn)多態(tài),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
C語(yǔ)言光標(biāo)旋轉(zhuǎn)與倒計(jì)時(shí)功能實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了C語(yǔ)言實(shí)現(xiàn)光標(biāo)旋轉(zhuǎn)與倒計(jì)時(shí)功能的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-11-11
C語(yǔ)言中的浮點(diǎn)數(shù)據(jù)類型
這篇文章主要介紹了C語(yǔ)言中的浮點(diǎn)數(shù)據(jù)類型,文章會(huì)從處理帶小數(shù)的數(shù)值的相關(guān)資料開(kāi)始介紹,感興趣的小伙伴的可以參考下面 文章的具體內(nèi)容2021-10-10
Qt連接MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)(保姆級(jí)成功版教程)
本文主要介紹了Qt連接MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
C語(yǔ)言帶你學(xué)會(huì)位段相關(guān)知識(shí)
這篇文章主要介紹了什么是位段,位段的聲明和結(jié)構(gòu)是類似的,位段的成員必須是 int、unsigned int 或signed int;位段的成員名后邊有一個(gè)冒號(hào)和一個(gè)數(shù)字,本文有詳細(xì)的代碼案例,感興趣的同學(xué)可以參考閱讀2023-04-04

