web-dev-qa-db-de.com

Qt: Ändern der Größe eines QLabels, das eine QPixmap enthält, unter Beibehaltung seines Seitenverhältnisses

Ich verwende ein QLabel, um dem Benutzer den Inhalt einer größeren, sich dynamisch ändernden QPixmap anzuzeigen. Es wäre schön, dieses Etikett je nach verfügbarem Platz kleiner/größer zu gestalten. Die Bildschirmgröße ist nicht immer so groß wie die QPixmap.

Wie kann ich die QSizePolicy und sizeHint() des QLabel ändern, um die Größe der QPixmap zu ändern, während das Seitenverhältnis der ursprünglichen QPixmap beibehalten wird?

Ich kann sizeHint() des QLabels nicht ändern, und es hilft nicht, minimumSize() auf Null zu setzen. Das Setzen von hasScaledContents() auf dem QLabel ermöglicht das Wachsen, unterbricht aber das Seitenverhältnis ...

QLabel-Unterklassen haben geholfen, aber diese Lösung fügt zu viel Code für ein einfaches Problem hinzu ...

Irgendwelche klugen Hinweise, wie man dies bewerkstelligt ohne Unterklassen?

67
marvin2k

Um die Etikettengröße zu ändern, können Sie eine geeignete Größenrichtlinie für das Etikett auswählen, z. B. Erweitern oder Minimalerweiterung.

Sie können die Pixmap skalieren, indem Sie bei jeder Änderung das Seitenverhältnis beibehalten:

QPixmap p; // load pixmap
// get label dimensions
int w = label->width();
int h = label->height();

// set a scaled pixmap to a w x h window keeping its aspect ratio 
label->setPixmap(p.scaled(w,h,Qt::KeepAspectRatio));

Es gibt zwei Stellen, an denen Sie diesen Code hinzufügen sollten:

  • Wenn die Pixmap aktualisiert wird
  • Im resizeEvent des Widgets, das die Bezeichnung enthält
84
pnezis

Ich habe diese fehlende Unterklasse von QLabel aufpoliert. Es ist großartig und funktioniert gut.

aspectratiopixmaplabel.h

#ifndef ASPECTRATIOPIXMAPLABEL_H
#define ASPECTRATIOPIXMAPLABEL_H

#include <QLabel>
#include <QPixmap>
#include <QResizeEvent>

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 <QDebug>

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());
}

Hoffentlich hilft das! (Aktualisiert resizeEvent, per @ dmzls Antwort)

29
phyatt

Ich benutze nur contentsMargin, um das Seitenverhältnis festzulegen.

#pragma once

#include <QLabel>

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);
    }
}

Funktioniert soweit perfekt für mich. Bitte.

11
Timmmm

Ich habe versucht, die Klasse AspectRatioPixmapLabel von phyatt zu verwenden, hatte jedoch einige Probleme:

  • Manchmal trat meine App in eine Endlosschleife von Größenänderungsereignissen ein. Ich habe dies auf den Aufruf von QLabel::setPixmap(...) innerhalb der resizeEvent-Methode zurückgeführt, da QLabel tatsächlich updateGeometry innerhalb von setPixmap aufruft, was Größenänderungsereignisse auslösen kann. .
  • heightForWidth schien vom enthaltenen Widget ignoriert zu werden (in meinem Fall ein QScrollArea), bis ich begann, eine Größenrichtlinie für das Etikett festzulegen, indem ich policy.setHeightForWidth(true) explizit aufrief.
  • Ich möchte, dass das Etikett niemals größer wird als die ursprüngliche Pixmap-Größe
  • QLabel 's Implementierung von minimumSizeHint() bewirkt eine gewisse Magie für Beschriftungen, die Text enthalten, setzt jedoch die Größenrichtlinie immer auf die Standardrichtlinie zurück, sodass ich sie überschreiben musste

Das heißt, hier ist meine Lösung. Ich stellte fest, dass ich einfach setScaledContents(true) verwenden und QLabel die Größenänderung vornehmen konnte. Dies hängt natürlich davon ab, welches Widget/Layout das heightForWidth enthält.

aspectratiopixmaplabel.h

#ifndef ASPECTRATIOPIXMAPLABEL_H
#define ASPECTRATIOPIXMAPLABEL_H

#include <QLabel>
#include <QPixmap>

class AspectRatioPixmapLabel : public QLabel
{
    Q_OBJECT
public:
    explicit AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent = 0);
    virtual int heightForWidth(int width) const;
    virtual bool hasHeightForWidth() { return true; }
    virtual QSize sizeHint() const { return pixmap()->size(); }
    virtual QSize minimumSizeHint() const { return QSize(0, 0); }
};

#endif // ASPECTRATIOPIXMAPLABEL_H

aspectratiopixmaplabel.cpp

#include "aspectratiopixmaplabel.h"

AspectRatioPixmapLabel::AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent) :
    QLabel(parent)
{
    QLabel::setPixmap(pixmap);
    setScaledContents(true);
    QSizePolicy policy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    policy.setHeightForWidth(true);
    this->setSizePolicy(policy);
}

int AspectRatioPixmapLabel::heightForWidth(int width) const
{
    if (width > pixmap()->width()) {
        return pixmap()->height();
    } else {
        return ((qreal)pixmap()->height()*width)/pixmap()->width();
    }
}
6

Vielen Dank für das Teilen. Haben Sie Vorschläge, wie ich eine "bevorzugte" Größe für die QPixmap festlegen kann, damit diese beim ersten Start der Anwendung nicht die maximale Auflösung annimmt?

0
Julien M