cakelover
cakelover

Reputation: 177

VTKWidget in Qt is not updated as expected

I would like to display a 3D-Animation in my Qt5-Gui. Everything works as expected, but unfortunately the scene is not getting updated when I don't interact with the vtkWidget. In other words: When I want to see the animation, I need to click continously with the mouse on the widget. I'd be greatful for any help.

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_())

Upvotes: 3

Views: 766

Answers (2)

surajj4837
surajj4837

Reputation: 61

Thanks @cakelover, I was facing same issue but in C++, your solution helped me resolve it:

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

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

Upvotes: 1

cakelover
cakelover

Reputation: 177

After reading the paintEvent()-Method of this file, I managed to find out, that one needs to call the Render()-Method of the Interactor-object. So instead of self.ren.Render() one needs to call self.iren.Render(). Then everything works. Complete example code:

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_())

Upvotes: 2

Related Questions