103 votes

Qt : redimensionner un QLabel contenant un QPixmap tout en conservant son ratio d'aspect

J'utilise un QLabel pour afficher le contenu d'un QPixmap plus grand et en constante évolution à l'utilisateur. Ce serait bien de rendre ce label plus petit ou plus grand en fonction de l'espace disponible. La taille de l'écran n'est pas toujours aussi grande que le QPixmap.

Comment puis-je modifier QSizePolicy et sizeHint() du QLabel pour redimensionner le QPixmap en conservant le rapport d'aspect du QPixmap d'origine?

Je ne peux pas modifier sizeHint() du QLabel, définir minimumSize() à zéro n'aide pas. Définir hasScaledContents() sur le QLabel permet de faire croître, mais casse le truc du rapport d'aspect...

La sous-classe QLabel a été utile, mais cette solution ajoute trop de code pour un problème aussi simple...

Des astuces intelligentes pour accomplir cela sans sous-classement?

116voto

pnezis Points 6971

Pour changer la taille de l'étiquette, vous pouvez sélectionner une politique de taille appropriée pour l'étiquette, comme l'expansion ou l'expansion minimale.

Vous pouvez mettre à l'échelle le pixmap en conservant son rapport hauteur-largeur chaque fois qu'il change :

QPixmap p; // charger le pixmap
// obtenir les dimensions de l'étiquette
int w = label->width();
int h = label->height();

// définir un pixmap mis à l'échelle pour une fenêtre de taille w x h en conservant son rapport hauteur-largeur
label->setPixmap(p.scaled(w,h,Qt::KeepAspectRatio));

Il y a deux endroits où vous devriez ajouter ce code :

  • Lorsque le pixmap est mis à jour
  • Dans le resizeEvent du widget contenant l'étiquette

48voto

phyatt Points 6647

J'ai poli cette sous-classe manquante de QLabel. C'est génial et ça fonctionne bien.

aspectratiopixmaplabel.h

#ifndef ASPECTRATIOPIXMAPLABEL_H
#define ASPECTRATIOPIXMAPLABEL_H

#include 
#include 
#include 

class AspectRatioPixmapLabel : public QLabel
{
    Q_OBJECT
public:
    explicit AspectRatioPixmapLabel(QWidget *parent = 0);
    virtual int heightForWidth( int width ) const;
    virtual QSize sizeHint() const;
    QPixmap scaledPixmap() const;
public slots:
    void setPixmap ( const QPixmap & );
    void resizeEvent(QResizeEvent *);
private:
    QPixmap pix;
};

#endif // ASPECTRATIOPIXMAPLABEL_H

aspectratiopixmaplabel.cpp

#include "aspectratiopixmaplabel.h"
//#include 

AspectRatioPixmapLabel::AspectRatioPixmapLabel(QWidget *parent) :
    QLabel(parent)
{
    this->setMinimumSize(1,1);
    setScaledContents(false);
}

void AspectRatioPixmapLabel::setPixmap ( const QPixmap & p)
{
    pix = p;
    QLabel::setPixmap(scaledPixmap());
}

int AspectRatioPixmapLabel::heightForWidth( int width ) const
{
    return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width();
}

QSize AspectRatioPixmapLabel::sizeHint() const
{
    int w = this->width();
    return QSize( w, heightForWidth(w) );
}

QPixmap AspectRatioPixmapLabel::scaledPixmap() const
{
    return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

void AspectRatioPixmapLabel::resizeEvent(QResizeEvent * e)
{
    if(!pix.isNull())
        QLabel::setPixmap(scaledPixmap());
}

J'espère que cela aide! (Mis à jour resizeEvent, selon la réponse de @dmzl)

23voto

Timmmm Points 9909

Je viens juste d'utiliser contentsMargin pour fixer le rapport hauteur/largeur.

#pragma once

#include 

class AspectRatioLabel : public QLabel
{
public:
    explicit AspectRatioLabel(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
    ~AspectRatioLabel();

public slots:
    void setPixmap(const QPixmap& pm);

protected:
    void resizeEvent(QResizeEvent* event) override;

private:
    void updateMargins();

    int pixmapWidth = 0;
    int pixmapHeight = 0;
};

#include "AspectRatioLabel.h"

AspectRatioLabel::AspectRatioLabel(QWidget* parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

AspectRatioLabel::~AspectRatioLabel()
{
}

void AspectRatioLabel::setPixmap(const QPixmap& pm)
{
    pixmapWidth = pm.width();
    pixmapHeight = pm.height();

    updateMargins();
    QLabel::setPixmap(pm);
}

void AspectRatioLabel::resizeEvent(QResizeEvent* event)
{
    updateMargins();
    QLabel::resizeEvent(event);
}

void AspectRatioLabel::updateMargins()
{
    if (pixmapWidth <= 0 || pixmapHeight <= 0)
        return;

    int w = this->width();
    int h = this->height();

    if (w <= 0 || h <= 0)
        return;

    if (w * pixmapHeight > h * pixmapWidth)
    {
        int m = (w - (pixmapWidth * h / pixmapHeight)) / 2;
        setContentsMargins(m, 0, m, 0);
    }
    else
    {
        int m = (h - (pixmapHeight * w / pixmapWidth)) / 2;
        setContentsMargins(0, m, 0, m);
    }
}

Fonctionne parfaitement pour moi jusqu'à présent. De rien.

8voto

Derek R. Points 21

Adapté de Timmmm à PYQT5

de PyQt5.QtGui import QPixmap
de PyQt5.QtGui import QResizeEvent
de PyQt5.QtWidgets import QLabel

classe Label(QLabel):

    def __init__(auto, *args, **kwargs):
        super(Label, self).__init__(*args, **kwargs)
        auto.pixmap_width: int = 1
        auto.pixmapHeight: int = 1

    def setPixmap(auto, pm: QPixmap) -> None:
        auto.pixmap_width = pm.width()
        auto.pixmapHeight = pm.height()

        auto.updateMargins()
        super(Label, auto).setPixmap(pm)

    def resizeEvent(auto, a0: QResizeEvent) -> None:
        auto.updateMargins()
        super(Label, auto).resizeEvent(a0)

    def updateMargins(auto):
        if auto.pixmap() is None:
            retour
        pixmapWidth = auto.pixmap().width()
        pixmapHeight = auto.pixmap().height()
        if pixmapWidth <= 0 or pixmapHeight <= 0:
            retour
        w, h = auto.width(), auto.height()
        if w <= 0 or h <= 0:
            retour

        if w * pixmapHeight > h * pixmapWidth:
            m = int((w - (pixmapWidth * h / pixmapHeight)) / 2)
            auto.setContentsMargins(m, 0, m, 0)
        else:
            m = int((h - (pixmapHeight * w / pixmapWidth)) / 2)
            auto.setContentsMargins(0, m, 0, m)

8voto

Jason C Points 14927

Si votre image est une ressource ou un fichier, vous n'avez pas besoin de sous-classer quoi que ce soit ; il suffit de définir image dans la feuille de style de l'étiquette; et elle sera mise à l'échelle pour s'adapter à l'étiquette tout en conservant son ratio, et suivra toutes les modifications de taille apportées à l'étiquette. Vous pouvez optionnellement utiliser image-position pour déplacer l'image vers l'un des bords.

Cela ne convient pas au cas d'une pixmap mise à jour dynamiquement par l'OP (je veux dire, vous pouvez définir différentes ressources quand vous le souhaitez mais elles doivent toujours être des ressources), mais c'est une bonne méthode si vous utilisez des pixmaps à partir de ressources.

Exemple de feuille de style :

image: url(:/chemin/vers/la/ressource);
image-position: right center; /* optionnel: par défaut, centré */

Dans le code (par exemple) :

QString feuilleDeStyle = "image:url(%1);image-position:right center;";
existingLabel->setStyleSheet(feuilleDeStyle.arg(":/chemin/vers/la/ressource"));

Ou vous pouvez simplement définir la propriété de feuille de style directement dans Designer :

entrer la description de l'image ici _Source de l'icône: Designspace Team via Flaticon_

L'inconvénient est qu'il ne fera pas grossir l'image, seulement rétrécir, donc assurez-vous que votre image est plus grande que votre gamme de tailles si vous voulez qu'elle grandisse (notez qu'il prend en charge SVG, ce qui peut améliorer la qualité).

La taille de l'étiquette peut être contrôlée comme d'habitude : utilisez soit des éléments de taille dans la feuille de style, soit utilisez les stratégies de disposition et de politique de taille standard.

Voir la documentation pour plus de détails.

Ce style est présent depuis les premières versions de Qt (la position a été ajoutée vers 4.3 environ en 2007 mais l'image était là avant cela).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X