我怎样才能让 QLabel 的大小与它显示的 QPixmap 的大小完全一样?
How can I have a QLabel exactly the size of the QPixmap it is showing?
我需要一些关于 QT/PyQt 中布局的建议。
我想要实现的是让图像显示、居中、正确缩放,在保持纵横比的同时尽可能地利用 space。使用这个可以很容易地完成:
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_())
这个问题是,图像将以标签为中心显示,周围有很多 "excess Label" 看截图,红色的东西
但我需要标签正好图像的大小。我想对图像的 select 部分进行一些橡皮筋处理(select 框供以后在 retinanet 训练中使用)并计算我需要 mapToGlobal 和 mapFromGlobal 的框的正确大小。我不能从 Pixmap 本身做到这一点(因为它不是小部件),当我从 Label 做到这一点时,我得到了错误的值,因为它比实际图像大。
现在,我可以将 GridLayout 或 HBoxLayout 与 SpacerItems 一起使用。问题在于它的逻辑。标签的大小(和 SpacerItems 在 UI 加载时确定。当我稍后动态添加图像时,它会缩放到标签的大小,即使它可以更大,只要 SpacerItems 会"give way" 做标签。结果是,我没有 "too much Label" 左右,而是 "too much label" 顶部和底部。我希望你明白我的意思。
我目前做的是:
- 将 window 调整为屏幕分辨率
- 添加(缩放的)图像
- 调整大小 (0,0)
然后应用程序会调整大小,以便 Labe 正好是图像的大小(我想要的),但这是一种邪恶的、骇人听闻的、闪烁的、疯狂的方式;-)
编辑:
非常感谢您的回答,@eyllanesc :-)
我试过了,它做了我想要的第一张照片。我忘了说的是,当第一张图片正常时"rubberbanded",点击"Next"按钮后,会显示另一张图片。如果此图像小于实际标签(或横向而不是纵向),则标签会缩小。你看,在一些不同分辨率和方向的图像之后,Label 不断缩小和缩小...
一种可能的解决方案是将大小的水平策略更改为 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的大小被用作建立新大小的参考,而不是它应该基于它可能拥有的最大大小,为此我实现了一个自定义class 跟踪最大尺寸:
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_())
我需要一些关于 QT/PyQt 中布局的建议。
我想要实现的是让图像显示、居中、正确缩放,在保持纵横比的同时尽可能地利用 space。使用这个可以很容易地完成:
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_())
这个问题是,图像将以标签为中心显示,周围有很多 "excess Label" 看截图,红色的东西
但我需要标签正好图像的大小。我想对图像的 select 部分进行一些橡皮筋处理(select 框供以后在 retinanet 训练中使用)并计算我需要 mapToGlobal 和 mapFromGlobal 的框的正确大小。我不能从 Pixmap 本身做到这一点(因为它不是小部件),当我从 Label 做到这一点时,我得到了错误的值,因为它比实际图像大。
现在,我可以将 GridLayout 或 HBoxLayout 与 SpacerItems 一起使用。问题在于它的逻辑。标签的大小(和 SpacerItems 在 UI 加载时确定。当我稍后动态添加图像时,它会缩放到标签的大小,即使它可以更大,只要 SpacerItems 会"give way" 做标签。结果是,我没有 "too much Label" 左右,而是 "too much label" 顶部和底部。我希望你明白我的意思。
我目前做的是:
- 将 window 调整为屏幕分辨率
- 添加(缩放的)图像
- 调整大小 (0,0)
然后应用程序会调整大小,以便 Labe 正好是图像的大小(我想要的),但这是一种邪恶的、骇人听闻的、闪烁的、疯狂的方式;-)
编辑: 非常感谢您的回答,@eyllanesc :-) 我试过了,它做了我想要的第一张照片。我忘了说的是,当第一张图片正常时"rubberbanded",点击"Next"按钮后,会显示另一张图片。如果此图像小于实际标签(或横向而不是纵向),则标签会缩小。你看,在一些不同分辨率和方向的图像之后,Label 不断缩小和缩小...
一种可能的解决方案是将大小的水平策略更改为 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的大小被用作建立新大小的参考,而不是它应该基于它可能拥有的最大大小,为此我实现了一个自定义class 跟踪最大尺寸:
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_())