如何在不使用类的情况下自动调整QLabel像素图保持率的大小



我们正在使用PyQt和Qt设计器制作GUI。现在,我们需要放置在QLabel中的图像(像素图)在调整窗口大小时很好地保持比例。

我一直在阅读其他问题/答案,但它们都使用了扩展课程。由于我们在UI中不断进行更改,并且它是用Qt Creator创建的,.UI和(相应的).py文件是自动生成的,所以,如果我没有错的话,使用类解决方案对我们来说不是一个好的选择,因为我们应该在每次更新UI时手动更改类的名称。

有没有任何选项可以在QLAbel中自动重设像素图,保持比例并避免使用扩展冲突?

谢谢。

有几种方法可以做到这一点。

首先,您可以在QtDesigner中将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)

为标签设置背景图像:、背景重复:和背景位置QSS属性。您可以通过Forms编辑器或代码QWidget::setStyleSheet来完成此操作。

QSS的一个良好起点(附示例)-http://doc.qt.io/qt-5/stylesheet-reference.html

一种方法是创建一个QWidget/QLabel子类并重新实现resizeEvent

void QWidget::resizeEvent(QResizeEvent*事件)[virtualprotected]

该事件处理程序可以在子类中重新实现,以接收在事件参数中传递的小部件调整大小事件。当调用resizeEvent()时,小部件已经有了新的几何体。可以通过QResizeEvent::oldSize()访问旧大小。

小部件将被擦除,并在处理大小调整事件后立即接收绘画事件。不需要(或不应该)在此处理程序中进行绘图。

这需要在C++中完成,而不是PyQt。

完成后,您可以将自定义小部件添加到QtDesigner中,如下所示:

在Qt Designer 中使用自定义小工具

令人难以置信的是,经过七年的努力,@ekhurmo的出色回答仍然是目前唯一可用的Python实现;其他人告诉该做什么,但没有人给出实际的代码。

尽管如此,它一开始对我来说并不起作用,因为我碰巧在代码中的其他地方生成了像素图——特别是,我的像素图是在一个函数内生成的,该函数只有在单击按钮时才会激活,所以在窗口初始化期间不会激活。

在弄清楚@ekhumulko的第二种方法是如何工作的之后,我对其进行了编辑,以适应这种差异。在实践中,我概括了原始代码,也是因为我不喜欢(出于效率原因)它如何向标签添加新的_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设置为ExpandingIgnored来实现的。请注意,如果未将包含图像的标签设置为中心小部件(self.setCentralWidget(self.label),其中selfMainWindow),则可能不起作用。

最新更新