如何使用 QStyledItemDelegate 在 QTreeWidget 中拥有不同高度的 QTreeWidgetItems?
How to have QTreeWidgetItems of different heights in a QTreeWidget utilizing QStyledItemDelegate?
注意:事实证明问题不是由于 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
,但目前还不可能。
解决方案
我会以不同(更简单)的方式解决这个问题:
为不同的项目大小定义枚举,例如:
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
的实现,而是在 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
,但目前还不可能。
解决方案
我会以不同(更简单)的方式解决这个问题:
为不同的项目大小定义枚举,例如:
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();
}
注意:此示例根据其索引(奇数或偶数)设置项目的大小。通过实施您需要区分项目的逻辑来随意更改此设置。
结果
给出的示例产生以下结果:
偶数项和奇数项的高度不同。