Minimal working example of vtk embedding in PyQt.
- Contributed by Michka Popoff, inspired by the example from Eric E Monson
- See notes at the end for more details.
#!/usr/bin/env python import sys import vtk from PyQt4 import QtCore, QtGui from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor class MainWindow(QtGui.QMainWindow): def __init__(self, parent = None): QtGui.QMainWindow.__init__(self, parent) self.frame = QtGui.QFrame() self.vl = QtGui.QVBoxLayout() self.vtkWidget = QVTKRenderWindowInteractor(self.frame) self.vl.addWidget(self.vtkWidget) self.ren = vtk.vtkRenderer() self.vtkWidget.GetRenderWindow().AddRenderer(self.ren) self.iren = self.vtkWidget.GetRenderWindow().GetInteractor() # Create source source = vtk.vtkSphereSource() source.SetCenter(0, 0, 0) source.SetRadius(5.0) # Create a mapper mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(source.GetOutputPort()) # Create an actor actor = vtk.vtkActor() actor.SetMapper(mapper) self.ren.AddActor(actor) self.ren.ResetCamera() self.frame.setLayout(self.vl) self.setCentralWidget(self.frame) self.show() self.iren.Initialize() if __name__ == "__main__": app = QtGui.QApplication(sys.argv) window = MainWindow() sys.exit(app.exec_())
Here are some explanations about this example, in case you need more informations.
1) Why use a QFrame to embed vtk ?
QVTKRenderWindowInteractor can not be reparented. So it is not possible to put it directly in a QWidget. Some people had some trouble with this : http://public.kitware.com/pipermail/vtkusers/2009-October/054152.html
Some people did propose a fix to this by using a QtOpenGL.QGLWidget instead of a QtGui.QWidget as a parent class for the QVTKRenderWindowInteractor. You can read this ticket to see why this is not a good solution : http://vtk.org/Bug/view.php?id=13983
But as embedding is working really well with a QFrame, it's not really a problem.
2) Why not call Start() on the interactor ?
Sometimes you see examples with Start() called before Initialize(). For Qt (and PyQt), Start() will trigger the event loop, which in our case exec already does. So it's not needed. See (ref needed) this discussion to know more about this.
3) Why put show() inside the MainWindow class ?
If you do a GetRenderWindow().Render() call before the show(), this will lead to some errors, especially on Apple's OS X. In VTK 5.10.1 and 6.0.0 you would only get some odd invalid drawable errors, but since VTK 6.1 OpenGl errors are fetched and displayed.
There is a long explanation here : http://www.vtk.org/pipermail/vtk-developers/2013-July/014005.html So show() has to be called before any rendering.
See (ref needed) this discussion to know more about this.
TODO : ref needed = link to discussion "VTK OpenGL errors" on the vtk user list from the 01 nov 2013