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();
        }
    });
相关推荐
丁劲犇27 分钟前
让 Win10 上网本 Debug 模式 QUDPSocket 信号&槽 收发不丢包的方法总结
网络·windows·qt·网络协议·udp·qudpsocket·丢包
码农客栈5 小时前
qt QCommandLineParser详解
qt
去往火星5 小时前
windows下Qt5自动编译配置QtMqtt环境
开发语言·qt
键盘会跳舞5 小时前
【Qt项目实战】使用脚本拓展CPP应用程序(3)——从外部控制Lua脚本中的循环中断
qt·lua
codears5 小时前
Qt编写的文件传输工具
c++·qt
写bug的小屁孩15 小时前
用户信息界面删除好友功能
运维·服务器·c语言·c++·qt·websocket·http
qq_54702617919 小时前
RPC 详解
qt·网络协议·rpc
Liu-Eleven1 天前
Qt之自定义动态调控是否显示日志
开发语言·qt
「QT(C++)开发工程师」1 天前
Qt UDP客户端
开发语言·qt·udp