[c++] Qt : 종횡비를 유지하면서 QPixmap을 포함하는 QLabel 크기 조정
QLabel을 사용하여 더 크고 동적으로 변경되는 QPixmap의 내용을 사용자에게 표시합니다. 사용 가능한 공간에 따라이 레이블을 더 작게 / 더 크게 만드는 것이 좋습니다. 화면 크기가 항상 QPixmap만큼 크지는 않습니다.
원본 QPixmap의 종횡비를 유지하면서 QPixmap의 크기를 조정하기 위해 QLabel QSizePolicy
과 sizeHint()
의 수정하려면 어떻게 해야합니까?
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
수업을 사용해 보았지만 몇 가지 문제가 발생했습니다.
- 때때로 내 앱이 크기 조정 이벤트의 무한 루프에 들어갔습니다. 실제로 내부를 호출하여 크기 조정 이벤트를 트리거 할 수
QLabel::setPixmap(...)
있기 때문에이 함수를 다시 resizeEvent 메서드 내부 호출로 추적했습니다 .QLabel
updateGeometry
setPixmap
heightForWidth
QScrollArea
레이블에 대한 크기 정책을 설정하기 시작할 때까지 포함하는 위젯 ( 제 경우에는)에서 무시한 것처럼 보였습니다.policy.setHeightForWidth(true)
- 라벨이 원래 픽스맵 크기 이상으로 커지지 않기를 바랍니다.
QLabel
의 구현은minimumSizeHint()
텍스트를 포함하는 레이블에 대해 약간의 마법을 수행하지만 항상 크기 정책을 기본값으로 재설정하므로 덮어 써야했습니다
즉, 여기 내 해결책이 있습니다. 크기 조정을 사용 setScaledContents(true)
하고 QLabel
처리 할 수 있다는 것을 알았습니다 . 물론 이것은 포함 된 위젯 / 레이아웃에 따라 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();
}
}
답변
Timmmm에서 PYQT5로 조정
from PyQt5.QtGui import QPixmap
from PyQt5.QtGui import QResizeEvent
from PyQt5.QtWidgets import QLabel
class Label(QLabel):
def __init__(self):
super(Label, self).__init__()
self.pixmap_width: int = 1
self.pixmapHeight: int = 1
def setPixmap(self, pm: QPixmap) -> None:
self.pixmap_width = pm.width()
self.pixmapHeight = pm.height()
self.updateMargins()
super(Label, self).setPixmap(pm)
def resizeEvent(self, a0: QResizeEvent) -> None:
self.updateMargins()
super(Label, self).resizeEvent(a0)
def updateMargins(self):
if self.pixmap() is None:
return
pixmapWidth = self.pixmap().width()
pixmapHeight = self.pixmap().height()
if pixmapWidth <= 0 or pixmapHeight <= 0:
return
w, h = self.width(), self.height()
if w <= 0 or h <= 0:
return
if w * pixmapHeight > h * pixmapWidth:
m = int((w - (pixmapWidth * h / pixmapHeight)) / 2)
self.setContentsMargins(m, 0, m, 0)
else:
m = int((h - (pixmapHeight * w / pixmapWidth)) / 2)
self.setContentsMargins(0, m, 0, m)
답변
Qt 문서에는 내부에서 크기 조정 이미지 처리를 보여주는 이미지 뷰어 예제 가 QLabel
있습니다. 기본 아이디어는 필요한 경우 사용 QScrollArea
을위한 컨테이너로 QLabel
사용 label.setScaledContents(bool)
하고 사용 scrollarea.setWidgetResizable(bool)
가능한 공간을 채우거나 내부의 QLabel 크기를 조정할 수 있는지 확인하는 것입니다. 또한 가로 세로 비율을 유지하면서 QLabel의 크기를 조정하려면 다음을 사용하십시오.
label.setPixmap(pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::FastTransformation));
width
과은 height
에 따라 설정할 수 있습니다 scrollarea.width()
및 scrollarea.height()
. 이런 식으로 QLabel을 하위 클래스화할 필요가 없습니다.