我已经阅读了其他问题/答案,但是它们都使用了扩展类。由于我们不断更改UI,并且使用Qt Creator创建它,.ui和(相应的).py文件会自动生成,因此,如果我没有弄错的话,使用类解决方案对我们来说不是一个好选择,因为每次更新ui时我们都应手动更改类名。
有没有选项可以自动调整QLAbel中的pixmap大小并保持比例而不使用扩展类呢?
谢谢。
有几种方法可以做到这一点。
首先,您可以在Qt Designer中将您的QLabel提升为一个用Python编写的自定义子类。右键单击QLabel并选择“Promote to ...”,然后给该类命名(例如“ScaledLabel”)并设置头文件为自定义子类类将从中导入的Python模块(例如'mylib.classes')。
然后,自定义子类将像这样重新实现resizeEvent
:
class ScaledLabel(QtGui.QLabel):
def __init__(self, *args, **kwargs):
QtGui.QLabel.__init__(self)
self._pixmap = QtGui.QPixmap(self.pixmap())
def resizeEvent(self, event):
self.setPixmap(self._pixmap.scaled(
self.width(), self.height(),
QtCore.Qt.KeepAspectRatio))
为了使此方法正常工作,QLabel应该将其大小策略设置为"expanding"或"minimumExpanding",并且最小大小应该设置为较小的非零值(以便图像可以被缩小)。
第二种方法避免使用子类,并使用事件过滤器来处理调整大小事件:
class MainWindow(QtGui.QMainWindow):
def __init__(self):
...
self._pixmap = QtGui.QPixmap(self.label.pixmap())
self.label.installEventFilter(self)
def eventFilter(self, widget, event):
if (event.type() == QtCore.QEvent.Resize and
widget is self.label):
self.label.setPixmap(self._pixmap.scaled(
self.label.width(), self.label.height(),
QtCore.Qt.KeepAspectRatio))
return True
return QtGui.QMainWindow.eventFilter(self, widget, event)
为您的标签设置background-image,background-repeat和background-position QSS属性。您可以通过表单编辑器或代码 QWidget :: setStyleSheet
来实现。
QSS的良好起点(附有示例)- http://doc.qt.io/qt-5/stylesheet-reference.html 。
resizeEvent
。
void QWidget::resizeEvent(QResizeEvent * event) [virtual protected]
可以在子类中重新实现此事件处理程序,以接收传递给event参数的小部件调整大小事件。当调用resizeEvent()时,小部件已经具有其新几何形状。旧大小可通过QResizeEvent::oldSize()访问。
在处理调整大小事件后,小部件将被擦除并立即接收绘图事件。不需要在此处理程序内进行任何绘制(也不应该)。
这需要使用C++完成,而不是PyQt。
完成后,您可以按如下方式将自定义小部件添加到QtDesigner中:
令人难以置信的是,经过七年,@ekhumoro的出色回答仍然是唯一可以找到的基本可行的Python实现;其他人告诉你该怎么做,但没有人给出实际的代码。
尽管如此,对我来说起初并没有起作用,因为我碰巧在代码的其他地方生成了像素图 - 具体来说,我的像素图是在点击按钮时才激活的函数内生成的,因此不是在窗口初始化期间生成的。
在弄清楚@ekhumoro的第二种方法如何工作之后,我进行了编辑,以适应这种差异。实际上,我将原始代码概括了,也因为我不喜欢(出于效率原因)它如何向标签添加新的_pixmap属性,这似乎只是原始像素图的副本。
以下是我的版本;请注意,我尚未完全测试它,但由于它是我的原始工作代码的较短版本,因此它也应该可以正常工作(欢迎更正):
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# Initialize stuff here; mind that no pixmap is added to the label at this point
def eventFilter(self, widget, event):
if event.type() == QEvent.Resize and widget is self.label:
self.label.setPixmap(self.label.pixmap.scaled(self.label.width(), self.label.height(), aspectRatioMode=Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation))
return True
return QMainWindow.eventFilter(self, widget, event)
def apply_pixelmap(self, image): # This is where the pixmap is added. For simplicity, suppose that you pass a QImage as an argument to this function; however, you can obtain this in any way you like
pixmap = QPixmap.fromImage(image).scaled(new_w, new_h, aspectRatioMode=Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation)
self.label.setPixmap(pixmap)
self.label.pixmap = QPixmap(pixmap) # I am aware that this line looks like a redundancy, but without it the program does not work; I could not figure out why, so I will gladly listen to anyone who knows it
self.label.installEventFilter(self)
return
ScaledContents
属性设置为 False
,并将 SizePolicy
设置为 Expanding
或 Ignored
来实现。请注意,如果包含图像的标签未设置为中央小部件(self.setCentralWidget(self.label)
,其中 self
指的是 MainWindow
),则可能无法正常工作。