我想显示图像并在每次鼠标左键单击时将标记放置在当前鼠标位置。
但是下面的代码可以完成这项工作,只有在注释了("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)
考虑到,如果宽/高比与源图像的宽度/高度比不同,则所有“点”都将变成拉伸矩形,但这只是外观上的问题:如果以后保存像素图,它们将再次变为正方形,因为保存基于源像素图。如果要在显示时保持其正方形形状,则需要跟踪这些点并覆盖paintEvent以在标签上手动绘制它们。