Qt中enterEvent触发paintEvent实现鼠标悬浮图片按钮变暗
核心错误点
- Qt绘制机制有强制约束:所有针对控件的自定义绘制操作,仅允许在
paintEvent回调内部执行。在enterEvent、鼠标响应等其他回调中直接创建QPainter操作控件绘制,会触发绘制冲突,属于错误用法。 - 你注释的报错行还有一处逻辑错误:
enterEvent传入的参数是QEnterEvent类型,该类型本身不存在rect()属性,仅存储鼠标进入时的坐标、修饰键等信息,不携带控件绘制区域数据。
实现方案
鼠标悬浮变暗的效果完全可以实现,不需要在非绘制事件中直接操作画笔,按以下逻辑实现即可:
- 给按钮类增加布尔类型的状态标记,记录当前控件是否处于鼠标悬浮状态
- 重写
enterEvent:鼠标进入时将悬浮标记设为True,调用update()方法主动触发控件重绘 - 重写
leaveEvent:鼠标离开时将悬浮标记设为False,同样调用update()触发重绘 - 所有绘制逻辑集中在
paintEvent中实现:先绘制原始图片,再根据悬浮标记判断是否叠加半透明黑色遮罩,实现变暗效果
修正后完整代码
from PySide2 import QtWidgets from PySide2 import QtGui from PySide2 import QtCore import sys class PicButton(QtWidgets.QAbstractButton): def __init__(self, pixmap, parent=None): super(PicButton, self).__init__(parent) self.pixmap = pixmap # 悬浮状态标记位 self.is_hover = False def paintEvent(self, event): painter = QtGui.QPainter(self) # 绘制原始图片 painter.drawPixmap(self.rect(), self.pixmap) # 悬浮状态下叠加半透黑遮罩实现变暗 if self.is_hover: painter.fillRect(self.rect(), QtGui.QColor(0, 0, 0, 128)) def enterEvent(self, event): self.is_hover = True self.update() def leaveEvent(self, event): self.is_hover = False self.update() def sizeHint(self): return self.pixmap.size() if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) window_wid = QtWidgets.QWidget() vlayout_wid = QtWidgets.QVBoxLayout() myPixmap = QtGui.QPixmap("image.jpg") my_button = PicButton(myPixmap) my_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) my_button.setMaximumSize(200, 100) vlayout_wid.addWidget(my_button) window_wid.setLayout(vlayout_wid) window_wid.show() sys.exit(app.exec_())
调参提示
- 遮罩透明度为
QColor的第四个参数,取值范围0-255,数值越大变暗效果越强,可根据实际UI需求调整 - 如果需要实现按钮点击按下的效果,可按相同思路新增
is_pressed标记位,在鼠标按下、释放回调中更新状态并触发重绘,在paintEvent中对应调整遮罩透明度即可 update()是Qt官方推荐的重绘触发方式,它会将绘制事件投递到事件队列中按调度顺序执行,不会产生绘制冲突,不要直接手动调用paintEvent。
内容的提问来源于stack exchange,提问作者johancc
相关产品推荐
相关产品推荐

