如何使用PyQt5获取图片像素坐标并在点击位置绘制可更新的点
实现方案
你需要新增点击位置存储逻辑和重绘逻辑即可满足需求,以下是完整修改后的代码:
核心修改点
- 新增实例变量存储最新点击的控件坐标
- 拦截QLabel的绘制事件,在图片上层绘制红色标记点
- 每次有效点击后更新坐标并触发重绘,自动清除旧标记
- 加载新图片时自动清空历史标记
完整可运行代码
from PyQt5 import QtCore, QtGui, QtWidgets class Window(QtWidgets.QWidget): def __init__(self): QtWidgets.QWidget.__init__(self) layout = QtWidgets.QGridLayout(self) self.getImageButton = QtWidgets.QPushButton('选择图片') layout.addWidget(self.getImageButton) self.getImageButton.clicked.connect(self.load_image) self.resim1 = QtWidgets.QLabel() layout.addWidget(self.resim1) self.resim1.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) self.resim1.setScaledContents(True) self.resim1.setFixedSize(701,451) # 给QLabel安装事件过滤器捕获鼠标事件、绘制事件 self.resim1.installEventFilter(self) # 存储最新点击位置(控件坐标系),初始为空 self.last_click_pos = None def load_image(self): filename, filter = QtWidgets.QFileDialog.getOpenFileName(None, '加载图片', '.', '图片文件 (*.png *.jpg *.jpeg *.bmp *.tif)') if not filename: return self.resim1.setPixmap(QtGui.QPixmap(filename)) # 加载新图片后清空历史点击标记 self.last_click_pos = None self.resim1.update() def eventFilter(self, source, event): # 处理绘制事件:先画原图,再画点击标记点 if event.type() == QtCore.QEvent.Paint and source == self.resim1: # 先让QLabel完成默认的图片绘制逻辑 super().eventFilter(source, event) # 如果有最新点击位置,在对应位置绘制红色圆点 if self.last_click_pos is not None: painter = QtGui.QPainter(source) painter.setRenderHint(QtGui.QPainter.Antialiasing) # 设置画笔:红色、宽度6像素、实线,绘制出的点大小适中容易识别 painter.setPen(QtGui.QPen(QtCore.Qt.red, 6, QtCore.Qt.SolidLine)) painter.drawPoint(self.last_click_pos) painter.end() return True # 处理鼠标点击事件 if (source == self.resim1 and source.pixmap() and not source.pixmap().isNull() and event.type() == QtCore.QEvent.MouseButtonPress and event.button() == QtCore.Qt.LeftButton): self.getClickedPosition(event.pos()) return super().eventFilter(source, event) def getClickedPosition(self, pos): # 保存控件坐标系的点击位置,用于后续绘制 click_widget_pos = pos # 计算控件内边距区域 contentsRect = QtCore.QRectF(self.resim1.contentsRect()) if pos not in contentsRect: # 点击位置在控件边距外,忽略 return # 坐标转换为相对于内边距区域的位置 pos -= contentsRect.topLeft() pixmapRect = self.resim1.pixmap().rect() if self.resim1.hasScaledContents(): # 开启了缩放适配,转换为原图像素坐标 x = pos.x() * pixmapRect.width() / contentsRect.width() y = pos.y() * pixmapRect.height() / contentsRect.height() pos = QtCore.QPoint(x, y) else: align = self.resim1.alignment() pixmapRect = QtCore.QRectF(pixmapRect) # 根据对齐方式计算原图在控件中的实际位置 if align & QtCore.Qt.AlignRight: pixmapRect.moveRight(contentsRect.x() + contentsRect.width()) elif align & QtCore.Qt.AlignHCenter: pixmapRect.moveLeft(contentsRect.center().x() - pixmapRect.width() / 2) if align & QtCore.Qt.AlignBottom: pixmapRect.moveBottom(contentsRect.y() + contentsRect.height()) elif align & QtCore.Qt.AlignVCenter: pixmapRect.moveTop(contentsRect.center().y() - pixmapRect.height() / 2) if not pos in pixmapRect: # 点击位置在图片区域外,忽略 return # 转换为原图像素坐标 pos = (pos - pixmapRect.topLeft()).toPoint() print('原图像素坐标:X={}, Y={}'.format(pos.x(), pos.y())) # 更新最新点击位置,触发重绘 self.last_click_pos = click_widget_pos self.resim1.update() if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = Window() w.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者Barun Basnet
相关产品推荐
相关产品推荐

