如何在不使用类的情况下自动调整QLabel pixmap保持率?

时间:2014-01-10 10:30:45

标签: python qt pyqt qt-designer qtgui

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

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

是否有任何选项可以自动调整QLAbel中的像素图,保持比率并避免使用扩展的clases?

感谢。

4 个答案:

答案 0 :(得分:6)

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

首先,您可以将Qt Designer中的QLabel推广到用python编写的自定义子类。右键单击QLabel并选择“Promote to ...”,然后为该类命名(例如“ScaledLabel”)并将头文件设置为将从其导入自定义子类的python模块(例如'mylib。类)。

然后,自定义子类将重新实现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的大小策略应设置为扩展或最小扩展,并且最小大小应设置为小的非零值(因此可以缩小图像)。

第二种方法避免使用子类并使用事件过滤器来处理resize事件:

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)

答案 1 :(得分:1)

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

  

void QWidget :: resizeEvent(QResizeEvent * event)[虚拟保护]

     

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

     

在处理resize事件后,窗口小部件将被删除并立即接收绘制事件。在此处理程序中不需要(或应该)完成绘图。

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

完成后,您可以按如下方式将自定义窗口小部件添加到QtDesigner:

Using Custom Widgets with Qt Designer

答案 2 :(得分:1)

为您的标签设置background-image:,background-repeat:和background-position QSS属性。您可以通过表单编辑器或代码QWidget::setStyleSheet来完成。

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

答案 3 :(得分:1)

令人难以置信的是,七年后 @ekhumoro's excellent answer 仍然几乎是唯一可以找到的 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 设置为 ExpandingIgnored 来实现的。请注意,如果包含图像的标签未设置为中央小部件(self.setCentralWidget(self.label),其中 self 指的是 MainWindow),则它可能不起作用。