eventFilter
方法:使用 PyQt 的 eventFilter
來攔截滑鼠離開或進入畫布的事件(QEvent.Leave
和 QEvent.Enter
)。mousePressEvent
, mouseMoveEvent
, 和 mouseReleaseEvent
來跟蹤滑鼠的位置,並更新畫布內外的狀態。假設整個白色區域都是畫布內,超出去就是畫布外,去偵測滑鼠在畫布上的位置並秀出
ZoomableGraphicsView
類別並設置滑鼠事件此類別繼承自 QGraphicsView
,並會擴展滑鼠事件處理、滾輪縮放功能,以及滑鼠的邊界檢查邏輯。
class ZoomableGraphicsView(QGraphicsView):
def __init__(self, *args, **kwargs):
super(ZoomableGraphicsView, self).__init__(*args, **kwargs)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setRenderHint(QPainter.Antialiasing)
self.setMouseTracking(True) # 啟用滑鼠追蹤
self.viewport().installEventFilter(self) # 安裝事件過濾器
# 相關變數初始化
self.mousePressCallback = None
self.mouseMoveCallback = None
self.mouseReleaseCallback = None
self.mouseLeaveCallback = None
self.last_in_bounds_pos = None # 記錄最後有效滑鼠位置
def eventFilter(self, source, event):
"""偵測滑鼠是否在畫布內或離開畫布"""
if event.type() == QEvent.Leave:
if self.last_in_bounds_pos is not None:
print(f"滑鼠離開畫布,最後位置為 {self.last_in_bounds_pos}")
if self.mouseLeaveCallback:
self.mouseLeaveCallback(event) # 調用離開事件處理
elif event.type() == QEvent.Enter:
print("滑鼠進入畫布範圍")
return super().eventFilter(source, event)
在 ZoomableGraphicsView
中實現 mouseMoveEvent
來檢查滑鼠是否超出畫布邊界範圍。此步驟將確認滑鼠是否在邊界內,若在內則更新 last_in_bounds_pos
。
def mouseMoveEvent(self, event):
"""當滑鼠在畫布內時更新位置,超出邊界則記錄最後位置"""
if self.rect().contains(event.pos()):
# 滑鼠在邊界內,更新有效位置
self.last_in_bounds_pos = self.mapToScene(event.pos())
if self.mouseMoveCallback:
self.mouseMoveCallback(event)
else:
# 滑鼠超出邊界,可根據需求處理
print("滑鼠超出畫布範圍")
當滑鼠移出畫布範圍時,將最後一個在畫布邊界內的位置設為繪製的終點,並觸發終點設置的繪製動作。
def set_end_position(self, end_position):
"""將最後有效位置設定為終點"""
self.end_pos = end_position
print(f"設定繪製終點為 {self.end_pos}")
以下展示了如何將 ZoomableGraphicsView
整合進主窗口應用程式中。此應用程式在 MaskROIEditor
中實現了基於滑鼠事件的繪圖功能。
import sys
from PyQt5.QtCore import QEvent, Qt, QPointF, QRectF
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QMainWindow, QApplication
from PyQt5.QtGui import QPainter, QPen, QColor
class ZoomableGraphicsView(QGraphicsView):
def __init__(self, *args, **kwargs):
super(ZoomableGraphicsView, self).__init__(*args, **kwargs)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setRenderHint(QPainter.Antialiasing)
self.setMouseTracking(True) # 啟用滑鼠追蹤
self.viewport().installEventFilter(self) # 安裝事件過濾器
# 相關變數初始化
self.mousePressCallback = None
self.mouseMoveCallback = None
self.mouseReleaseCallback = None
self.mouseLeaveCallback = None
self.last_in_bounds_pos = None # 記錄最後有效滑鼠位置
def eventFilter(self, source, event):
"""偵測滑鼠是否在畫布內或離開畫布"""
if event.type() == QEvent.Leave:
if self.last_in_bounds_pos is not None:
print(f"滑鼠離開畫布,最後位置為 {self.last_in_bounds_pos}")
if self.mouseLeaveCallback:
self.mouseLeaveCallback(event) # 調用離開事件處理
elif event.type() == QEvent.Enter:
print("滑鼠進入畫布範圍")
return super().eventFilter(source, event)
def mouseMoveEvent(self, event):
"""當滑鼠在畫布內時更新位置,超出邊界則記錄最後位置"""
if self.rect().contains(event.pos()):
# 滑鼠在邊界內,更新有效位置
self.last_in_bounds_pos = self.mapToScene(event.pos())
if self.mouseMoveCallback:
self.mouseMoveCallback(event)
else:
# 滑鼠超出邊界,可根據需求處理
print("滑鼠超出畫布範圍")
def set_end_position(self, end_position):
"""將最後有效位置設定為終點"""
self.end_pos = end_position
print(f"設定繪製終點為 {self.end_pos}")
class MaskROIEditor(QMainWindow):
def __init__(self, img=None):
super().__init__()
# 初始化畫布
self.view = ZoomableGraphicsView()
self.scene = QGraphicsScene(self) # 建立畫布
self.view.setScene(self.scene) # 將畫布設定到視圖中
self.setCentralWidget(self.view)
self.view.mousePressCallback = self.mousePressEvent
self.view.mouseMoveCallback = self.mouseMoveEvent
self.view.mouseReleaseCallback = self.mouseReleaseEvent
self.view.mouseLeaveCallback = self.handle_mouse_leave
# 初始化繪圖變數
self.is_drawing = False
self.start_pos = None
self.end_pos = None
# 設定畫布的大小(可根據需要調整)
self.scene.setSceneRect(QRectF(0, 0, 800, 600))
# 若 img 不為 None,可以在此顯示圖像
if img:
# 此處可將 img 作為背景顯示
pass
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and self.view.rect().contains(event.pos()):
self.is_drawing = True
self.start_pos = self.view.mapToScene(event.pos())
def mouseMoveEvent(self, event):
if self.is_drawing and self.view.rect().contains(event.pos()):
self.end_pos = self.view.mapToScene(event.pos())
# 動態繪製矩形框作為測試
self.scene.clear() # 每次移動時清除畫布內容
pen = QPen(QColor("blue"), 2)
self.scene.addRect(QRectF(self.start_pos, self.end_pos), pen)
def mouseReleaseEvent(self, event):
if self.is_drawing and self.view.rect().contains(event.pos()):
self.is_drawing = False
self.end_pos = self.view.mapToScene(event.pos())
# 完成繪圖
pen = QPen(QColor("red"), 2)
self.scene.addRect(QRectF(self.start_pos, self.end_pos), pen)
def handle_mouse_leave(self, event):
"""處理滑鼠離開畫布"""
if self.is_drawing and self.view.last_in_bounds_pos:
self.view.set_end_position(self.view.last_in_bounds_pos)
self.is_drawing = False
# 觸發最終繪製行為
if __name__ == "__main__":
app = QApplication(sys.argv)
editor = MaskROIEditor()
editor.show()
sys.exit(app.exec_())
installEventFilter
來檢測 QEvent.Leave
和 QEvent.Enter
事件。mouseMoveEvent
中更新 last_in_bounds_pos
。通過這些步驟,你可以有效地在 PyQt 中監控滑鼠的畫布內外狀態,並設置滑鼠移出畫布後的繪製行為。