在保持比例的情况下调整QPixmap大小

2 投票
2 回答
12858 浏览
提问于 2025-04-18 09:01

为了在调整 QDialog 大小时保持图片的宽高比,我尝试了以下方法:

import os, sys
from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt

class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)
        self.pic = QLabel()
        self.pic.resizeEvent = onResize 
        self.pic.setPixmap(QPixmap(os.getcwd() + "/images/1.jpg").scaled(300, 200, Qt.KeepAspectRatio,Qt.SmoothTransformation))
        layout = QGridLayout()
        layout.addWidget(self.pic, 1, 0)
        self.setLayout(layout)

def onResize(event):
    size = dialog.pic.size()
    dialog.pic.setPixmap(QPixmap(os.getcwd() + "/images/1.jpg").scaled(size, Qt.KeepAspectRatio, Qt.SmoothTransformation))    

if __name__ == '__main__':
    app = QApplication(sys.argv)
    dialog = Dialog()
    dialog.show()
    sys.exit(app.exec_())

正如预期的那样,图片一开始是300x200的大小。可以随意放大,但大小完全不能缩小(放大后只能回到300x200)。看起来 onResize 这个部分似乎缺少了一些东西。

2 个回答

0

你的 onResize 是一个独立的函数,而不是 Dialog 类的方法(看看缩进和没有 'self'),所以它根本不会被调用。

3

我有一个可以解决这个问题的例子。不要使用 setPixmap 方法来在小部件上绘制图像,而是通过重新实现小部件的 paintEvent 来绘制。

from PyQt4 import QtGui, QtCore
import sys
from PyQt4.QtCore import Qt

class Label(QtGui.QLabel):
    def __init__(self, img):
        super(Label, self).__init__()
        self.setFrameStyle(QtGui.QFrame.StyledPanel)
        self.pixmap = QtGui.QPixmap(img)

    def paintEvent(self, event):
        size = self.size()
        painter = QtGui.QPainter(self)
        point = QtCore.QPoint(0,0)
        scaledPix = self.pixmap.scaled(size, Qt.KeepAspectRatio, transformMode = Qt.SmoothTransformation)
        # start painting the label from left upper corner
        point.setX((size.width() - scaledPix.width())/2)
        point.setY((size.height() - scaledPix.height())/2)
        print point.x(), ' ', point.y()
        painter.drawPixmap(point, scaledPix)


class Main(QtGui.QWidget):          
    def __init__(self):
        super(Main, self).__init__()
        layout = QtGui.QGridLayout()
        label = Label(r"/path/to/some/image.png")
        layout.addWidget(label)
        layout.setRowStretch(0,1)
        layout.setColumnStretch(0,1)

        self.setLayout(layout)
        self.show()

if __name__ =="__main__":
    app = QtGui.QApplication(sys.argv)
    widget = Main()
    sys.exit(app.exec_())

把整个代码复制下来,直接运行。然后试着调整出现的窗口大小。接着理解一下 Label 类中的 paintEvent。别忘了在 Main 类的 __init__ 方法中把路径改成一个存在的 png 图片。

更新:关于更换图片:

要更换图片,你可以在 Label 类中添加一个方法 changePixmap(self, img),然后在你想更换图像的事件中调用这个方法。

...
def changePixmap(self, img):
    self.pixmap = QtGui.QPixmap(img)
    self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label

你可以通过在 Main 类中保存对 Label 类的引用到一个成员变量来调用这个方法。

...
self.label = Label('/path/to/image.png')
...

然后在 Main 类的任何事件中,调用 self.label.changePixmap('path/to/new/image.png')

撰写回答