87

QLabelを使用して、動的に変化するより大きなQPixmapのコンテンツをユーザーに表示します。利用可能なスペースに応じて、このラベルを小さく/大きくすると便利です。画面サイズは必ずしもQPixmapほど大きくはありません。

元のQPixmapのアスペクト比を維持しながら、QLabelのとを変更してQPixmapのサイズを変更するQSizePolicyにはどうすればよいですか?sizeHint()

sizeHint()QLabelを変更できませminimumSize()ん。ゼロに設定しても効果がありません。hasScaledContents()QLabelに設定すると、成長は可能になりますが、アスペクト比が崩れます...

QLabelをサブクラス化することは役に立ちましたが、このソリューションでは、単純な問題に対してコードが多すぎます...

サブクラス化せずにこれを達成するための賢いヒントはありますか?

4

9 に答える 9

104

ラベルサイズを変更するには、拡張や最小拡張など、ラベルに適切なサイズポリシーを選択できます。

変更するたびにアスペクト比を維持することで、ピックスマップを拡大縮小できます。

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

このコードを追加する必要がある場所は2つあります。

  • ピックスマップが更新されたとき
  • resizeEventラベルを含むウィジェットの
于 2011-11-21T12:53:17.260 に答える
37

のこの欠落しているサブクラスを磨きましたQLabel。それは素晴らしく、うまく機能します。

アスペクトピクスマップラベル.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

アスペクトピクスマップラベル.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の回答に従って更新)

于 2014-03-24T19:11:54.263 に答える
22

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

これまでのところ、私にとっては完璧に機能します。どういたしまして。

于 2017-05-12T11:21:09.533 に答える
7

phyattのAspectRatioPixmapLabelクラスを使用してみましたが、いくつかの問題が発生しました。

  • 時々私のアプリはサイズ変更イベントの無限ループに入りました。QLabel::setPixmap(...)これは、resizeEventメソッド内の呼び出しにまでさかのぼります。これは、QLabel実際には、updateGeometrysetPixmapで呼び出して、サイズ変更イベントをトリガーする可能性があるためです...
  • heightForWidthQScrollAreaラベルのサイズポリシーを明示的に呼び出して設定を開始するまで、含まれているウィジェット(私の場合はa)によって無視されているように見えましたpolicy.setHeightForWidth(true)
  • ラベルが元のピックスマップサイズを超えないようにしたい
  • QLabelの実装はminimumSizeHint()、テキストを含むラベルに対していくつかの魔法を実行しますが、サイズポリシーを常にデフォルトのポリシーにリセットするため、上書きする必要がありました

そうは言っても、これが私の解決策です。サイズ変更をそのまま使用setScaledContents(true)して処理できることがわかりました。QLabelもちろん、これはを尊重するウィジェット/レイアウトに依存しますheightForWidth

アスペクトピクスマップラベル.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

アスペクトピクスマップラベル.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();
    }
}
于 2016-12-30T22:22:47.540 に答える
7

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)
于 2020-06-12T22:24:15.600 に答える
1

画像がリソースまたはファイルの場合、何もサブクラス化する必要はありません。imageラベルのスタイルシートに設定するだけです。アスペクト比を維持しながらラベルに合わせて拡大縮小され、ラベルに加えられたサイズ変更を追跡します。オプションで、を使用image-positionして画像をエッジの1つに移動できます。

動的に更新されるピックスマップのOPの場合には適合しません(つまり、必要なときにいつでも異なるリソースを設定できますが、それでもリソースである必要があります)が、リソースからのピックスマップを使用している場合は良い方法です。

スタイルシートの例:

image: url(:/resource/path);
image-position: right center; /* optional: default is centered. */

コード内(例):

QString stylesheet = "image:url(%1);image-position:right center;";
existingLabel->setStyleSheet(stylesheet.arg(":/resource/path"));

または、Designerでスタイルシートプロパティを設定することもできます。

ここに画像の説明を入力してください アイコンソース:Flaticon経由のDesignspaceチーム

注意点は、画像が大きくなるのではなく、小さくなるだけなので、拡大したい場合は、画像がサイズの範囲よりも大きいことを確認してください(SVGをサポートできるため、品質が向上する可能性があります)。

ラベルのサイズは通常どおりに制御できます。スタイルシートでサイズ要素を使用するか、標準のレイアウトとサイズポリシー戦略を使用します。

詳細については、ドキュメントを参照してください。

このスタイルはQtの初期から存在しています(位置は2007年頃の4.3で追加されましたが、画像はそれ以前にありました)。

于 2022-01-26T03:22:46.610 に答える
0

Qtのドキュメントには、内の画像のサイズ変更の処理を示す画像ビューアの例QLabelがあります。基本的な考え方は、および必要に応じて使用するQScrollAreaためのコンテナとして使用し、使用可能なスペースを埋める、および/または内部のQLabelのサイズを変更できるようにすることです。さらに、アスペクト比を尊重しながらQLabelのサイズを変更するには、次のようにします。QLabellabel.setScaledContents(bool)scrollarea.setWidgetResizable(bool)

label.setPixmap(pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::FastTransformation));

widthおよびは、およびheightに基づいて設定できます。このようにして、QLabelをサブクラス化する必要はありません。scrollarea.width()scrollarea.height()

于 2020-09-02T14:21:28.783 に答える
0

私はついにこれを期待通りに機能させることができました。sizeHintをオーバーライドしresizeEvent、最小サイズとサイズポリシーを設定する ことが不可欠です。setAlignmentコントロールが画像と異なるアスペクト比である場合、コントロールの画像を水平または垂直に中央揃えにするために使用されます。

class ImageDisplayWidget(QLabel):
    def __init__(self, max_enlargement=2.0):
        super().__init__()
        self.max_enlargement = max_enlargement
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setAlignment(Qt.AlignCenter)
        self.setMinimumSize(1, 1)
        self.__image = None

    def setImage(self, image):
        self.__image = image
        self.resize(self.sizeHint())
        self.update()

    def sizeHint(self):
        if self.__image:
            return self.__image.size() * self.max_enlargement
        else:
            return QSize(1, 1)

    def resizeEvent(self, event):
        if self.__image:
            pixmap = QPixmap.fromImage(self.__image)
            scaled = pixmap.scaled(event.size(), Qt.KeepAspectRatio)
            self.setPixmap(scaled)
        super().resizeEvent(event)
于 2021-11-01T11:49:46.010 に答える
0

ここでは本当に新しいことは何もありません。

受け入れられた返信 https://stackoverflow.com/a/8212120/11413792https://stackoverflow.com/a/43936590/11413792 を使用して混合しましsetContentsMarginsたが、少し独自の方法でコーディングしました。

/**
 * @brief calcMargins Calculate the margins when a rectangle of one size is centred inside another
 * @param outside - the size of the surrounding rectanle
 * @param inside  - the size of the surrounded rectangle
 * @return the size of the four margins, as a QMargins
 */
QMargins calcMargins(QSize const outside, QSize const inside)
{
    int left = (outside.width()-inside.width())/2;
    int top  = (outside.height()-inside.height())/2;
    int right = outside.width()-(inside.width()+left);
    int bottom = outside.height()-(inside.height()+top);

    QMargins margins(left, top, right, bottom);
    return margins;
}

関数は、ある長方形を別の長方形の中央に配置するために必要なマージンを計算します。何がわからないのですが、いろいろなことに使えるかなり汎用的な機能です。

その後setContentsMargins、多くの人が1つに結合する2つの余分な行で使いやすくなります。

QPixmap scaled = p.scaled(this->size(), Qt::KeepAspectRatio);
QMargins margins = calcMargins(this->size(), scaled.size());
this->setContentsMargins(margins);
setPixmap(scaled);

それは誰かに興味があるかもしれません...私は処理mousePressEventし、画像内のどこにいるかを知る必要がありました。

void MyClass::mousePressEvent(QMouseEvent *ev)
{
    QMargins margins = contentsMargins();

    QPoint labelCoordinateClickPos = ev->pos();
    QPoint pixmapCoordinateClickedPos = labelCoordinateClickPos - QPoint(margins.left(),margins.top());
    ... more stuff here
}

私の大きな画像はカメラからのものであり、ピックスマップの幅で割ってから元の画像の幅を掛けることによって相対座標[0、1)を取得しました。

于 2021-12-22T13:08:25.507 に答える