如何使用 QStyledItemDelegate 在 QTreeWidget 中拥有不同高度的 QTreeWidgetItems?
Posted
技术标签:
【中文标题】如何使用 QStyledItemDelegate 在 QTreeWidget 中拥有不同高度的 QTreeWidgetItems?【英文标题】:How to have QTreeWidgetItems of different heights in a QTreeWidget utilizing QStyledItemDelegate? 【发布时间】:2021-02-12 10:20:24 【问题描述】:注意:原来问题不是由于QStyledItemDelegate
的实现,而是在MyTreeWidget
的构造函数中我调用了setUniformRowHeights(true)。下面的代码和@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;
这不起作用,因为代理的sizeHint()
不会被每个QTreeWidgetItem
调用。
所以我在MyCustomTreeWidgetItem1
的构造函数中调用setSizeHint()
的文本选项似乎也没有任何效果。 Qt
是否因为有委托而忽略它?
另一个选项是设置包含在MyCustomTreeWidgetItem
中的QWidget
的最小高度,这可以通过QTreeWidget::setItemWidget()
实现。
所以看起来在我使用委托的那一刻,我只限于大小。我可以选择摆脱委托还是可以尝试其他方法?
我知道很多人会说从QTreeWidget
切换到QTreeView
,但目前不可能。
【问题讨论】:
【参考方案1】:解决方案
我会以不同(更简单)的方式解决这个问题:
为不同的项目大小定义一个枚举,例如:
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();
注意:此示例根据其索引设置项目的大小 - 奇数或偶数。随意通过实施区分项目所需的逻辑来改变这一点。
结果
给定的示例产生以下结果:
偶数项和奇数项的高度不同。
【讨论】:
我能够深入了解我的问题,问题是我的QTreeWidget
将uniformRowHeights
属性设置为true。把它取下来解决了这个问题。
您的解决方案消除了对dynamic_cast
的需求,所以我赞成它。
@ArmaniStyles,我的解决方案不仅更简单,而且是通过使用委托来获得不同项目高度的正确方法。如果您让代理知道使用它的视图并使用它的方法,就像您所做的那样,这称为紧密耦合,并且会在项目的后期阶段给您带来麻烦。所以我建议你使用我描述的方法。你不妨接受这个答案,因为它为关于达到不同高度的问题提供了一个有效的解决方案。
我同意你的观点,你的解决方案更简单,但我不同意紧耦合部分,因为它只适用于你的样本。事实是我可能有 3 种不同类型的 QTreeWidgetItem
并通过对它们进行子类化来实现。然后我可能有这样的逻辑,即我的QTreeWidget
的子类正在创建这些项目。这意味着QTreeWidget
将完全了解这些类型。一旦它完全意识到,在同一个源文件中调用dynamic_cast
是没有害处的。
@ArmaniStyles,你描述的用例确实很有趣,如果你决定在另一篇文章中更具体地描述它,我很乐意为它寻找合适的解决方案。以上是关于如何使用 QStyledItemDelegate 在 QTreeWidget 中拥有不同高度的 QTreeWidgetItems?的主要内容,如果未能解决你的问题,请参考以下文章
QStyledItemDelegate中如何根据qStylesheet进行绘制
在带有 QSqlQueryModel 的 QListView 上使用 QStyledItemDelegate
重新实现 QStyledItemDelegate::paint - 如何获取子元素坐标?