pythonpyqtpyqt5vtkqvtkwidget

VTK and PyQt5 : How to refresh display after changing radius value with slider


I'm trying to write a python code with VTK and PyQt5 which display a VTK Sphere customizable by the user with sliders. The conception of the windows and the widgets is ok, the problem is when I change the value of the sphere radius with the sliders, the rendering windows need a click to update the view. I would like that the scene updates automatically when the slider has moved. I've tried some methods like .reinitialize() , .Update(), .CameraReset() but either it doesn't exist or either it doesn't work correctly

Here's the code :

    import sys
from PyQt5.QtWidgets import QApplication, QWidget, QSlider, QLCDNumber
from PyQt5.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox,
                             QMenu, QPushButton, QRadioButton, QVBoxLayout, QWidget, QSlider,QLineEdit,QLabel)
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import *
import vtk
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
from PyQt5 import Qt

def window():

   source = vtk.vtkSphereSource()
   source.SetCenter(0, 0, 0)
   source.SetRadius(5.0)

   app = QApplication(sys.argv)
   win = QWidget()

   Display_1 = QLCDNumber(3)
   Display_2 = QLCDNumber(3)
   Display_3 = QLCDNumber(3)

   Display_1.setSegmentStyle(QLCDNumber.Flat)
   Display_2.setSegmentStyle(QLCDNumber.Flat)
   Display_3.setSegmentStyle(QLCDNumber.Flat)

   Display_1.display(128)
   Display_2.display(128)
   Display_3.display(128)

   Slider_1 = QSlider(QtCore.Qt.Horizontal)
   Slider_1.setMinimum(0)
   Slider_1.setMaximum(255)
   Slider_1.setValue(128)
   Slider_1.valueChanged.connect(Display_1.display)
   Slider_1.valueChanged.connect(source.SetRadius)
   source.Update()
   source.Modified()




   Slider_2 = QSlider(QtCore.Qt.Horizontal)
   Slider_2.setMinimum(0)
   Slider_2.setMaximum(255)
   Slider_2.setValue(128)
   Slider_2.valueChanged.connect(Display_2.display)


   Slider_3 = QSlider(QtCore.Qt.Horizontal)
   Slider_3.setMinimum(0)
   Slider_3.setMaximum(255)
   Slider_3.setValue(128)
   Slider_3.valueChanged.connect(Display_3.display)

   label_1 = QLabel("Label_1")
   label_1.setAlignment(QtCore.Qt.AlignCenter)

   label_2 = QLabel("Label_2")
   label_2.setAlignment(QtCore.Qt.AlignCenter)

   label_3 = QLabel("Label_3")
   label_3.setAlignment(QtCore.Qt.AlignCenter)  

   vbox = QtWidgets.QVBoxLayout()


   vbox.addWidget(label_1)
   vbox.addWidget(Display_1)
   vbox.addWidget(Slider_1)

   vbox.addWidget(label_2)
   vbox.addWidget(Display_2)
   vbox.addWidget(Slider_2)

   vbox.addWidget(label_3)
   vbox.addWidget(Display_3)
   vbox.addWidget(Slider_3)

   vbox.addStretch()






   hbox = QtWidgets.QHBoxLayout()

   frame = QtWidgets.QFrame()
   frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
   frame.setFrameShape(QtWidgets.QFrame.StyledPanel) # Application de la forme
   frame.setFrameShadow(QtWidgets.QFrame.Raised) # application d'une ombre
   frame.setObjectName("frame") # Appellation du cadre

   #b3 = QtWidgets.QPushButton("Button3")
   #b4 = QtWidgets.QPushButton("Button4")
   hbox.addWidget(frame)
   hbox.addStretch()
   #hbox.addWidget(b4)

   vbox.addStretch()
   hbox.addLayout(vbox)
   win.setLayout(hbox)



   vtkWidget = QVTKRenderWindowInteractor(frame)
   vl = Qt.QVBoxLayout()
   vl.addWidget(vtkWidget)

   ren = vtk.vtkRenderer()
   vtkWidget.GetRenderWindow().AddRenderer(ren)
   iren = vtkWidget.GetRenderWindow().GetInteractor()



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

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

   ren.AddActor(actor)
   ren.ResetCamera()
   frame.setLayout(vl)
   #setCentralWidget(self.frame)
   #show()
   iren.Initialize()

   iren.Start()
   iren.Render()

   win.setWindowTitle("PyQt")
   win.resize(743, 430)
   win.show()
   sys.exit(app.exec_())




if __name__ == '__main__':
   window()

Thanks in advance !


Solution

  • I use reintialize on the render window interactor whenever I want to force it to update following a programmatic (non-interactive) change. In your case, since the slider is a part of the rest of your application and not interaction within the render window interactor itself, you'll need to call reinitialize to force it to update.

    Call iren.ReInitialize() (notice the capitalization). The documentation for the VTKRenderWindowInteractor is here:

    https://www.vtk.org/doc/release/7.1/html/classvtkRenderWindowInteractor.html

    This answer also appears as part of the comments associated with question:

    pyqt and VTK : problem to connect slider to vtk object