TableDelegate 自定義代理組件的主要作用是對原有表格進行調整,例如默認情況下Table中的缺省代理就是一個編輯框,我們只能夠在編輯框內輸入數據,而有時我們想選擇數據而不是輸入,此時就需要重寫編輯框實現選擇的效果,代理組件常用於個性化定制Table表格中的字段類型。
代理類的作用是用來實現重寫的,例如我們的TableView
中默認是可編輯的,這個可編輯的組件是QT默認為我們重寫了QLineEdit
組件,也可理解為將組件嵌入到了表格中,實現了對表格的編輯功能。
在自定義代理中QAbstractItemDelegate
是所有代理類的抽象基類,我們繼承任何組件時都必須要包括如下4個函數:
- CreateEditor() 用於創建編輯模型數據的組件,例如(QSpinBox組件)
- SetEditorData() 從數據模型獲取數據,以供Widget組件進行編輯
- SetModelData() 將Widget組件上的數據更新到數據模型
- UpdateEditorGeometry() 給Widget組件設置一個合適的大小
此處我們分別重寫三個代理接口,其中兩個ComBox
組件用於選擇婚否,SpinBox
組件用於調節數值范圍,先來定義三個重寫部件。
先來實現一個代理,代理到Spin
組件上,首先需要在項目上右鍵
- 選擇addnew -> C++Class 輸入自定義類名稱
QWintSpinDelegate
,然后基類繼承QStyledItemDelegate/QMainWindow
,然后下一步結束向導。
重寫接口spindelegate.cpp
代碼如下.
#include "spindelegate.h"
#include <QSpinBox>
QWIntSpinDelegate::QWIntSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}
// https://www.cnblogs.com/lyshark
QWidget *QWIntSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
//創建代理編輯組件
Q_UNUSED(option);
Q_UNUSED(index);
QSpinBox *editor = new QSpinBox(parent); //創建一個QSpinBox
editor->setFrame(false); //設置為無邊框
editor->setMinimum(0);
editor->setMaximum(10000);
return editor; //返回此編輯器
}
void QWIntSpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
//從數據模型獲取數據,顯示到代理組件中
//獲取數據模型的模型索引指向的單元的數據
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); //強制類型轉換
spinBox->setValue(value); //設置編輯器的數值
}
void QWIntSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
//將代理組件的數據,保存到數據模型中
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); //強制類型轉換
spinBox->interpretText(); //解釋數據,如果數據被修改后,就觸發信號
int value = spinBox->value(); //獲取spinBox的值
model->setData(index, value, Qt::EditRole); //更新到數據模型
}
void QWIntSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
//設置組件大小
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
重寫接口floatspindelegate.cpp
代碼如下.
#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);
}
// https://www.cnblogs.com/lyshark
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;
}
// https://www.cnblogs.com/lyshark
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);
}
將部件導入到mainwindow.cpp
中,並將其通過ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);
關聯部件到指定的table下標索引上面。
#include "mainwindow.h"
#include "ui_mainwindow.h"
// https://www.cnblogs.com/lyshark
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 初始化模型數據
model = new QStandardItemModel(4,6,this); // 初始化4行,每行六列
selection = new QItemSelectionModel(model); // 關聯模型
ui->tableView->setModel(model);
ui->tableView->setSelectionModel(selection);
// 添加表頭
QStringList HeaderList;
HeaderList << "序號" << "姓名" << "年齡" << "性別" << "婚否" << "薪資";
model->setHorizontalHeaderLabels(HeaderList);
// 批量添加數據
QStringList DataList[3];
QStandardItem *Item;
DataList[0] << "1001" << "admin" << "24" << "男" << "已婚" << "4235.43";
DataList[1] << "1002" << "lyshark" << "23" << "男" << "未婚" << "10000.21";
DataList[2] << "1003" << "lucy" << "37" << "女" << "單身" << "8900.23";
int Array_Length = DataList->length(); // 獲取每個數組中元素數
int Array_Count = sizeof(DataList) / sizeof(DataList[0]); // 獲取數組個數
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);
}
}
// 為各列設置自定義代理組件
// 0,4,5 代表第幾列 后面的函數則是使用哪個代理類的意思
ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);
ui->tableView->setItemDelegateForColumn(4,&comboBoxDelegate);
ui->tableView->setItemDelegateForColumn(5,&floatSpinDelegate);
}
MainWindow::~MainWindow()
{
delete ui;
}
代理部件關聯后,再次運行程序,會發現原來的TableWidget
組件中的編輯框已經替換為了選擇框等組件: