Hi,
Here my solution to reproduce the Windows behavior to have always the QListWidget filled in space (override of QStyledItemDelegate) :
virtual QSize sizeHint
( const QStyleOptionViewItem
& option,
const QModelIndex
& index
) const override
{
const int RightMargin = 15;
const int MaxWidth = ListWidget->viewport()->width() - RightMargin;
const int ItemWidth = option.decorationSize.width() + ItemPadding.width();
if( ItemWidth >= MaxWidth )
return option.
decorationSize + QSize( 0, option.
fontMetrics.
height() ) + ItemPadding;
const int ItemHeight = option.decorationSize.height() + option.fontMetrics.height() + ItemPadding.height();
const int NumItem = std::max( 1, MaxWidth / ItemWidth );
const int NumRow = std::ceil( static_cast< float >( ListWidget->count() ) / static_cast< float >( NumItem ) );
const bool ScrollbarVisible = ( NumRow * ItemHeight ) > ListWidget->viewport()->height();
if( ScrollbarVisible )
{
const int PaddingOffset = ( NumItem >= ListWidget->count() ) ? 0 : ( MaxWidth - ( NumItem * ItemWidth ) ) / NumItem;
return option.
decorationSize + QSize( 0, option.
fontMetrics.
height() ) + ItemPadding
+ QSize( PaddingOffset,
0 );
}
else
{
// 3 pixels removed to avoid flickering when resize.
const int NewMaxWidth = ListWidget->viewport()->width() - RightMargin - 3;
const int NewNumItem = std::max( 1, NewMaxWidth / ItemWidth );
const int PaddingOffset = ( NewNumItem >= ListWidget->count() ) ? 0 : ( NewMaxWidth - ( NewNumItem * ItemWidth ) ) / NewNumItem;
return option.
decorationSize + QSize( 0, option.
fontMetrics.
height() ) + ItemPadding
+ QSize( PaddingOffset,
0 );
}
}
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const override
{
const int RightMargin = 15;
const QSize ItemPadding = QSize( 6, 6 );
QListWidget* ListWidget = static_cast< QListWidget* >( parent() );
const int MaxWidth = ListWidget->viewport()->width() - RightMargin;
const int ItemWidth = option.decorationSize.width() + ItemPadding.width();
if( ItemWidth >= MaxWidth )
return option.decorationSize + QSize( 0, option.fontMetrics.height() ) + ItemPadding;
const int ItemHeight = option.decorationSize.height() + option.fontMetrics.height() + ItemPadding.height();
const int NumItem = std::max( 1, MaxWidth / ItemWidth );
const int NumRow = std::ceil( static_cast< float >( ListWidget->count() ) / static_cast< float >( NumItem ) );
const bool ScrollbarVisible = ( NumRow * ItemHeight ) > ListWidget->viewport()->height();
if( ScrollbarVisible )
{
const int PaddingOffset = ( NumItem >= ListWidget->count() ) ? 0 : ( MaxWidth - ( NumItem * ItemWidth ) ) / NumItem;
return option.decorationSize + QSize( 0, option.fontMetrics.height() ) + ItemPadding + QSize( PaddingOffset, 0 );
}
else
{
// 3 pixels removed to avoid flickering when resize.
const int NewMaxWidth = ListWidget->viewport()->width() - RightMargin - 3;
const int NewNumItem = std::max( 1, NewMaxWidth / ItemWidth );
const int PaddingOffset = ( NewNumItem >= ListWidget->count() ) ? 0 : ( NewMaxWidth - ( NewNumItem * ItemWidth ) ) / NewNumItem;
return option.decorationSize + QSize( 0, option.fontMetrics.height() ) + ItemPadding + QSize( PaddingOffset, 0 );
}
}
To copy to clipboard, switch view to plain text mode
This code compute the free space on the right based on the known item size and distribute in each item to always be filled on the width.
All works fine but why this 3px magical number is needed to avoid flickering when the scrollbar is not visible ?
If this magical number is not used one item always swap from one line to another when resize.
Thanks
Bookmarks