Custom Widget in QListView/QTreeView expands whole width
-
Hello.
I have tried to implement custom model based on
QStandadItemModel
to store pointers to custom widgets and display this widgets inQListView
andQTreeView
. The example code could be found on GitHub.This works almost perfectly except two things:
- In QListView I'd like to represent static view of widget. So I have tried to use
Qt::DecorationRole
but it not use my style defined in QSS file. Code snippet:setIconSize(QSize(200, 200)); ... auto w = new Widget; ... m_model->setData(index, QIcon(w->grab()), Qt::DecorationRole);
- In QTreeView I'd like to represent the real widget. But it expands the whole width of QTreeView widget. Code snippet:
void TreeWidget::dataChanged(const QModelIndex &topLeft, ... auto expr = m_model->data(topLeft).value<Widget*>(); setIndexWidget(topLeft, expr);
To prevent expanding I have tried to set some size policy and size hint:
Widget::Widget(QString text, QWidget *parent) : QFrame(parent) { ... setBaseSize(sizeHint()); setSizeIncrement(QSize(1, 1)); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } QSize Widget::sizeHint() const { return QSize(80, 80); }
Any advice and suggestions will be greatly appreciated. Thank you very much.
- In QListView I'd like to represent static view of widget. So I have tried to use
-
I have found first part of solution.
Based on star delegate example I've added my own delegate like this:
QWidget *Delegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(parent); Q_UNUSED(option); Q_UNUSED(index); return nullptr; } void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (index.data().canConvert<Widget*>()) { auto w = qvariant_cast<Widget*>(index.data()); w->paint(painter, option.rect); } else QStyledItemDelegate::paint(painter, option, index); } QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { if (index.data().canConvert<Widget*>()) return qvariant_cast<Widget*>(index.data())->sizeHint(); else return QStyledItemDelegate::sizeHint(option, index); }
The implementation of `Widget::paint`` method is:
void Widget::paint(QPainter *painter, const QRect &rect) { painter->save(); painter->translate(rect.x(), rect.y()); render(painter); painter->restore(); }
-
I have updated my delegate to show widget in parent view.
To achieve this I have changed the implementation of
Delegate::paint()
method like this:if (!index.data().canConvert<Widget*>()) return; QAbstractItemView *p = dynamic_cast<QAbstractItemView*>(parent()); if (p) { auto w = qvariant_cast<Widget*>(index.data()); w->setParent(p); w->paint(painter, option.rect, m_enabled); } else qDebug() << "FATAL: Delegate's parent is not a QAbstractItemView subclass:" << parent();
I have also changed
Widget::paint()
like this:void Widget::paint(QPainter *painter, const QRect &rect, bool enabled) { painter->save(); move(rect.topLeft()); setEnabled(enabled); show(); painter->restore(); }
But I have one more issue with this code. I can't move widgets between views by pressing on them. I have to press an area next to widget to start dragging. How to avoid this?