Qt: अपने पहलू अनुपात को बनाए रखते हुए QLixmap युक्त QLabel का आकार बदलना


81

मैं उपयोगकर्ता के लिए QPixmap को गतिशील रूप से बदलने वाली सामग्री प्रदर्शित करने के लिए QLabel का उपयोग करता हूं। उपलब्ध जगह के आधार पर इस लेबल को छोटा / बड़ा करना अच्छा होगा। स्क्रीन का आकार हमेशा QPixmap जितना बड़ा नहीं होता है।

मैं मूल QPixmap के पहलू अनुपात को ध्यान में रखते हुए QPixmap को आकार QSizePolicyदेने sizeHint()के लिए QLabel को कैसे संशोधित कर सकता हूं ?

मैं sizeHint()QLabel को संशोधित नहीं कर सकता , minimumSize()शून्य पर सेट करने से मदद नहीं मिलती। hasScaledContents()QLabel पर सेटिंग बढ़ने की अनुमति देता है, लेकिन पहलू अनुपात को तोड़ता है ...

Subclassing QLabel ने मदद की, लेकिन यह समाधान सिर्फ एक साधारण समस्या के लिए बहुत अधिक कोड जोड़ता है ...

किसी भी स्मार्ट संकेत उपवर्ग के बिना इसे पूरा करने के लिए कैसे ?


गतिशील रूप से बदलने से क्या आपको पिक्सेल डेटा या आयामों से मतलब है?
r_ahlskog

मेरा मतलब QLabelहै कि वर्तमान लेआउट में आयाम । QPixmapइसके आकार, सामग्री और आयाम रखना चाहिए। इसके अलावा, यह आकार बदलने के लिए अच्छा होगा (वास्तविकता में सिकुड़ते हुए) उपलब्ध स्थान को भरने के लिए "स्वचालित रूप से" होता है - मूल के आकार तक QPixmap। यह सब उपवर्ग के माध्यम से किया गया था ...
marvin2k

जवाबों:


98

लेबल आकार बदलने के लिए आप विस्तार या न्यूनतम विस्तार जैसे लेबल के लिए एक उपयुक्त आकार नीति का चयन कर सकते हैं।

हर बार जब आप बदलाव करते हैं, तो आप इसके पहलू अनुपात को ध्यान में रखकर पिक्समैप को माप सकते हैं:

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

दो जगह हैं जहाँ आपको यह कोड जोड़ना चाहिए:

  • जब Pixmap को अपडेट किया जाता है
  • में resizeEventविजेट है कि लेबल शामिल की

हम्म, हाँ, यह मूल रूप से मुख्य था जब मैंने उपवर्ग किया QLabel। लेकिन मुझे लगा कि यह उपयोग मामला (मनमाने आकार के विजेट में मनमाने आकार के साथ छवियां दिखाना) पर्याप्त होगा जो मौजूदा कोड के माध्यम से इसे लागू करने जैसा कुछ हो ...
मार्विन 2k

AFAIK यह कार्यक्षमता डिफ़ॉल्ट रूप से प्रदान नहीं की गई है। जो आप चाहते हैं उसे प्राप्त करने का सबसे सुरुचिपूर्ण तरीका उपवर्ग है QLabel। अन्यथा आप एक स्लॉट / फ़ंक्शन में मेरे उत्तर के कोड का उपयोग कर सकते हैं जिसे हर बार पिक्समैप में परिवर्तन कहा जाएगा।
pnezis

1
चूँकि मैं QLabelउपयोगकर्ताओं QMainWindowऔर उपलब्ध स्थान के आकार के आधार पर स्वचालित रूप से विस्तार करना चाहता हूं , इसलिए मैं सिग्नल / स्लॉट समाधान का उपयोग नहीं कर सकता - मैं इस तरह से एक विस्तार नीति नहीं बना सकता ।
15

21
साथ ही साथ बड़े पैमाने पर सक्षम होने के लिए, आपको इस कॉल को जोड़ने की आवश्यकता है:label->setMinimumSize(1, 1)
पीटर-जन बूस्चर्ट

1
यह बहुत उपयोगी नहीं है अगर मैं पहलू राशन को संरक्षित करना चाहता हूं, भले ही उपयोगकर्ता लेबल के आकार में परिवर्तन करता है।
टॉम ज़ातो -

33

मैंने इस लापता उपवर्ग को पॉलिश किया है QLabel। यह कमाल है और अच्छी तरह से काम करता है।

पहलु

#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

पहलु

#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 का उत्तर)


1
धन्यवाद, महान काम करता है। मैं भी जोड़ना होगा QLabel::setPixmap(pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));करने के लिए setPixmap()विधि।
Hyndrix

तुम सही हो। मैंने यह अनुमान लगाया कि आप पिक्समैप के उच्चतम गुणवत्ता संस्करण को संग्रहीत करना चाहते हैं, और लेबल को आकार देने / एंकरिंग करने से पहले आप सेटपिक्समैप कहते हैं। कोड दोहराव को कम करने के लिए, मुझे संभवतः फ़ंक्शन के this->resize(width(), height());अंत में रखना चाहिए setPixmap
phyatt

इसे साझा करने के लिए धन्यवाद। क्या आपके पास कोई सुझाव होगा कि मैं Q "प्रिक्सपैम में" पसंदीदा "आकार कैसे सेट कर सकता हूं ताकि यह एप्लिकेशन के पहले लॉन्च पर अधिकतम रिज़ॉल्यूशन न ले?
जुलिएन एम

लेआउट और खिंचाव के नियमों का उपयोग करें।
फिएट

3
बहुत बढ़िया जवाब! उच्च डीपीआई स्क्रीन पर काम करने की आवश्यकता वाले किसी व्यक्ति के लिए बस स्केल्डपिक्समैप () को बदलने के लिए: auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(devicePixelRatioF()); return scaled;यह सामान्य रूप से स्केल किए गए स्क्रीन पर भी काम करता है।
शाऊल

18

मैं सिर्फ 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);
    }
}

मेरे लिए अब तक पूरी तरह से काम करता है। आपका स्वागत है।


4
बस इस का इस्तेमाल किया और यह एक आकर्षण की तरह काम करता है! इसके अलावा, लेआउट प्रबंधक का बहुत चालाक उपयोग। सभी मामलों में खामियां होने के कारण स्वीकृत जवाब होना चाहिए।
त्रिकोणीय

2
जबकि गैर-सहज रूप से चतुर, यह उत्तर एक मौलिक रूप से भिन्न प्रश्न को हल करता है : "हमें एक लेबल के बीच कितना आंतरिक पैडिंग जोड़ना चाहिए जिसका आकार पहले से ही ज्ञात है और उस लेबल में शामिल पिक्समैप उस पिक्समैप के पहलू अनुपात को संरक्षित करने के लिए है? " हर दूसरा उत्तर मूल प्रश्न को हल करता है: "किस आकार का हमें पिक्समैप युक्त एक लेबल का आकार बदलना चाहिए ताकि उस पिक्समैप के पहलू अनुपात को संरक्षित किया जा सके?" इस उत्तर के लिए लेबल के आकार को किसी तरह पूर्व निर्धारित करने की आवश्यकता होती है (जैसे, एक निश्चित आकार की नीति के साथ), जो कई उपयोग के मामलों में अवांछनीय या यहां तक ​​कि अक्षम है।
सेसिल करी

1
यह HiResolution (उर्फ "रेटिना") के लिए जाने का रास्ता दिखाता है - यह QPixmap को डाउन करने से कहीं बेहतर है।
jvb

हो सकता है कि मैं एक छोटे से भी बनाने पर ध्यान केंद्रित कर रहा हूँ कोड उच्च स्तरीय रख-रखाव के लिये अर्थ को व्यक्त लेकिन इसे और अधिक समझ में उपयोग करने के लिए नहीं होगा QSizeके बजाय ...Widthऔर ...Height? यदि और कुछ नहीं, तो यह आपके शुरुआती रिटर्न की जांच को एक साधारण QSize::isEmptyकॉल बना देगा। QPixmapऔर QWidgetदोनों के पास sizeचौड़ाई और ऊंचाई को पुनः प्राप्त करने के तरीके हैं QSize
ssokolow 12

@ssokolow हाँ जो बेहतर लगता है - उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें।
टिम्मम नोव

5

मैंने फिएट की AspectRatioPixmapLabelकक्षा का उपयोग करने की कोशिश की , लेकिन कुछ समस्याओं का अनुभव किया:

  • कभी-कभी मेरा ऐप आकार बदलने वाली घटनाओं का एक अनंत लूप में प्रवेश करता है। मैंने इसे QLabel::setPixmap(...)पुनः आकार विधि के अंदर कॉल करने के लिए वापस ट्रेस किया, क्योंकि QLabelवास्तव में कॉल updateGeometryअंदर होता है setPixmap, जो पुन: आकार देने वाली घटनाओं को ट्रिगर कर सकता है ...
  • heightForWidthQScrollAreaजब तक मैं स्पष्ट रूप से कॉल करने के लिए लेबल के लिए एक आकार नीति स्थापित करना शुरू नहीं करता, तब तक युक्त विजेट ( मेरे मामले में) को नजरअंदाज किया गयाpolicy.setHeightForWidth(true)
  • मैं चाहता हूं कि लेबल मूल पिक्समैप आकार से अधिक कभी न बढ़े
  • QLabelminimumSizeHint()पाठ के लेबल के लिए कुछ जादू करता है, लेकिन कार्यान्वयन हमेशा डिफ़ॉल्ट नीति आकार को रीसेट करता है, इसलिए मुझे इसे अधिलेखित करना पड़ा

उस ने कहा, यहाँ मेरा समाधान है। मैंने पाया कि मैं सिर्फ इस्तेमाल कर सकता हूं setScaledContents(true)और QLabelआकार बदलने का काम कर सकता हूं । बेशक, यह सम्मान करने वाले युक्त विजेट / लेआउट पर निर्भर करता है heightForWidth

पहलु

#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

पहलु

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

किनारे के मामलों के लिए बेहतर है, जिसमें इस लेबल वाले माता-पिता विजेट और / या लेआउट heightForWidthसंपत्ति का सम्मान करते हैं, यह उत्तर सामान्य मामले के लिए विफल रहता है जिसमें माता-पिता विजेट और / या इस लेबल वाले लेआउट संपत्ति का सम्मान नहीं करते heightForWidthहैं। जो दुर्भाग्यपूर्ण है, क्योंकि यह उत्तर अन्यथा फिएट के लंबे समय तक उत्तर देने के लिए बेहतर है ।
सेसिल करी

3

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)

0

Qt दस्तावेज़ीकरण में एक छवि दर्शक उदाहरण है जो एक के अंदर छवियों को आकार देने से निपटने को प्रदर्शित करता है QLabel। मूल विचार के लिए QScrollAreaएक कंटेनर के रूप में उपयोग करना है QLabelऔर यदि आवश्यक उपयोग है label.setScaledContents(bool)और scrollarea.setWidgetResizable(bool)उपलब्ध स्थान को भरने और / या सुनिश्चित करें कि अंदर QLabel resizable है। इसके अलावा, पहलू अनुपात का उपयोग करते हुए QLabel का आकार बदलने के लिए:

widthऔर heightके आधार पर स्थापित किया जा सकता scrollarea.width()है और scrollarea.height()। इस तरह QLabel को उप-करने की कोई आवश्यकता नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.