1

I would like to use a QListView with custom widgets that contain QSlider and QSpinBox widgets. I succeeded in creating the QListView with a new custom item delegate that displays the custom widgets but the mouse events are not propagated to the custom widgets.

It's not possible to slide the QSlider or change the value of the QSpinBox. The user can not interact with the items.

I'm new to Qt and I guess it's because the custom widgets are not children of the list view. I tried to associate the widgets to the list view (in the item delegate constructor) but that does not work.

I also tried to propagate the item delegate's events to the widgets using the QWidget::event() functions, but that does not work.

Does any one have an idea ?

Here is the custom widget :

Here is the QListView displaying the custom widget :

Here is the code of my custom item delegate :

#include <QPainter>
#include "layeritemwidgetdelegate.h"
#include "../../libs/debug/debug.h"

LayerItemWidgetDelegate::LayerItemWidgetDelegate( QObject *ptParent ) :
    QItemDelegate( ptParent ),
    m_ptItemWidget( new LayerItemWidget() )
{
}

LayerItemWidgetDelegate::~LayerItemWidgetDelegate()
{
    delete m_ptItemWidget;
}

void LayerItemWidgetDelegate::paint( QPainter *ptPainter, const QStyleOptionViewItem &tOption, const QModelIndex &tIndex ) const
{
    QPalette tPalette;

    //  Resize the item widget
    m_ptItemWidget->resize( tOption.rect.size() );

    // Change the background color of the widget if it is selected.
    if( QStyle::State_Selected == ( tOption.state & QStyle::State_Selected ) )
        tPalette.setBrush( QPalette::Window, QBrush( QColor( Qt::lightGray ) ) );
    else
        tPalette.setBrush( QPalette::Window, QBrush( QColor( Qt::transparent ) ) );
    m_ptItemWidget->setPalette( tPalette );

    //  Paint the widget
    ptPainter->save();
    ptPainter->translate( tOption.rect.topLeft() );
    m_ptItemWidget->render( ptPainter );
    ptPainter->restore();
}

QSize LayerItemWidgetDelegate::sizeHint(const QStyleOptionViewItem &tOption, const QModelIndex &tIndex) const
{
    Q_UNUSED( tOption )
    Q_UNUSED( tIndex )
    return QSize( m_ptItemWidget->minimumWidth(), m_ptItemWidget->height() );
}

bool LayerItemWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    m_ptItemWidget->propagateEvent(event);
    m_ptItemWidget->setEnabled( true );
    DEBUG_MESSAGE( "EVENT" );
}
A.G.
  • 1,279
  • 1
  • 11
  • 28

1 Answers1

1

You should read documentation about setItemWidget method. You may set widgets only to show some data, not for interacting with this widgets.

Possible workaround (how it should be done, but this task need a lot of tuning):

  1. Implement a delegate that will draw necessary controls (or use QPixmap::grabWidget and cache your widget view)
  2. Track mouse events
  3. When mouse hovers some QModelIndex - then create an editor for this item.
  4. Track editor events, and when mouse leaves it - hide an editor and submit data

But in your case I beleive that you should think about redesign your idea (If you have not to much items):

  1. Create your own widget with a vertical layout
  2. Place your widgets there
  3. Handle model events (...Profit!)

Remark: item view widgets are designed to show large amount of data and they not designed to do complex interaction.

Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
  • I used a QListView with a delegate because of the documentation about setItemWidget _"If you want to display custom dynamic content or implement a custom editor widget, use QListView and subclass QItemDelegate instead."_. But I'll have to implement the workdaroung cause this was QListWidget does (I've checked the source code). I won't display hundreds of data only a dozen. – A.G. Oct 10 '14 at 13:33