PyQT5 VTK 鼠标按钮事件不匹配

问题描述 投票:0回答:1

我使用PyQT5和VTK来显示信息,并一直使用观察者通过交互器风格注册鼠标单击事件。由于某种原因,当单击多个按钮时,释放事件会丢失。我修改了 VTK QT 示例之一来执行此操作:

# Contributed by Eric E Monson

import sys

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera,vtkInteractorStyleUser
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderer
)

class MyInteractorStyle(vtkInteractorStyleTrackballCamera):

    def __init__(self, parent=None):
        self.AddObserver('LeftButtonPressEvent', self.left_button_press_event)
        self.AddObserver('LeftButtonReleaseEvent', self.left_button_release_event)
        self.AddObserver('MiddleButtonPressEvent', self.middle_button_press_event)
        self.AddObserver('MiddleButtonReleaseEvent', self.middle_button_release_event)

    def middle_button_press_event(self, obj, event):
        print('Middle Button pressed')
        #self.OnMiddleButtonDown()
        return

    def middle_button_release_event(self, obj, event):
        print('Middle Button released')
        #self.OnMiddleButtonUp()
        return

    def left_button_press_event(self, obj, event):
        print('Left Button pressed')
        #self.OnLeftButtonDown()
        return

    def left_button_release_event(self, obj, event):
        print('Left Button released')
        #self.OnLeftButtonUp()
        return

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(603, 553)
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.gridlayout = QtWidgets.QGridLayout(self.centralWidget)
        self.vtkWidget = QVTKRenderWindowInteractor(self.centralWidget)
        self.gridlayout.addWidget(self.vtkWidget, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralWidget)


class SimpleView(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ren = vtkRenderer()
        self.ui.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
        self.iren = self.ui.vtkWidget.GetRenderWindow().GetInteractor()
        self.iren.SetInteractorStyle(MyInteractorStyle())

        # Create source
        source = vtkSphereSource()
        source.SetCenter(0, 0, 0)
        source.SetRadius(5.0)

        # Create a mapper
        mapper = vtkPolyDataMapper()
        mapper.SetInputConnection(source.GetOutputPort())

        # Create an actor
        actor = vtkActor()
        actor.SetMapper(mapper)

        self.ren.AddActor(actor)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SimpleView()
    window.show()
    window.iren.Initialize()  # Need this line to actually show the render inside Qt
    sys.exit(app.exec_())

执行以下操作:

  1. 中按并按住
  2. 左按
  3. 左释放
  4. 中间释放

产生以下输出:

  1. 按下中间按钮
  2. 左键按下
  3. 左键松开
  4. 左键松开

最后一个事件显然是不正确的。任何按下和按住的排列似乎都能做到这一点。似乎事件注册不起作用,因为按下的最后一个按钮是“释放”的。当在 pyqt 之外使用 VTK 时,这种行为不会持续存在,这让我相信 QVTKRenderWindowInteractor 存在问题。

python pyqt5 vtk qvtkwidget
1个回答
0
投票

我创建了一个继承自
    CustomQVTKRenderWindowInteractor
  • 的自定义
    QVTKRenderWindowInteractor
    类。这使我们能够直接处理 Qt 鼠标事件,而不是依赖 VTK 的事件系统。
    我重写了自定义类中的 
  • mousePressEvent
  • mouseReleaseEvent
    方法。这些方法现在直接处理 Qt 鼠标事件,确保准确捕获每个按钮的按下和释放。
    我删除了之前用于观察VTK事件的
  • MyInteractorStyle
  • 类。相反,我们现在使用标准
    vtkInteractorStyleTrackballCamera
    进行 3D 导航,同时通过 Qt 处理鼠标按钮事件。
  • SimpleView
  • 类中,我们用自定义
    QVTKRenderWindowInteractor
    替换了标准
    CustomQVTKRenderWindowInteractor
    
    
  • 完整代码:

import sys from typing import Optional from PyQt5 import QtCore, QtWidgets from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera from vtkmodules.vtkFiltersSources import vtkSphereSource from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor class CustomQVTKRenderWindowInteractor(QVTKRenderWindowInteractor): def __init__(self, parent: Optional[QWidget] = None): super().__init__(parent) self.setFocusPolicy(QtCore.Qt.StrongFocus) def mousePressEvent(self, event: QtCore.QEvent): super().mousePressEvent(event) self._print_button_event(event, "pressed") def mouseReleaseEvent(self, event: QtCore.QEvent): super().mouseReleaseEvent(event) self._print_button_event(event, "released") def _print_button_event(self, event: QtCore.QEvent, action: str): button_map = { QtCore.Qt.LeftButton: "Left", QtCore.Qt.MiddleButton: "Middle", QtCore.Qt.RightButton: "Right" } button = button_map.get(event.button(), "Unknown") print(f"{button} Button {action}") class Ui_MainWindow: def setupUi(self, MainWindow: QMainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(603, 553) self.centralWidget = QtWidgets.QWidget(MainWindow) self.gridlayout = QtWidgets.QGridLayout(self.centralWidget) self.vtkWidget = CustomQVTKRenderWindowInteractor(self.centralWidget) self.gridlayout.addWidget(self.vtkWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralWidget) class SimpleView(QMainWindow): def __init__(self, parent: Optional[QWidget] = None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ren = vtkRenderer() self.ui.vtkWidget.GetRenderWindow().AddRenderer(self.ren) self.iren = self.ui.vtkWidget.GetRenderWindow().GetInteractor() self.iren.SetInteractorStyle(vtkInteractorStyleTrackballCamera()) # Create and set up the actor source = vtkSphereSource() source.SetCenter(0, 0, 0) source.SetRadius(5.0) mapper = vtkPolyDataMapper() mapper.SetInputConnection(source.GetOutputPort()) actor = vtkActor() actor.SetMapper(mapper) self.ren.AddActor(actor) def initialize(self): try: self.iren.Initialize() except Exception as e: print(f"Error initializing render window: {e}") if __name__ == "__main__": app = QApplication(sys.argv) window = SimpleView() window.show() window.initialize() sys.exit(app.exec_())

通过 Qt 的事件系统而不是 VTK 的事件系统处理鼠标事件,我们确保正确捕获所有鼠标按钮的按下和释放,即使涉及多个按钮也是如此。这种方法利用了 Qt 强大的事件处理系统,该系统与 PyQt5 应用程序框架更好地集成

执行以下操作:

中按并按住
  1. 左按
  2. 左释放
  3. 中间释放
  4. 产生以下输出:

按下中间按钮
  1. 左键按下
  2. 左键松开
  3. 中间按钮松开
© www.soinside.com 2019 - 2024. All rights reserved.