如何在PyQt5中通过鼠标操作在QLabel展示的图片上绘制矩形
PyQt5在QLabel承载的图片上绘制矩形的实现方案
问题根源
你现有代码的核心问题如下:
- 重写的是父容器QWidget的
paintEvent,矩形绘制在父控件层面,和QLabel的图片层级分离,会出现错位问题 - 鼠标事件获取的是父控件的全局坐标,没有对应QLabel的内部相对坐标,绘制位置会偏移
解决方案
自定义可绘制矩形的QLabel子类,所有绘制逻辑和鼠标事件都封装在子类内部,直接作用于QLabel控件本身。
完整可运行代码
import sys from PyQt5 import QtWidgets, QtCore, QtGui class DrawableLabel(QtWidgets.QLabel): def __init__(self, parent=None): super().__init__(parent) self.begin = QtCore.QPoint() self.end = QtCore.QPoint() self.original_pixmap = None def setPixmap(self, pixmap): self.original_pixmap = pixmap super().setPixmap(pixmap) def paintEvent(self, event): super().paintEvent(event) if self.begin.isNull() or self.end.isNull(): return qp = QtGui.QPainter(self) br = QtGui.QBrush(QtGui.QColor(100, 10, 10, 40)) qp.setBrush(br) qp.drawRect(QtCore.QRect(self.begin, self.end).normalized()) def mousePressEvent(self, event): self.begin = event.pos() self.end = event.pos() self.update() def mouseMoveEvent(self, event): self.end = event.pos() self.update() def mouseReleaseEvent(self, event): self.end = event.pos() self.update() class MyWidget(QtWidgets.QWidget): def __init__(self): super().__init__() self.setGeometry(30,30,600,400) self.picture = DrawableLabel(self) self.picture.setGeometry(QtCore.QRect(10, 60, 1111, 541)) self.picture.setMinimumSize(QtCore.QSize(0, 0)) self.picture.setStyleSheet("background-color: rgb(188, 188, 188);") self.picture.setText("") # 替换为你的本地图片路径 pixmap = QtGui.QPixmap("G:/JOB files/JoBfiles/300/5.jpg") self.picture.setPixmap(pixmap) self.picture.setScaledContents(True) self.picture.setObjectName("picture") self.show() if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) ui = MyWidget() mainwindow = QtWidgets.QStackedWidget() mainwindow.addWidget(ui) screen = app.primaryScreen() size = screen.size() mainwindow.setFixedWidth(size.width()) mainwindow.setFixedHeight(size.height()) mainwindow.showMaximized() mainwindow.show() sys.exit(app.exec_())
补充说明
- 代码中调用
normalized()方法是为了适配任意方向的鼠标拖拽,不管你从左上往右下拖还是反向拖拽,都能正常显示矩形 - 如果需要将绘制的矩形永久保存到图片文件中,可在
mouseReleaseEvent中将矩形绘制到self.original_pixmap上,再调用self.original_pixmap.save()方法存储即可 - 因为你开启了
setScaledContents(True),如果需要获取矩形对应原始图片的坐标,需要将QLabel内的相对坐标按缩放比例换算即可。
内容的提问来源于stack exchange,提问作者NaQi
相关产品推荐
相关产品推荐

