Scale pixmap image in QHeaderView

Maurizio Berti maurizio.berti at gmail.com
Mon Oct 20 05:27:03 BST 2025


First of all, this is not a PyQt issue.
Then, let's remember that QAbstractItemModel's data() (and headerData())
always return a QVariant, which is a dynamic type object that can be
cast/interpreted depending on the implementation.
That's why we can, for instance, return a DisplayRole that could be a
string, an integer or a float.

Standard views display a returned DecorationRole value as a QIcon, a
QPixmap or even a QImage. The implementation of default delegates is based
primarily on the original data type, and eventually behave differently: the
default assumption is that the value is a QIcon, therefore they follow the
view's iconSize() and provide an appropriate scaled image based on that
value (which, according to the pixmap() docs of QIcon, "might be smaller
than requested, but never larger"), but if a pixmap or an image is
provided, it may be shown at its original size, assuming that the item size
allows it, otherwise it's clipped.

The issue with QHeaderView is based on two aspects:
1. as the documentation explains, it doesn't use delegates;
2. the icons normally use the QStyle.PM_SmallIconSize size as reference;
3. it *always* considers the DecorationRole as a QIcon, therefore (as noted
above) it can never be larger than expected;

By checking the sources, the both sectionSizeFromContents() and
paintSection() implementations do the following:

const QVariant variant = d->model->headerData(logicalIndex, d->orientation,
Qt::DecorationRole);
opt.icon = qvariant_cast<QIcon>(variant);
if (opt.icon.isNull())
    opt.icon = qvariant_cast<QPixmap>(variant);

Therefore, QHeaderView relies on the current style to eventually return an
appropriate size for each section, and then display a related "icon" based
on the style implementation.
And while it's up to the style to eventually decide the section size based
on the contents, that's not an assumption that can be normally assumed
simply based on the DecorationRole: the style only receives a QIcon without
a specific context (except for the iconSize() it can get from the view).
QIcons can contain any "available size", and there's no way to know if the
given QIcon should be assumed as a pixmap returned from the model that
should be shown at its original size, or if it's just a QIcon that only has
one specified size.

So, the result is that you will always get an icon with a size that is
equal or smaller than the style "small icon size" or the size explicitly
set on the header (assuming the style respects it, and it normally
doesn't), but never larger than it.

If you want to have larger icon sizes, then your only options are to use a
custom QProxyStyle for the header (or any relevant parent) that eventually
returns appropriate sizes for the related CT_HeaderSection), or subclass
QHeaderView and eventually implement everything based on your needs.

Regards,
MaurizioB

Il giorno dom 19 ott 2025 alle ore 22:08 John Sturtz <john at sturtz.org> ha
scritto:

> Hello again.
>
> Attached is a short bit of code that displays a QTableView with a custom
> QHeaderView.  The .headerData() method loads a 64x64 PNG and returns it
> for DecorationRole.
>
> Can anyone tell me why the .scaled() call on line #61 can't make the
> header image larger?  If I change the argument to .scaled() to QSize(8, 8),
> it makes the image small.  So the .scaled() call is evidently having an
> effect.  But if I specify QSize(64, 64), it doesn't get anywhere near as
> large as 64x64.  I've been unable to determine why.
>
> Thanks!
>
> /John
>


-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20251020/548fed6b/attachment-0001.htm>


More information about the PyQt mailing list