Fix action column widget rendering artifacts

This creates an action column widget when the widget is rendered for the
first time.
The original approach was to create an image and render the buffered
image onto the cell until the first mouse action triggered the creation
of the real widget. This led to several rendering problems and triggered
some strange ownership issues with crashes under certain situations.

Followup a05b2ad9
This commit is contained in:
Matthias Kuhn 2016-06-14 11:11:53 +02:00
parent 6d1e554206
commit 3fcabc96fe
5 changed files with 24 additions and 44 deletions

View File

@ -40,8 +40,14 @@ class QgsAttributeTableDelegate : QItemDelegate
void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel );
signals:
/**
* Set an image that represents an action widget
* Is emitted when an action column item is painted.
* The consumer of this signal can initialize the index widget.
*
* @note This signal is emitted repeatedly whenever the item is being painted.
* It is the consumers responsibility to check if initialization has already
* happened before.
*/
void setActionWidgetImage( const QImage& image );
void actionColumnItemPainted( const QModelIndex& index ) const;
};

View File

@ -118,20 +118,13 @@ void QgsAttributeTableDelegate::setFeatureSelectionModel( QgsFeatureSelectionMod
mFeatureSelectionModel = featureSelectionModel;
}
void QgsAttributeTableDelegate::setActionWidgetImage( const QImage& image )
{
mActionWidgetImage = image;
}
void QgsAttributeTableDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QgsAttributeTableFilterModel::ColumnType columnType = static_cast<QgsAttributeTableFilterModel::ColumnType>( index.model()->data( index, QgsAttributeTableFilterModel::TypeRole ).toInt() );
if ( columnType == QgsAttributeTableFilterModel::ColumnTypeActionButton )
{
QRect r = option.rect.adjusted( -1, 0, 0, 0 );
painter->drawImage( r.x(), r.y(), mActionWidgetImage );
emit actionColumnItemPainted( index );
}
else
{

View File

@ -77,15 +77,20 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate
void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel );
signals:
/**
* Set an image that represents an action widget
* Is emitted when an action column item is painted.
* The consumer of this signal can initialize the index widget.
*
* @note This signal is emitted repeatedly whenever the item is being painted.
* It is the consumers responsibility to check if initialization has already
* happened before.
*/
void setActionWidgetImage( const QImage& image );
void actionColumnItemPainted( const QModelIndex& index ) const;
private:
QgsVectorLayer* mLayer;
QgsFeatureSelectionModel* mFeatureSelectionModel;
QImage mActionWidgetImage;
};
#endif //QGSATTRIBUTETABLEDELEGATE_H

View File

@ -35,15 +35,12 @@
QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
: QTableView( parent )
, mMasterModel( nullptr )
, mFilterModel( nullptr )
, mFeatureSelectionModel( nullptr )
, mFeatureSelectionManager( nullptr )
, mModel( nullptr )
, mActionPopup( nullptr )
, mRowSectionAnchor( 0 )
, mCtrlDragSelectionFlag( QItemSelectionModel::Select )
, mActionWidget( nullptr )
{
QSettings settings;
restoreGeometry( settings.value( "/BetterAttributeTable/geometry" ).toByteArray() );
@ -52,8 +49,6 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
horizontalHeader()->setHighlightSections( false );
// We need mouse move events to create the action button on hover
setMouseTracking( true );
mTableDelegate = new QgsAttributeTableDelegate( this );
setItemDelegate( mTableDelegate );
@ -121,6 +116,7 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel
if ( mFilterModel )
{
connect( mFilterModel, SIGNAL( destroyed() ), this, SLOT( modelDeleted() ) );
connect( mTableDelegate, SIGNAL( actionColumnItemPainted( QModelIndex ) ), this, SLOT( onActionColumnItemPainted( QModelIndex ) ) );
}
delete mFeatureSelectionModel;
@ -138,10 +134,6 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel
mTableDelegate->setFeatureSelectionModel( mFeatureSelectionModel );
connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
mActionWidget.reset( createActionWidget( 0 ) );
mActionWidget->setVisible( false );
updateActionImage( mActionWidget.data() );
}
}
@ -238,15 +230,6 @@ void QgsAttributeTableView::mouseReleaseEvent( QMouseEvent *event )
void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event )
{
QModelIndex index = indexAt( event->pos() );
if ( index.data( QgsAttributeTableFilterModel::TypeRole ) == QgsAttributeTableFilterModel::ColumnTypeActionButton )
{
Q_ASSERT( index.isValid() );
if ( !indexWidget( index ) )
setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) );
}
setSelectionMode( QAbstractItemView::NoSelection );
QTableView::mouseMoveEvent( event );
setSelectionMode( QAbstractItemView::ExtendedSelection );
@ -396,18 +379,13 @@ void QgsAttributeTableView::actionTriggered()
void QgsAttributeTableView::columnSizeChanged( int index, int oldWidth, int newWidth )
{
Q_UNUSED( oldWidth )
if ( mFilterModel->actionColumnIndex() == index )
{
mActionWidget->resize( newWidth, mActionWidget->height() );
updateActionImage( mActionWidget.data() );
}
emit columnResized( index, newWidth );
}
void QgsAttributeTableView::updateActionImage( QWidget* widget )
void QgsAttributeTableView::onActionColumnItemPainted( const QModelIndex& index )
{
QImage image( widget->size(), QImage::Format_ARGB32_Premultiplied );
QPainter painter( &image );
widget->render( &painter );
mTableDelegate->setActionWidgetImage( image );
if ( !indexWidget( index ) )
{
setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) );
}
}

View File

@ -155,22 +155,20 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
void showHorizontalSortIndicator();
void actionTriggered();
void columnSizeChanged( int index, int oldWidth, int newWidth );
void onActionColumnItemPainted( const QModelIndex& index );
private:
void updateActionImage( QWidget* widget );
QWidget* createActionWidget( QgsFeatureId fid );
void selectRow( int row, bool anchor );
QgsAttributeTableModel* mMasterModel;
QgsAttributeTableFilterModel* mFilterModel;
QgsFeatureSelectionModel* mFeatureSelectionModel;
QgsIFeatureSelectionManager* mFeatureSelectionManager;
QgsAttributeTableDelegate* mTableDelegate;
QAbstractItemModel* mModel; // Most likely the filter model
QMenu *mActionPopup;
int mRowSectionAnchor;
QItemSelectionModel::SelectionFlag mCtrlDragSelectionFlag;
QScopedPointer<QWidget> mActionWidget;
};
#endif