我怎样才能让 QLabel 与它显示的 QPixmap 的大小完全一致?

Posted

技术标签:

【中文标题】我怎样才能让 QLabel 与它显示的 QPixmap 的大小完全一致?【英文标题】:How can I have a QLabel exactly the size of the QPixmap it is showing? 【发布时间】:2019-08-19 15:44:14 【问题描述】:

我需要一些关于 QT/PyQt 布局的建议。

我想要实现的是让图像显示、居中、正确缩放,在保持纵横比的同时占用尽可能多的空间。使用这个可以很容易地做到这一点:

class Demo(QWidget):
    def __init__(self) -> None:
        super().__init__()
        self.setWindowState(Qt.WindowMaximized)
        self.layout = QVBoxLayout()
        self.setLayout(self.layout)

        self.button = QPushButton("Next image")
        self.label = QLabel()
        self.label.setStyleSheet("QLabel  background-color : red; ")
        self.label.setAlignment(Qt.AlignCenter)

        self.layout.addWidget(self.label)
        self.layout.addWidget(self.button)

        self.button.clicked.connect(self.showImage)
        self.show()


    def showImage(self):
        self.pixmap = QPixmap("image.jpg")
        scaled = self.pixmap.scaled(self.label.size(), Qt.KeepAspectRatio)
        self.label.setPixmap(scaled)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Demo()
    sys.exit(app.exec_())

这样做的问题是,图像将显示在标签的中心,周围有很多“多余的标签”,见截图,红色的东西

但我需要标签 正好 是图像的大小。我想在图像上做一些橡皮筋以选择其中的一部分(选择框以供以后在视网膜训练中使用)并计算我需要 mapToGlobal 和 mapFromGlobal 的框的正确大小。我不能从 Pixmap 本身执行此操作(因为它不是小部件),当我从标签执行此操作时,我会得到错误的值,因为它大于实际图像。

现在,我可以使用带有 SpacerItems 的 GridLayout 或 HBoxLayout。问题在于它的逻辑。标签的大小(以及在 UI 加载时确定 SpacerItems。当我稍后动态添加图像时,它会缩放到标签的大小,即使它可能更大,如果只有 SpacerItems 会“让路”做标签。结果是,不是左右都有“太多标签”,而是顶部和底部都有“太多标签”。我希望你明白我的意思。

我目前做的是:

    将窗口大小调整为屏幕分辨率 添加(缩放)图像 调整大小 (0,0)

然后应用程序被调整大小,以便 Labe 与图像的大小完全相同(我想要的),但它是一种邪恶的、骇人听闻的、闪烁的、疯狂的方式;-)

编辑: 非常感谢您的回答,@eyllanesc :-) 我试过了,它做了我想要的第一张照片。我忘了提到的是,当第一张图像正确“橡皮筋”时,单击“下一步”按钮后,会显示另一张图像。如果此图像小于实际标签(或横向而不是纵向),则标签会缩小。瞧,在一些不同分辨率和方向的图像之后,标签不断缩小和缩小......

https://pastebin.com/ZMMw20Z7

https://giphy.com/gifs/xlou5RpQoX805fUymR

【问题讨论】:

【参考方案1】:

一种可能的解决方案是将大小的水平策略更改为QSizePolicy::Maximum 并将小部件在布局中居中:

from PyQt5 import QtCore, QtGui, QtWidgets

class Demo(QtWidgets.QWidget):
    def __init__(self) -> None:
        super().__init__()
        self.setWindowState(QtCore.Qt.WindowMaximized)
        layout = QtWidgets.QVBoxLayout(self)
        self.button = QtWidgets.QPushButton("Next image")
        self.label = QtWidgets.QLabel()
        self.label.setStyleSheet("QLabel  background-color : red; ")
        layout.addWidget(self.label)
        layout.addWidget(self.button)
        self.button.clicked.connect(self.showImage)
        self.show()

    def showImage(self):
        self.pixmap = QtGui.QPixmap("image.jpg")
        scaled = self.pixmap.scaled(self.label.size(), QtCore.Qt.KeepAspectRatio)
        self.label.setPixmap(scaled)
        sp = self.label.sizePolicy()
        sp.setHorizontalPolicy(QtWidgets.QSizePolicy.Maximum)
        self.label.setSizePolicy(sp)
        self.layout().setAlignment(self.label, QtCore.Qt.AlignCenter)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ex = Demo()
    sys.exit(app.exec_())

更新:

以前的解决方案的问题是以前的 QLabel 的大小被用作建立新大小的参考,而不是它应该基于它可能拥有的最大大小,为此我实现了一个自定义类跟踪最大尺寸:

from PyQt5 import QtCore, QtGui, QtWidgets
from itertools import cycle
from glob import glob

class Label(QtWidgets.QLabel):
    def resizeEvent(self, event):
        if not hasattr(self, 'maximum_size'):
            self.maximum_size = self.size()
        else:
            self.maximum_size = QtCore.QSize(
                max(self.maximum_size.width(), self.width()),
                max(self.maximum_size.height(), self.height()),
            )
        super(Label, self).resizeEvent(event)

    def setPixmap(self, pixmap):
        scaled = pixmap.scaled(self.maximum_size, QtCore.Qt.KeepAspectRatio)
        super(Label, self).setPixmap(scaled)

class Demo(QtWidgets.QWidget):
    def __init__(self) -> None:
        super().__init__()
        self.setWindowState(QtCore.Qt.WindowMaximized)
        layout = QtWidgets.QVBoxLayout(self)
        self.button = QtWidgets.QPushButton("Next image")
        self.label = Label()
        self.label.setStyleSheet("QLabel  background-color : red; ")
        layout.addWidget(self.label)
        layout.addWidget(self.button)
        self.button.clicked.connect(self.showImage)
        self.show() 
        self.images = cycle(glob("images/*"))

    def showImage(self):
        try:
            filename = next(self.images)
            self.label.setPixmap(QtGui.QPixmap(filename))
            sp = self.label.sizePolicy()
            sp.setHorizontalPolicy(QtWidgets.QSizePolicy.Maximum)
            self.label.setSizePolicy(sp)
            self.layout().setAlignment(self.label, QtCore.Qt.AlignCenter)
        except StopIteration:
            pass

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ex = Demo()
    sys.exit(app.exec_())

【讨论】:

非常感谢您的回答 :-) 我试过了,它完成了我想要的第一张照片。我忘了提到的是,当第一张图像正确“橡皮筋”时,单击“下一步”按钮后,会显示另一张图像。如果此图像小于实际标签(或横向而不是纵向),则标签会缩小。瞧,在一些不同分辨率和方向的图像之后,标签不断缩小和缩小...... 这是用你上面的代码拍摄的,同样的两张图片一遍又一遍。 pastebin.com/ZMMw20Z7giphy.com/gifs/xlou5RpQoX805fUymR 我希望应用程序处于全屏状态,并且图像可以缩放到尽可能大的尺寸,同时保持纵横比。那样的话,橡皮筋是最简单的,我发现......它不需要最大化,(固定)缩放到屏幕分辨率也可以 像魅力一样工作!一千谢谢你:-)

以上是关于我怎样才能让 QLabel 与它显示的 QPixmap 的大小完全一致?的主要内容,如果未能解决你的问题,请参考以下文章

qt编程为什么不能显示图片:qt 为了让QLabel显示图片,用如下语句:

我怎样才能让它显示 10,11,12,13.... 而不是...在 javafx 中。我尝试使用所有这些 setPrefWidth, maxSize 但无法工作

怎么才能让博客图片清晰显示

网页中的表格怎样才能让他的边框显示为一条细线?

我怎样才能让我的背景色填充我的所有内容,即使是水平滚动?

我怎样才能让RecyclerView变得更流畅?