UFO ET IT

Qt : 종횡비를 유지하면서 QPixmap을 포함하는 QLabel 크기 조정

ufoet 2020. 11. 7. 18:15
반응형

Qt : 종횡비를 유지하면서 QPixmap을 포함하는 QLabel 크기 조정


QLabel을 사용하여 더 크고 동적으로 변경되는 QPixmap의 내용을 사용자에게 표시합니다. 사용 가능한 공간에 따라이 레이블을 더 작게 / 더 크게 만드는 것이 좋습니다. 화면 크기가 항상 QPixmap만큼 크지는 않습니다.

원본 QPixmap의 종횡비를 유지하면서 QPixmap의 크기를 조정하기 위해 QLabel QSizePolicysizeHint()수정하려면 어떻게 해야합니까?

sizeHint()QLabel을 수정할 수 없습니다 minimumSize(). 0으로 설정해도 도움이되지 않습니다. hasScaledContents()QLabel을 설정 하면 성장이 허용되지만 종횡비가 깨집니다.

QLabel을 서브 클래 싱하는 것이 도움이되었지만이 솔루션은 단순한 문제에 너무 많은 코드를 추가합니다.

서브 클래 싱 없이 이를 수행하는 방법에 대한 현명한 힌트가 있습니까?


레이블 크기를 변경하려면 확장 또는 최소 확장과 같은 레이블에 적절한 크기 정책을 선택할 수 있습니다.

픽스맵이 변경 될 때마다 종횡비를 유지하여 픽스맵의 크기를 조정할 수 있습니다.

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

이 코드를 추가해야하는 두 곳이 있습니다.

  • 픽스맵이 업데이트 될 때
  • 에서 resizeEvent라벨을 포함하는 위젯의

이 누락 된 하위 클래스를 다듬 었습니다 QLabel. 굉장하고 잘 작동합니다.

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

도움이 되었기를 바랍니다. ( resizeEvent@dmzl의 답변에 따라 업데이트 됨 )


contentsMargin가로 세로 비율을 수정하는 데 사용 합니다.

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

지금까지 완벽하게 작동합니다. 천만에요.


phyatt의 AspectRatioPixmapLabel수업을 사용해 보았지만 몇 가지 문제가 발생했습니다.

  • Sometimes my app entered an infinite loop of resize events. I traced this back to the call of QLabel::setPixmap(...) inside the resizeEvent method, because QLabel actually calls updateGeometry inside setPixmap, which may trigger resize events...
  • heightForWidth seemed to be ignored by the containing widget (a QScrollArea in my case) until I started setting a size policy for the label, explicitly calling policy.setHeightForWidth(true)
  • I want the label to never grow more than the original pixmap size
  • QLabel's implementation of minimumSizeHint() does some magic for labels containing text, but always resets the size policy to the default one, so I had to overwrite it

That said, here is my solution. I found that I could just use setScaledContents(true) and let QLabel handle the resizing. Of course, this depends on the containing widget / layout honoring the heightForWidth.

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

Thanks for sharing this. Would you have any suggestions on how I can set a "preferred" size to the QPixmap so that it does not take the maximum resolution on the first launch of the application?

참고URL : https://stackoverflow.com/questions/8211982/qt-resizing-a-qlabel-containing-a-qpixmap-while-keeping-its-aspect-ratio

반응형