QTreeView 例子

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();
        }
    });
相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能15 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G15 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt