#c #qt #qwidget #qtreewidget #qtreewidgetitem
#c #qt #qwidget #qtreewidget #qtreewidgetitem
Вопрос:
ПРИМЕЧАНИЕ: оказалось, что проблема была связана не с реализацией 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 QModelIndexamp; 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 QStyleOptionViewItemamp; option, const QModelIndexamp; 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
.
Итак, мои текстовые параметры для вызова setSizeHint()
в конструкторе MyCustomTreeWidgetItem1
, и это, похоже, тоже не имело никакого эффекта. Qt
Игнорирует ли это, потому что есть делегат?
Другим вариантом было установить минимальную высоту a QWidget
, которая содержится в MyCustomTreeWidgetItem
, что стало возможным благодаря QTreeWidget::setItemWidget()
.
Итак, похоже, что в тот момент, когда я использую делегат, я ограничен только размером. Есть ли у меня возможность избавиться от делегата или есть что-то еще, что я могу попробовать?
Я знаю, что многие люди сказали бы переключиться с a QTreeWidget
на a 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 amp;option, const QModelIndex amp;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 amp;option,
const QModelIndex amp;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 amp;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();
}
Примечание: В этом примере размер элемента устанавливается в зависимости от его индекса — четного или нечетного. Не стесняйтесь изменять это, реализуя логику, необходимую для различения элементов.
Результат
Приведенный пример дает следующий результат:
Четные и нечетные элементы имеют разную высоту.
Комментарии:
1. Я смог разобраться в своей проблеме, проблема заключалась в том, что мое
QTreeWidget
uniformRowHeights
свойство устанавливало значение true. Удаление этого решило проблему.2. Однако ваше решение устраняет необходимость
dynamic_cast
, поэтому я поддержал его.3. @ArmaniStyles, мое решение не только проще, но и является правильным способом иметь разные высоты элементов с помощью делегата. Если вы сообщите делегату о представлении, которое его использует, и используете его методы, как вы это делаете, это называется тесной связью и может вызвать проблемы на более позднем этапе вашего проекта. Поэтому я предлагаю вам использовать подход, который я описал. Вы могли бы также принять ответ, поскольку он дает правильное решение вопроса о достижении разных высот.
4. Я согласен с вами в том, что ваше решение проще, но я не согласен с частью жесткой связи, поскольку она применима только к вашему образцу. Дело в том, что у меня может быть 3 разных типа
QTreeWidgetItem
и достичь этого путем их подклассификации. Тогда у меня может быть такая логика, что мой подклассQTreeWidget
создает эти элементы. Это означает, чтоQTreeWidget
они будут полностью знать об этих типах. Как только он полностью осознает, нет никакого вреда в вызовеdynamic_cast
того же исходного файла.5. @ArmaniStyles, описанный вами вариант использования действительно интересен, и я был бы очень рад найти для него подходящее решение, если вы решите описать его более конкретно в другом сообщении.