web-dev-qa-db-fra.com

Afficher l'image en Qt pour s'adapter à la taille de l'étiquette

J'ai déjà essayé plusieurs méthodes pour afficher une image sur un formulaire, mais aucune ne fonctionne comme je le souhaite.

J'ai lu à de nombreux endroits que le moyen le plus simple est de créer une étiquette et de l'utiliser pour afficher l'image. J'ai une étiquette, dont la taille est spécifiée par la mise en page, mais si je charge une image dedans avec un pixmap, l'étiquette est redimensionnée à la taille de l'image. Si j'utilise la balise img comme propriété de texte ou d'arrière-plan CSS, elle n'affichera pas l'image entière. Ce que je voudrais faire, c'est charger l'image et l'ajuster dans l'étiquette, sans changer la taille de l'étiquette, mais quand je redimensionne ma fenêtre, et en redimensionnant également l'étiquette, l'image doit être redimensionnée aussi pour qu'elle s'adapte toujours dans ça.

Si la seule méthode consiste à obtenir la taille de l'étiquette, à redimensionner le pixmap afin qu'il tienne et à gérer l'événement de redimensionnement (signal), comment pourrais-je redimensionner le pixmap? J'espère que je n'aurai pas besoin d'enregistrer le tout dans un QImage et de créer un pixmap à partir de celui-ci à chaque fois.

Aussi, comment puis-je le centrer? S'il ne peut pas s'adapter à la fois à la largeur et à la hauteur, je voudrais que la plus petite dimension soit centrée.

Oh, et je ne veux pas utiliser de curseurs pour gérer les débordements.

27

QLabel :: setScaledContents (bool) aide-t-il? Il peut également y avoir des informations utiles dans exemple de visionneuse d'images .

19
Arnold Spence

En fait, il existe une solution très simple à ce problème. Vous devez modifier deux choses:

  1. définissez le contenu mis à l'échelle sur vrai (mentionné ci-dessus)
  2. définir la politique de taille de l'étiquette sur ignoré

    QLabel lblImage;
    
    lblImage->setPixmap( QPixmap( "big_image.jpg" ) );
    
    lblImage->setScaledContents( true );
    
    lblImage->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
    

Si lblImage se redimensionne automatiquement, l'image s'étire à la taille de l'étiquette.

19
bukkfa

Je vais également répondre à ma propre question, mais je ne la marquerai pas comme une solution, car j'ai demandé une simple qui a été donnée ci-dessus. J'ai fini par utiliser une solution pas trop simple après tout, donc toute personne qui a également besoin de faire quelque chose de similaire et qui a le temps de jouer avec elle, voici mon code de travail final. L'idée est d'étendre le QLabel et de surcharger les méthodes setPixmap et drawEvent.

QPictureLabel.hpp (fichier d'en-tête)

#include "QImage.h"
#include "QPixmap.h"
#include "QLabel.h"

class QPictureLabel : public QLabel
{
private:
    QPixmap _qpSource; //preserve the original, so multiple resize events won't break the quality
    QPixmap _qpCurrent;

    void _displayImage();

public:
    QPictureLabel(QWidget *aParent) : QLabel(aParent) { }
    void setPixmap(QPixmap aPicture);
    void paintEvent(QPaintEvent *aEvent);
};

QPictureLabel.cpp (implémentation)

#include "QPainter.h"

#include "QPictureLabel.hpp"

void QPictureLabel::paintEvent(QPaintEvent *aEvent)
{
    QLabel::paintEvent(aEvent);
    _displayImage();
}

void QPictureLabel::setPixmap(QPixmap aPicture)
{
    _qpSource = _qpCurrent = aPicture;
    repaint();
}

void QPictureLabel::_displayImage()
{
    if (_qpSource.isNull()) //no image was set, don't draw anything
        return;

    float cw = width(), ch = height();
    float pw = _qpCurrent.width(), ph = _qpCurrent.height();

    if (pw > cw && ph > ch && pw/cw > ph/ch || //both width and high are bigger, ratio at high is bigger or
        pw > cw && ph <= ch || //only the width is bigger or
        pw < cw && ph < ch && cw/pw < ch/ph //both width and height is smaller, ratio at width is smaller
        )
        _qpCurrent = _qpSource.scaledToWidth(cw, Qt::TransformationMode::FastTransformation);
    else if (pw > cw && ph > ch && pw/cw <= ph/ch || //both width and high are bigger, ratio at width is bigger or
        ph > ch && pw <= cw || //only the height is bigger or
        pw < cw && ph < ch && cw/pw > ch/ph //both width and height is smaller, ratio at height is smaller
        )
        _qpCurrent = _qpSource.scaledToHeight(ch, Qt::TransformationMode::FastTransformation);

    int x = (cw - _qpCurrent.width())/2, y = (ch - _qpCurrent.height())/2;

    QPainter Paint(this);
    Paint.drawPixmap(x, y, _qpCurrent);
}

tilisation: identique à l'utilisation d'une étiquette normale pour afficher l'image sans les setScaledContents

img_Result = new QPictureLabel(ui.parent);
layout = new QVBoxLayout(ui.parent);
layout->setContentsMargins(11, 11, 11, 11);
ui.parent->setLayout(layout);
layout->addWidget(img_Result);

//{...}

QPixmap qpImage(qsImagePath);
img_Result->setPixmap(qpImage);
14

Gardez une copie de votre pixmap d'origine autour. Ensuite, connectez le signal resized à un slot (ou remplacez la fonction resizeEvent()) qui implémente ceci:

lblImage->setPixmap(pixmap.scaled(lblImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
12
Tim MB