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 in QListView and QTreeView. 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.



  • 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?



  • Finaly I have finished my little example!

    Previous version have been really buggy in items move. So I have to subclass from QAbstractItemModel. Many thanks to @Patou355 with his solution.

    NB I haven't deal with mousePressEvent() yet.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.