C++ Qt开发:QItemDelegate 自定义代理组件
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實(shí)現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點(diǎn)介紹QStyledItemDelegate自定義代理組件的常用方法及靈活運(yùn)用。
在Qt中,QStyledItemDelegate 類是用于創(chuàng)建自定義表格視圖(如QTableView和QTableWidget)的委托類,允許你自定義表格中每個單元格的外觀和交互。QStyledItemDelegate 是QItemDelegate 的子類,提供了更現(xiàn)代、更易用的接口。此處我們將實(shí)現(xiàn)對QTableView表格組件的自定義代理功能,例如默認(rèn)情況下表格中的缺省代理就是一個編輯框,我們只能夠在編輯框內(nèi)輸入數(shù)據(jù),而有時我們想選擇數(shù)據(jù)而不是輸入,此時就需要重寫編輯框?qū)崿F(xiàn)選擇的效果,代理組件常用于個性化定制表格中的字段類型。
1.1 概述代理類
代理類的作用是用來實(shí)現(xiàn)組件重寫的,例如TableView中默認(rèn)是可編輯的,之所以可編輯是因?yàn)镼t默認(rèn)為我們重寫了QLineEdit編輯框?qū)崿F(xiàn)的,也可理解為將組件嵌入到了表格中,實(shí)現(xiàn)了對表格的編輯功能。
在自定義代理中QAbstractItemDelegate是所有代理類的抽象基類,它用于創(chuàng)建自定義的項(xiàng)委托。提供了一個基本的框架,使得可以定制如何在視圖中繪制和編輯數(shù)據(jù)項(xiàng)。
QAbstractItemDelegate 是 QItemDelegate 的基類,而 QItemDelegate 則是 QStyledItemDelegate 的基類。這個繼承體系提供了不同層次的定制能力。我們繼承任何組件時都必須要包括如下4個函數(shù):
- CreateEditor() 用于創(chuàng)建編輯模型數(shù)據(jù)的組件,例如(QSpinBox組件)
- SetEditorData() 從數(shù)據(jù)模型獲取數(shù)據(jù),以供Widget組件進(jìn)行編輯
- SetModelData() 將Widget組件上的數(shù)據(jù)更新到數(shù)據(jù)模型
- UpdateEditorGeometry() 給Widget組件設(shè)置一個合適的大小
通過繼承 QAbstractItemDelegate 并實(shí)現(xiàn)這些函數(shù),讀者可創(chuàng)建一個定制的項(xiàng)委托,用于控制數(shù)據(jù)項(xiàng)在視圖中的外觀和交互行為。此處我們分別重寫三個代理接口,其中兩個ComBox組件用于選擇婚否,而第三個SpinBox組件則用于調(diào)節(jié)數(shù)值范圍,先來定義三個重寫部件。
1.2 自定義代理組件
這里我們以第一個SpinBox組件為例,要實(shí)現(xiàn)代理該組件,首先需要在項(xiàng)目上新建一個SpinDelegate類,并依次實(shí)現(xiàn)上述的四個方法,先來開創(chuàng)建流程;
- 選擇
addnew選中C++ Class輸入自定義類名稱QWintSpinDelegate,然后基類繼承QStyledItemDelegate/QMainWindow,然后下一步結(jié)束向?qū)?,同理其他功能的?chuàng)建也如此。
接著就是對該接口的重寫了,此處重寫代碼spindelegate.cpp如下所示,其關(guān)鍵位置的解釋可參考注釋部分。
#include "spindelegate.h"
#include <QSpinBox>
QWIntSpinDelegate::QWIntSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}
// 創(chuàng)建代理編輯組件
QWidget *QWIntSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QSpinBox *editor = new QSpinBox(parent); // 創(chuàng)建一個QSpinBox
editor->setFrame(false); // 設(shè)置為無邊框
editor->setMinimum(0);
editor->setMaximum(10000);
return editor; // 返回此編輯器
}
// 從數(shù)據(jù)模型獲取數(shù)據(jù),顯示到代理組件中
void QWIntSpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
// 獲取數(shù)據(jù)模型的模型索引指向的單元的數(shù)據(jù)
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); // 強(qiáng)制類型轉(zhuǎn)換
spinBox->setValue(value); // 設(shè)置編輯器的數(shù)值
}
// 將代理組件的數(shù)據(jù),保存到數(shù)據(jù)模型中
void QWIntSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); // 強(qiáng)制類型轉(zhuǎn)換
spinBox->interpretText(); // 解釋數(shù)據(jù),如果數(shù)據(jù)被修改后,就觸發(fā)信號
int value = spinBox->value(); // 獲取spinBox的值
model->setData(index, value, Qt::EditRole); // 更新到數(shù)據(jù)模型
}
// 設(shè)置組件大小
void QWIntSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
接著重寫接口floatspindelegate.cpp實(shí)現(xiàn)代碼如上述部分一致,唯一的變化是組件變了,代碼如下;
#include "floatspindelegate.h"
#include <QDoubleSpinBox>
QWFloatSpinDelegate::QWFloatSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}
QWidget *QWFloatSpinDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setDecimals(2);
editor->setMaximum(10000);
return editor;
}
void QWFloatSpinDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
float value = index.model()->data(index, Qt::EditRole).toFloat();
QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
spinBox->setValue(value);
}
void QWFloatSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
spinBox->interpretText();
float value = spinBox->value();
QString str=QString::asprintf("%.2f",value);
model->setData(index, str, Qt::EditRole);
}
void QWFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
最后重寫接口comboxdelegate.cpp其代碼如下所示;
#include "comboxdelegate.h"
#include <QComboBox>
QWComboBoxDelegate::QWComboBoxDelegate(QObject *parent):QItemDelegate(parent)
{
}
QWidget *QWComboBoxDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem("已婚");
editor->addItem("未婚");
editor->addItem("單身");
return editor;
}
void QWComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString str = index.model()->data(index, Qt::EditRole).toString();
QComboBox *comboBox = static_cast<QComboBox*>(editor);
comboBox->setCurrentText(str);
}
void QWComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
QString str = comboBox->currentText();
model->setData(index, str, Qt::EditRole);
}
void QWComboBoxDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
將部件導(dǎo)入到mainwindow.cpp主程序中,并將其通過ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);關(guān)聯(lián)部件到指定的table下標(biāo)索引上面。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化模型數(shù)據(jù)
model = new QStandardItemModel(4,6,this); // 初始化4行,每行六列
selection = new QItemSelectionModel(model); // 關(guān)聯(lián)模型
ui->tableView->setModel(model);
ui->tableView->setSelectionModel(selection);
// 添加表頭
QStringList HeaderList;
HeaderList << "序號" << "姓名" << "年齡" << "性別" << "婚否" << "薪資";
model->setHorizontalHeaderLabels(HeaderList);
// 批量添加數(shù)據(jù)
QStringList DataList[3];
QStandardItem *Item;
DataList[0] << "1001" << "admin" << "24" << "男" << "已婚" << "4235.43";
DataList[1] << "1002" << "guest" << "23" << "男" << "未婚" << "20000.21";
DataList[2] << "1003" << "lucy" << "37" << "女" << "單身" << "8900.23";
int Array_Length = DataList->length(); // 獲取每個數(shù)組中元素數(shù)
int Array_Count = sizeof(DataList) / sizeof(DataList[0]); // 獲取數(shù)組個數(shù)
for(int x=0; x<Array_Count; x++)
{
for(int y=0; y<Array_Length; y++)
{
// std::cout << DataList[x][y].toStdString().data() << std::endl;
Item = new QStandardItem(DataList[x][y]);
model->setItem(x,y,Item);
}
}
// 為各列設(shè)置自定義代理組件
// 0,4,5 代表第幾列 后面的函數(shù)則是使用哪個代理類的意思
ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);
ui->tableView->setItemDelegateForColumn(4,&comboBoxDelegate);
ui->tableView->setItemDelegateForColumn(5,&floatSpinDelegate);
}
MainWindow::~MainWindow()
{
delete ui;
}
運(yùn)行后,序號部分與薪資部分將變成一個SpinBox組件,讀者可自行調(diào)節(jié)大小,如下圖;
而婚否字段將被重寫成一個ComBoBox組件,這有助于讓用戶直接選擇一個狀態(tài),如下圖;
完整案例下載
總結(jié)
以上是生活随笔為你收集整理的C++ Qt开发:QItemDelegate 自定义代理组件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iQOO Neo8 Pro发布:全球首发
- 下一篇: iQOO Neo8系列正式发布!2299