C++ 如何利用QStyledItemDelegate在QTreeWidget中拥有不同高度的QTreeWidgetItems?

C++ 如何利用QStyledItemDelegate在QTreeWidget中拥有不同高度的QTreeWidgetItems?,c++,qt,qwidget,qtreewidget,qtreewidgetitem,C++,Qt,Qwidget,Qtreewidget,Qtreewidgetitem,注意:原来问题不是由于实现了QStyledItemDelegate,而是因为在MyTreeWidget的构造函数中我调用了。以下代码和@scopchanov发布的解决方案有效且有效 QTreeWidget有一个受保护的方法,名为itemFromIndex(),这就是我如何使其可访问的方法: class MyTreeWidget : public QTreeWidget { Q_OBJECT public: MyTreeWidget(QWidget *parent) : QTree

注意:原来问题不是由于实现了
QStyledItemDelegate
,而是因为在
MyTreeWidget
的构造函数中我调用了。以下代码和@scopchanov发布的解决方案有效且有效

QTreeWidget
有一个受保护的方法,名为
itemFromIndex()
,这就是我如何使其可访问的方法:

class MyTreeWidget : public QTreeWidget {
    Q_OBJECT
public:
    MyTreeWidget(QWidget *parent) : QTreeWidget(parent) {
        setItemDelegate(new MyItemDelegate(this));
    }

    QTreeWidgetItem treeWidgetItemFromIndex(const QModelIndex& index) {
        return itemFromIndex(index);
    }
}
在我的
QStyledItemDelegate
中,我存储一个指向
MyTreeWidget
的指针,然后重写其虚拟
sizeHint()
方法,并根据
QTreeWidgetItem
的类型添加填充

class MyItemDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    MyItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {
        _myTreeWidget = dynamic_cast<MyTreeWidget*>(parent);
    }

    QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
        auto treeWidgetItem = _myTreeWidget->treeWidgetItemFromIndex(index);
        QSize padding;
        if (dynamic_cast<MyCustomTreeWidgetItem1*>(treeWidgetItem) {
            padding = {0, 5};
        } else if (dynamic_cast<MyCustomTreeWidgetItem2*>(treeWidgetItem) {
            padding = {0, 10};
        }

        return QStyledItemDelegate::sizeHint(option, index) + padding;
    }
}
类MyItemDelegate:公共QStyledItemDelegate
{
Q_对象
公众:
MyItemDelegate(QObject*父级):QStyledItemDelegate(父级){
_myTreeWidget=动态投影(父级);
}
QSize sizeHint(常数QStyleOptionViewItem&option、常数QModelIndex&index)常数{
auto treeWidgetItem=\u myTreeWidget->treeWidgetItemFromIndex(索引);
量化填充;
if(动态_铸造(树状边缘){
填充={0,5};
}else if(动态施法(树状边缘){
填充={0,10};
}
返回QStyledItemDelegate::sizeHint(选项,索引)+填充;
}
}
这不起作用,因为不会为每个
QTreeWidgetItem
调用委托的
sizeHint()

因此,我的文本选项在
MyCustomTreeWidgetItem1
的构造函数中调用
setSizeHint()
,这似乎也没有任何效果。是否因为存在委托而忽略它

另一个选项是设置
QWidget
中包含的
MyCustomTreeWidgetItem
的最小高度,这可以通过
QTreeWidget::setItemWidget()
实现

所以,从我使用代理的那一刻起,我似乎只限于大小。是我可以选择摆脱代理,还是我可以尝试其他方法

我知道很多人会说从
QTreeWidget
切换到
QTreeView
,但目前这是不可能的。

解决方案 我将以不同(更简单)的方式处理此问题:

  • 定义不同项目大小的枚举,例如:

     enum ItemType : int {
         IT_ItemWithRegularPadding,
         IT_ItemWithBigPadding
     };
    
  • 创建项目时,根据其类型在其用户数据中设置所需的大小,例如:

     switch (type) {
     case IT_ItemWithRegularPadding:
         item->setData(0, Qt::UserRole, QSize(0, 5));
         break;
     case IT_ItemWithBigPadding:
         item->setData(0, Qt::UserRole, QSize(0, 10));
         break;
     }
    
  • 在重新实现
    sizeHint
    时,从索引的数据中检索所需的大小,例如:

     QSize sizeHint(const QStyleOptionViewItem &option,
                    const QModelIndex &index) const override {
         return QStyledItemDelegate::sizeHint(option, index)
                 + index.data(Qt::UserRole).toSize();
     }
    
  • 例子 下面是我为您编写的一个示例,用于演示如何实施建议的解决方案:

    #include <QApplication>
    #include <QStyledItemDelegate>
    #include <QTreeWidget>
    #include <QBoxLayout>
    
    class Delegate : public QStyledItemDelegate
    {
    public:
        explicit Delegate(QObject *parent = nullptr) :
            QStyledItemDelegate(parent){
        }
    
        QSize sizeHint(const QStyleOptionViewItem &option,
                       const QModelIndex &index) const override {
            return QStyledItemDelegate::sizeHint(option, index)
                    + index.data(Qt::UserRole).toSize();
        }
    };
    
    class MainWindow : public QWidget
    {
    public:
        enum ItemType : int {
            IT_ItemWithRegularPadding,
            IT_ItemWithBigPadding
        };
    
        MainWindow(QWidget *parent = nullptr) :
            QWidget(parent) {
            auto *l = new QVBoxLayout(this);
            auto *treeWidget = new QTreeWidget(this);
            QList<QTreeWidgetItem *> items;
    
            for (int i = 0; i < 10; ++i)
                items.append(createItem(QString("item: %1").arg(i),
                                        0.5*i == i/2 ? IT_ItemWithRegularPadding
                                                     : IT_ItemWithBigPadding));
    
            treeWidget->setColumnCount(1);
            treeWidget->setItemDelegate(new Delegate(this));
            treeWidget->insertTopLevelItems(0, items);
    
            l->addWidget(treeWidget);
    
            resize(300, 400);
            setWindowTitle(tr("Different Sizes"));
        }
    
    private:
        QTreeWidgetItem *createItem(const QString &text, int type) {
            auto *item = new QTreeWidgetItem(QStringList(text));
    
            switch (type) {
            case IT_ItemWithRegularPadding:
                item->setData(0, Qt::UserRole, QSize(0, 5));
                break;
            case IT_ItemWithBigPadding:
                item->setData(0, Qt::UserRole, QSize(0, 10));
                break;
            }
    
            return item;
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    
    #包括
    #包括
    #包括
    #包括
    类委托:公共QStyledItemDelegate
    {
    公众:
    显式委托(QObject*parent=nullptr):
    QStyledItemDelegate(父级){
    }
    QSize sizeHint(常量QStyleOptionViewItem和option,
    常量QModelIndex和索引)常量覆盖{
    返回QStyledItemDelegate::sizeHint(选项,索引)
    +data(Qt::UserRole).toSize();
    }
    };
    类主窗口:公共QWidget
    {
    公众:
    枚举项类型:int{
    它是一个有规则填充的项目,
    它有很大的填充物
    };
    主窗口(QWidget*parent=nullptr):
    QWidget(父级){
    auto*l=新的QVBoxLayout(此);
    auto*treeWidget=新的QTreeWidget(此);
    QList项目;
    对于(int i=0;i<10;++i)
    items.append(createItem(QString(“项:%1”).arg(i),
    0.5*i==i/2?具有规则填充的IT_项
    :IT_items with big padding));
    treeWidget->setColumnCount(1);
    treeWidget->setItemDelegate(新委托(此));
    treeWidget->insertTopLevelItems(0,items);
    l->addWidget(树边条);
    调整大小(300400);
    setWindowTitle(tr(“不同尺寸”);
    }
    私人:
    QTreeWidgetItem*createItem(常量QString&text,int类型){
    auto*item=新的QTreeWidgetItem(QStringList(text));
    开关(类型){
    使用规则填充的大小写IT_项:
    item->setData(0,Qt::UserRole,QSize(0,5));
    打破
    使用大填充的大小写IT_项:
    item->setData(0,Qt::UserRole,QSize(0,10));
    打破
    }
    退货项目;
    }
    };
    int main(int argc,char*argv[])
    {
    质量保证申请a(argc、argv);
    主窗口w;
    w、 show();
    返回a.exec();
    }
    
    注意:此示例根据索引设置项目的大小-奇数或偶数。通过实现区分项目所需的逻辑,您可以随意更改此设置

    结果 给定的示例产生以下结果:


    偶数项和奇数项的高度不同。

    我能够找到问题的根源,问题是我的
    QTreeWidget
    uniformRowHeights
    属性设置为true。将其取下解决了问题。但是,您的解决方案消除了对
    动态施法的需要,因此我将其升级。@ArmaniStyles,my解决方案不仅更简单,而且它是通过使用代理来获得不同项目高度的正确方法。如果您让代理知道使用它的视图和使用它的方法,就像您所做的那样,这称为紧耦合,会在项目的后期给您带来麻烦。因此,我建议您使用我描述的方法。哟你最好接受这个答案,因为它为关于达到不同高度的问题提供了一个有效的解决方案。我同意你的解决方案更简单,但我不同意紧耦合部分,因为它只适用于你的样本。事实上,我可能有3种不同类型的
    qtreewigetitem
    和ac通过对它们进行子分类,我可以得到这样的逻辑:m的子类