pyqt5 QLabel Image setScaledContents(True) 不允许Qpainter更新

pyqt5 QLabel Image setScaledContents(True) don't allow Qpainter updates

我想在每次鼠标左键单击时显示图像并在当前鼠标位置放置一个标记。

下面的代码完成了这项工作,但只有在注释 ("self.imglabel.setScaledContents(True)") 时它才有效。有什么原因吗?

我必须在不同分辨率的各种图像上完成这项工作,我阅读以保持适当的宽高比并适当地显示我们需要使用的图像 setScaledContents(True)。但是为什么启用它不允许 update() (PaintEvent)??

import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QSizePolicy, QMessageBox
from PyQt5.QtGui import QPixmap, QPainter, QPen, QColor, QImage, QPalette

class Menu(QMainWindow):
    def __init__(self):
        super().__init__()
        self.central_widget = QWidget()               # define central widget
        self.setCentralWidget(self.central_widget)
        self.vbox = QVBoxLayout(self.central_widget)       
        self.vbox.addWidget(self.imgWidget())
        self.vbox.addWidget(QPushButton("test"))

    def imgWidget(self):
        self.imglabel = QLabel()
        self.imglabel.setScaledContents(True)
        self.image = QImage("calib.jpeg")
        self.imagepix = QPixmap.fromImage(self.image)
        self.imglabel.setPixmap(self.imagepix)
        self.imglabel.mousePressEvent = self.imgMousePress
        return self.imglabel

    def imgMousePress(self, e):
        painter = QPainter(self.imglabel.pixmap())
        pen = QPen()
        pen.setWidth(10)
        pen.setColor(QColor('red'))
        painter.setPen(pen)
        painter.drawPoint(e.x(), e.y())
        painter.end()
        self.imglabel.update()

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

为了避免对 QLabel 的每个 paintEvent 进行不必要的计算,只要 scaledContents 属性 为 True,缩放后的图像就会被缓存,所有的绘画都会被自动丢弃。

为避免这种情况,您应该使用现有的 QPixmap 创建一个新实例,然后再次设置新绘制的像素图。请注意,如果缩放图像,小部件坐标将不会反映像素图上的实际位置,因此您需要使用转换来获取实际绘制点。

    def imgMousePress(self, e):
        pm = QPixmap(self.imglabel.pixmap())
        painter = QPainter(pm)
        pen = QPen()
        pen.setWidth(10)
        pen.setColor(QColor('red'))
        painter.setPen(pen)
        transform = QTransform().scale(
            pm.width() / self.imglabel.width(), 
            pm.height() / self.imglabel.height())
        painter.drawPoint(transform.map(e.pos()))
        painter.end()
        self.imglabel.setPixmap(pm)

考虑到如果 width/height 比例与源图像不同,所有 "points" 都会变成拉伸矩形,但这只是外观问题:如果您稍后保存像素图, 它们将再次成为正方形,因为保存是基于源像素图。
如果你想在显示时保持它们的方形,你需要跟踪点并覆盖 paintEvent 以在标签上手动绘制它们。