QT6(QStandardItemModel和QTableView及自定义代理)
QT6
QStandardItemModel和QTableView
- QStandardItemModel:jag:基于项的模型类在,每个项是一个QStandarditem对象
- QtableView:显示二维数据的组件
- QItemSelectionModel:选择模型,用于跟踪视图组件的单元格选择状态,通过它可以获得选中单元格的模型索引,设置选择状态
QTableView常用方法和属性
外观属性
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
showGrid | bool | 是否显示网格线 |
gridStyle | Qt::PenStyle | 网格线样式(如 Qt::SolidLine , Qt::DotLine ) |
alternatingRowColors | bool | 是否使用交替行颜色 |
表头控制
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
horizontalHeader() | QHeaderView* | 获取水平表头对象 |
verticalHeader() | QHeaderView* | 获取垂直表头对象 |
horizontalHeaderVisible | bool | 水平表头是否可见 |
verticalHeaderVisible | bool | 垂直表头是否可见 |
选择行为
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
selectionBehavior | QAbstractItemView::SelectionBehavior | 选择行为(选择项、行或列) |
selectionMode | QAbstractItemView::SelectionMode | 选择模式(如单选、多选) |
编辑特性
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
editTriggers | QAbstractItemView::EditTriggers | 编辑触发器(如双击编辑) |
排序功能
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
sortingEnabled | bool | 是否启用排序 |
调整尺寸
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
resizeColumnToContents(int) | void | 调整某列宽度以适应内容 |
resizeColumnsToContents() | void | 调整所有列宽度以适应内容 |
resizeRowToContents(int) | void | 调整某行高度以适应内容 |
resizeRowsToContents() | void | 调整所有行高度以适应内容 |
模型操作
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
setModel(QAbstractItemModel*) | void | 设置数据模型 |
model() | QAbstractItemModel* | 获取当前数据模型 |
交互相关
属性/方法名 | 类型/返回值 | 说明 |
---|---|---|
setIndexWidget(const QModelIndex &, QWidget*) | void | 在指定索引处设置部件 |
代码测试
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QLabel>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QFile>
#include <QRegularExpression>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);labCurrFile = new QLabel("当前文件",this);labCurrFile->setMinimumWidth(200);labCellpos = new QLabel("当前单元格",this);labCurrFile->setMinimumWidth(200);labCellText = new QLabel("单元格内容",this);labCellText->setMinimumWidth(200);ui->statusbar->addWidget(labCurrFile);ui->statusbar->addWidget(labCellpos);ui->statusbar->addWidget(labCellText);m_model = new QStandardItemModel(2,FixedColumCount,this);m_selection = new QItemSelectionModel(m_model,this);ui->tableView->setModel(m_model);ui->tableView->setSelectionModel(m_selection);ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);connect(m_selection,&QItemSelectionModel::currentChanged,this,&MainWindow::do_currentChanged);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::do_currentChanged(const QModelIndex ¤t, const QModelIndex &prevous)
{if(current.isValid()){labCellpos->setText(QString::asprintf("当前单元格:%d行,%d列",current.row(),current.column()));QStandardItem* aItem = m_model->itemFromIndex(current);labCellText->setText("单元格内容:"+ aItem->text());// 判断当前选择的item是否为粗体ui->actionBold->setChecked(aItem->font().bold());}
}void MainWindow::on_actionOpenFile_triggered()
{QString curPath = QCoreApplication::applicationFilePath();QString aFileName = QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);;所有文件(*.*)");if(aFileName.isEmpty())return;QFile aFile(aFileName);if(!aFile.open(QIODevice::ReadOnly|QIODevice::Text))return;QStringList aFileContent;ui->plainTextEdit->clear();QTextStream aStream(&aFile);while(!aStream.atEnd()){QString str = aStream.readLine();ui->plainTextEdit->appendPlainText(str);aFileContent.append(str);}aFile.close();labCurrFile->setText("当前文件" + aFileName);ui->actionAddLine->setEnabled(true);ui->actionInsertLine->setEnabled(true);ui->actionDelLine->setEnabled(true);iniModelData(aFileContent);
}void MainWindow::iniModelData(QStringList& aFileContext)
{int rowCnt = aFileContext.size();m_model->setRowCount(rowCnt - 1);QString header = aFileContext.at(0);QStandardItem *aItem;int j;// 获取表头QStringList headerList = header.split(QRegularExpression(R"(\s)"),Qt::SkipEmptyParts);// 设置表头m_model->setHorizontalHeaderLabels(headerList);for(int i = 0; i < rowCnt ; i++){QString aLineText = aFileContext.at(i);QStringList tempList = aLineText.split(QRegularExpression(R"(\s)"),Qt::SkipEmptyParts);for(j = 0 ; j < FixedColumCount -1 ; ++j){aItem = new QStandardItem(tempList.at(j));// 设置每一项m_model->setItem(i-1,j,aItem);}// 设置最后一项aItem = new QStandardItem(headerList.at(j));aItem->setCheckable(true);aItem->setBackground(QBrush(Qt::yellow));if(tempList.at(j) == "0")aItem->setCheckState(Qt::Unchecked);elseaItem->setCheckState(Qt::Checked);m_model->setItem(i-1,j,aItem);}
}void MainWindow::on_actionDataPreview_triggered()
{ui->plainTextEdit->clear();QStandardItem* aItem;QString str;int j;for(int i = 0; i<m_model->columnCount();i++){aItem = m_model->horizontalHeaderItem(i);str+=aItem->text();str+="\t";}ui->plainTextEdit->appendPlainText(str);for(int i = 0;i < m_model->rowCount();i++){str="";for(j = 0; j<m_model->columnCount() -1;j++){aItem = m_model->item(i,j);str+=aItem->text();str+="\t";}aItem = m_model->item(i,j);if(aItem->checkState()==Qt::Checked){str+="是";}else{str+="否";}ui->plainTextEdit->appendPlainText(str);}
}void MainWindow::on_actionAddLine_triggered()
{QList<QStandardItem*> aItemList;QStandardItem* aItem;for(int i = 0;i<m_model->columnCount()-1;i++){aItem = new QStandardItem("0");aItemList << aItem;}QString str = m_model->headerData(m_model->columnCount() - 1,Qt::Horizontal).toString();aItem = new QStandardItem(str);aItem->setCheckable(true);aItem->setBackground(QBrush(Qt::yellow));aItemList << aItem;m_model->insertRow(m_model->rowCount(),aItemList);m_selection->clearSelection();m_selection->setCurrentIndex(m_model->index(m_model->rowCount() - 1,0),QItemSelectionModel::Select);
}void MainWindow::on_actionInsertLine_triggered()
{QList<QStandardItem*> aItemList;QStandardItem* aItem;for(int i = 0;i<m_model->columnCount()-1;i++){aItem = new QStandardItem("123");aItemList << aItem;}QString str = m_model->headerData(m_model->columnCount() - 1,Qt::Horizontal).toString();aItem = new QStandardItem(str);aItem->setCheckable(true);aItem->setBackground(QBrush(Qt::yellow));aItemList << aItem;QModelIndex curIndex = m_selection->currentIndex();m_model->insertRow(m_selection->currentIndex().row(),aItemList);m_selection->clearSelection();m_selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}void MainWindow::on_actionDelLine_triggered()
{QModelIndex curIndex = m_selection->currentIndex();if(curIndex.row() != m_model->columnCount()-1){m_selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);m_model->removeRow(curIndex.row());}else{m_model->removeRow(curIndex.row());}
}void MainWindow::on_actionLeft_triggered()
{if(!m_selection->hasSelection())return;QModelIndexList indexList = m_selection->selectedIndexes();for(auto index:indexList){m_model->itemFromIndex(index)->setTextAlignment(Qt::AlignLeft|Qt::AlignVCenter);}
}void MainWindow::on_actionCenter_triggered()
{if(!m_selection->hasSelection())return;QModelIndexList indexList = m_selection->selectedIndexes();for(auto index:indexList){m_model->itemFromIndex(index)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);}
}void MainWindow::on_actionRight_triggered()
{if(!m_selection->hasSelection())return;QModelIndexList indexList = m_selection->selectedIndexes();for(auto index:indexList){m_model->itemFromIndex(index)->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);}
}void MainWindow::on_actionBold_triggered(bool checked)
{if(!m_selection->hasSelection())return;QModelIndexList indexList = m_selection->selectedIndexes();for(auto index:indexList){QFont font = m_model->itemFromIndex(index)->font();font.setBold(checked);m_model->itemFromIndex(index)->setFont(font);}
}
效果展示
自定义代理
- 在模型视图结构中,代理的作用就是在视图组件进入编辑状态编辑某个项时,提供一个临时的编辑器用于数据编辑,默认的代理编辑器是QLineEdit编辑框
- 可以对这个默认的编辑框进行替换,比如QSpinBox、QDoubleSpinBox、ComboBox
继承关系
必须实现以下几个函数
- createEditor():创建用于编辑模型数据的widget组件,如QSpinBox,QComboBox
- setEditorData():从数据模型获取数据,供widget组件进行编辑
- setModelData():将widget上的数据更新到数据模型
- updateditorGeometry():用于给widget组件设置一个合适的大小
代码测试
TComboBoxDelegate.cpp
#include "tcomboboxdelegate.h"
#include <QComboBox>
TComboBoxDelegate::TComboBoxDelegate(QObject *parent): QStyledItemDelegate{parent}
{}QWidget *TComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(option);Q_UNUSED(index);QComboBox* editor = new QComboBox(parent);editor->setEditable(m_editTable);for(auto item:m_itemList){editor->addItem(item);}return editor;
}void TComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{QComboBox* comBoBox = dynamic_cast<QComboBox*>(editor);QString str = index.model()->data(index,Qt::EditRole).toString();comBoBox->setCurrentText(str);
}void TComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{QComboBox* comBoBox = dynamic_cast<QComboBox*>(editor);QString str = comBoBox->currentText();model->setData(index,str,Qt::EditRole);
}void TComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(index);editor->setGeometry(option.rect);}void TComboBoxDelegate::setItems(QStringList itemList, bool editTable)
{m_itemList = itemList;m_editTable = editTable;
}
TFloatSpinDelegate.cpp
#include "tfloatspindelegate.h"
#include <QDoubleSpinBox>
TFloatSpinDelegate::TFloatSpinDelegate(QObject *parent): QStyledItemDelegate{parent}
{}QWidget *TFloatSpinDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{QDoubleSpinBox* editor = new QDoubleSpinBox(parent);editor->setFrame(false);editor->setMinimum(0);editor->setMaximum(5000);return editor;
}void TFloatSpinDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);double value = index.model()->data(index,Qt::EditRole).toDouble();spinBox->setValue(value);
}void TFloatSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);double value = spinBox->value();model->setData(index,value,Qt::EditRole);
}void TFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(index);editor->setGeometry(option.rect);
}
TSpinBoxDelegate.cpp
#include "tspinboxdelegate.h"
#include <QSpinBox>
TSpinBoxDelegate::TSpinBoxDelegate(QObject *parent): QStyledItemDelegate{parent}{}QWidget *TSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{QSpinBox* editor = new QSpinBox(parent);editor->setFrame(false);editor->setMinimum(0);editor->setMaximum(5000);return editor;
}void TSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);int value = index.model()->data(index,Qt::EditRole).toInt();spinBox->setValue(value);
}void TSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);int value = spinBox->value();model->setData(index,value,Qt::EditRole);
}void TSpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(index);editor->setGeometry(option.rect);
}
MainWindow.cpp
// 创建代理类对象intSpinDelegate = new TSpinBoxDelegate(this);// 通过列来设置ui->tableView->setItemDelegateForColumn(0,intSpinDelegate);doubleSpinDelegate = new TFloatSpinDelegate(this);ui->tableView->setItemDelegateForColumn(1,doubleSpinDelegate);ui->tableView->setItemDelegateForColumn(2,doubleSpinDelegate);ui->tableView->setItemDelegateForColumn(3,doubleSpinDelegate);comBoDelegate = new TComboBoxDelegate(this);QStringList strList;strList << "优" << "良" << "中" << "差";comBoDelegate->setItems(strList,false);ui->tableView->setItemDelegateForColumn(4,comBoDelegate);
效果展示