1. 先举个例子
1班有3个学生:张三、李四、王五
4个学生属性:语文 数学 英语 性别。
语文 数学 英语使用QDoubleSpinBox* 编辑,范围为0到100,1位小数
性别使用QComboBox* 编辑,选项为:男、女
实现效果:
2. 按照例子实现
2.1 自定义一个QStandardItemModel 来存数据
c++
#include <QApplication>
#include <QTreeView>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QStyledItemDelegate>
#include <QHeaderView>
class CustomStandardItemModel : public QStandardItemModel
{
public:
CustomStandardItemModel(QObject *parent = nullptr);
Qt::ItemFlags flags(const QModelIndex &index) const override;
};
c++
class CustomStandardItemModel : public QStandardItemModel
{
public:
CustomStandardItemModel(QObject *parent = nullptr);
Qt::ItemFlags flags(const QModelIndex &index) const override;
};
CustomStandardItemModel::CustomStandardItemModel(QObject *parent) : QStandardItemModel(parent)
{
// Set up the model
setColumnCount(2);
setHorizontalHeaderLabels(QStringList()<< "属性" << "值") ;
// Root item
QStandardItem *rootItem = invisibleRootItem();
QStandardItem *classItem = new QStandardItem("1班");
rootItem->appendRow(classItem);
// Students
QStringList students = {"张三", "李四", "王五"};
for (const QString &student : students)
{
QStandardItem *studentItem = new QStandardItem(student);
classItem->appendRow(studentItem);
// Subjects
QStringList subjects = {"语文", "数学", "英语", "性别"};
for (const QString &subject : subjects)
{
QStandardItem *subjectItem = new QStandardItem(subject);
subjectItem->setEditable(false); // Property column is not editable
QStandardItem *valueItem = new QStandardItem(subject == "性别"?"女":"100.0");
valueItem->setEditable(true); // Value column is editable for level 2
studentItem->appendRow(QList<QStandardItem*>() << subjectItem << valueItem);
}
}
}
Qt::ItemFlags CustomStandardItemModel::flags(const QModelIndex &index) const
{
if (index.column() == 1 && index.parent().isValid()) {
QStandardItem *item = itemFromIndex(index);
if (item && item->hasChildren()) {
// If the item has children, it's a student node, make value column not editable
return QAbstractItemModel::flags(index) & ~Qt::ItemIsEditable;
}
}
return QStandardItemModel::flags(index);
}
2.2 自定义一个QStyledItemDelegate 来显示不同的QWidget控件
cpp
class CustomDelegate : public QStyledItemDelegate
{
public:
CustomDelegate(QObject *parent = nullptr) ;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
};
cpp
CustomDelegate::CustomDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
QWidget *CustomDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 1 && index.parent().isValid())
{
QString property = index.sibling(index.row(), 0).data().toString();
if (property == "语文" || property == "数学" || property == "英语")
{
QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent);
spinBox->setRange(0, 100);
spinBox->setDecimals(1);
return spinBox;
} else if (property == "性别") {
QComboBox *comboBox = new QComboBox(parent);
comboBox->addItem("男");
comboBox->addItem("女");
return comboBox;
}
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
2.3 使用 QTreeView 来显示
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CustomStandardItemModel* model;
CustomDelegate* delegate;
QTreeView *treeView;
treeView = new QTreeView();
treeView->setObjectName(QString::fromUtf8("treeView"));
treeView->setGeometry(QRect(40, 30, 241, 501));
model = new CustomStandardItemModel();
delegate = new CustomDelegate();
treeView->setModel(model);
treeView->setItemDelegate(delegate);
treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
treeView->expandAll();
treeView->show();
bool ret = a.exec();
delete model;
delete delegate;
delete treeView;
return ret;
}
2.4 运行效果
修改语文、数学、英语时,双击后,变成QDoubleSpinBox 控件
修改性别时,双击后,变成QComboBox控件
3. 增加修改的信号
要在 CustomDelegate 中实现值修改时发送信号,通知告知是哪个学生的哪个属性的值变成了多少,可以按照以下步骤进行修改:
定义信号:在 CustomDelegate 类中添加一个信号,用于在值修改时发送。
捕获编辑器值的变化:在 setModelData 方法中捕获编辑器的值变化,并发出信号。
修改代码:
cpp
class CustomDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
CustomDelegate(QObject *parent = nullptr) ;
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
signals:
void valueChanged( QString &student, QString &property, QVariant value) const;
};
cpp
CustomDelegate::CustomDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
QWidget *CustomDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 1 && index.parent().isValid()) {
QString property = index.sibling(index.row(), 0).data().toString();
if (property == "语文" || property == "数学" || property == "英语") {
QDoubleSpinBox *spinBox = new QDoubleSpinBox(parent);
spinBox->setRange(0, 100);
spinBox->setDecimals(1);
return spinBox;
} else if (property == "性别") {
QComboBox *comboBox = new QComboBox(parent);
comboBox->addItem("男");
comboBox->addItem("女");
return comboBox;
}
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
void CustomDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.column() == 1 && index.parent().isValid()) {
QString property = index.sibling(index.row(), 0).data().toString();
QString student = index.parent().data().toString();
if (QDoubleSpinBox *spinBox = qobject_cast<QDoubleSpinBox*>(editor))
{
double value = spinBox->value();
model->setData(index, value);
emit valueChanged(student, property, QVariant::fromValue(value));
}
else if (QComboBox *comboBox = qobject_cast<QComboBox*>(editor))
{
QString value = comboBox->currentText();
model->setData(index, value);
emit valueChanged(student, property, QVariant::fromValue(value));
}
}
else
{
QStyledItemDelegate::setModelData(editor, model, index);
}
}
连接信号和槽
cpp
// 连接信号槽
QObject::connect(delegate, &CustomDelegate::valueChanged, [&](const QString &student, const QString &property, QVariant value)
{
if (property == "性别")
{
qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toString();
}
else
{
qDebug() << "学生:" << student << "属性:" << property << "值:" << value.toDouble();
}
});