Qt 中的 VTK Widget 未按预期更新

VTKWidget in Qt is not updated as expeced

我想在我的 Qt5-Gui 中显示 3D 动画。一切都按预期工作,但不幸的是,当我不与 vtkWidget 交互时,场景没有得到更新。换句话说:当我想看动画时,我需要用鼠标连续点击小部件。如果有任何帮助,我将不胜感激。

import sys
import vtk
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import Qt
import numpy as np

from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor

class mainWindow(Qt.QMainWindow):
def __init__(self, parent = None):
    Qt.QMainWindow.__init__(self, parent)

    self.frame = Qt.QFrame()
    self.vl = Qt.QVBoxLayout()
    self.button = QtWidgets.QPushButton("TestButton")
    self.label = QtWidgets.QLabel("This is a label")
    self.vtkWidget = QVTKRenderWindowInteractor(self.frame)

    #Create Source
    self.source = vtk.vtkCylinderSource()
    self.source.SetCenter(0, 0, 0)
    self.source.SetRadius(5.0)
    #Create Mapper
    self.mapper = vtk.vtkPolyDataMapper()
    self.mapper.SetInputConnection(self.source.GetOutputPort())
    #Create Actor
    self.actor = vtk.vtkActor()
    self.actor.SetMapper(self.mapper)

    #Create poke matrix for cylinder
    self.pMatrix = vtk.vtkMatrix4x4()

    self.vl.addWidget(self.vtkWidget)
    self.vl.addWidget(self.button)
    self.vl.addWidget(self.label)

    self.ren = vtk.vtkRenderer()
    self.ren.AddActor(self.actor)
    self.renWin = self.vtkWidget.GetRenderWindow()
    self.renWin.AddRenderer(self.ren)
    self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()

    #Settings
    self.ren.SetBackground(0.2, 0.2, 0.2)
    self.timeStep = 20 #ms
    self.total_t = 0

    #Inititalize Window, Interactor, Renderer, Layout
    self.frame.setLayout(self.vl)
    self.setCentralWidget(self.frame)
    self.ren.ResetCamera()
    self.show()
    self.iren.Initialize()

    # Create Timer
    self.timer = QtCore.QTimer()
    self.timer.timeout.connect(self.timerCallback)
    self.timer.start(self.timeStep)

def timerCallback(self, *args):
    self.total_t += self.timeStep / 1000
    #Rotate Cylinder
    angle = 2 * np.pi * self.total_t
    rotMatrix = np.array([[np.cos(angle), -np.sin(angle), 0],
                          [np.sin(angle), np.cos(angle), 0],
                          [0, 0, 1]])
    for i in range(3):
        for j in range(3):
            self.pMatrix.SetElement(i, j, rotMatrix[i, j])

    self.actor.PokeMatrix(self.pMatrix)
    self.ren.Render()


if __name__ == "__main__":
    app = Qt.QApplication(sys.argv)
    window = mainWindow()
    sys.exit(app.exec_())

在阅读 this file 的 paintEvent() 方法后,我设法发现,需要调用 Interactor 对象的 Render() 方法。因此,需要调用 self.iren.Render() 而不是 self.ren.Render()。然后一切正常。 完整示例代码:

import sys
import vtk
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import Qt
import numpy as np

from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor

class mainWindow(Qt.QMainWindow):
    def __init__(self, parent = None):
        Qt.QMainWindow.__init__(self, parent)

        self.frame = Qt.QFrame()
        self.vl = Qt.QVBoxLayout()
        self.button = QtWidgets.QPushButton("TestButton")
        self.label = QtWidgets.QLabel("This is a label")
        self.vtkWidget = QVTKRenderWindowInteractor(self.frame)

        #Create Source
        self.source = vtk.vtkCylinderSource()
        self.source.SetCenter(0, 0, 0)
        self.source.SetRadius(5.0)
        #Create Mapper
        self.mapper = vtk.vtkPolyDataMapper()
        self.mapper.SetInputConnection(self.source.GetOutputPort())
        #Create Actor
        self.actor = vtk.vtkActor()
        self.actor.SetMapper(self.mapper)

        #Create poke matrix for cylinder
        self.pMatrix = vtk.vtkMatrix4x4()

        self.vl.addWidget(self.vtkWidget)
        self.vl.addWidget(self.button)
        self.vl.addWidget(self.label)

        self.ren = vtk.vtkRenderer()
        self.ren.AddActor(self.actor)
        self.renWin = self.vtkWidget.GetRenderWindow()
        self.renWin.AddRenderer(self.ren)
        self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()

        #Settings
        self.ren.SetBackground(0.2, 0.2, 0.2)
        self.timeStep = 20 #ms
        self.total_t = 0

        #Inititalize Window, Interactor, Renderer, Layout
        self.frame.setLayout(self.vl)
        self.setCentralWidget(self.frame)
        self.ren.ResetCamera()
        self.show()
        self.iren.Initialize()

        # Create Timer
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.timerCallback)
        self.timer.start(self.timeStep)

    def timerCallback(self, *args):
        self.total_t += self.timeStep / 1000
        #Rotate Cylinder
        angle = 2 * np.pi * self.total_t
        rotMatrix = np.array([[np.cos(angle), -np.sin(angle), 0],
                              [np.sin(angle), np.cos(angle), 0],
                                  [0, 0, 1]])
        for i in range(3):
            for j in range(3):
                self.pMatrix.SetElement(i, j, rotMatrix[i, j])

        self.actor.PokeMatrix(self.pMatrix)
        self.iren.Render() #NOT: self.ren.Render()


if __name__ == "__main__":
    app = Qt.QApplication(sys.argv)
    window = mainWindow()
    sys.exit(app.exec_())

谢谢@cakelover,我遇到了同样的问题,但在 C++ 中,你的解决方案帮助我解决了它:

//PCLVisualizer pointer
pcl::visualization::PCLVisualizer::Ptr viewer_3D;

//Renderer method to update the visualizer
viewer_3D->getRenderWindow()->GetInteractor()->Render();