Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedding VTK object in PyQT5 window

I'm working on a generative design project for 3D models. I need to create a simple QT application that allows the user to view meshes using VTK and includes a few buttons for feedback into the generation algorithms.

GUIs are something completely new to me so I'm quite stumped on how to integrate the code from here for a viewer into a wider program. For now I'm merely trying to create a single button and a 3D cone in the viewer.

My code so far crashes when run. It uses the QVTKRenderWindowInteractor() object from the link given, with the object directly pasted into the file.

try:
    import sys
    import vtk
    from PyQt5.QtWidgets import QWidget, QSizePolicy, QApplication, QPushButton, QVBoxLayout
    from PyQt5.QtCore import Qt, pyqtSignal, QTimer, QObject, QSize, QEvent
except ImportError:
    raise ImportError("Cannot load either PyQt5")

import vtk

class neuralDesignerApp(QWidget):
    def __init__(self):
        super(QWidget,self).__init__()
        self.initUI()

    def initUI(self):

        app = QApplication(['QVTKRenderWindowInteractor'])
        vtkWindow = QVTKRenderWindowInteractor(self)
        vtkWindow.Initialize()
        vtkWindow.Start()
        ren = vtk.vtkRenderer()
        vtkWindow.GetRenderWindow().AddRenderer(ren)

        cone = vtk.vtkConeSource()
        cone.SetResolution(8)

        coneMapper = vtk.vtkPolyDataMapper()
        coneMapper.SetInputConnection(cone.GetOutputPort())

        coneActor = vtk.vtkActor()
        coneActor.SetMapper(coneMapper)
        ren.AddActor(coneActor)

        btn1 = QPushButton("Button 1", self)

        vbox = QVBoxLayout()
        vbox.addWidget(vtkWindow)
        vbox.addWidget(btn1)

        self.setLayout(vbox)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Neural Designer')
        self.show()
like image 718
Harrison Rose Avatar asked Jan 29 '23 22:01

Harrison Rose


1 Answers

When you call the method Start() you are starting the event loop, which means that the following instructions will not be executed. Tipically you start the event loop after you completed the VTK pipeline, i.e, after you defined your actors, mappers, etc.

Have you checked this example here? https://www.vtk.org/Wiki/VTK/Examples/Python/Widgets/EmbedPyQt

It works fine, but assumes that you have PyQt4. In order to work with PyQt5, I made a few changes. Try this:

import sys
import vtk
from PyQt5 import QtCore, QtGui
from PyQt5 import Qt

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.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()
        self.iren.Start()


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

Important note: if your qt application becomes increasingly complex and you will be using multiple QVTKRenderWindowInteractor objects in it, do not call the interactor through the Start() method. Otherwise, as I mentioned before, you are creating another unnecessary event loop inside your qt application (app.exec() starts the qt loop). In this case, I think you should call app.exec() after you declared you necessary objects. More information can be found in these links:

  • https://www.vtk.org/doc/nightly/html/classQVTKInteractor.html#details
  • https://www.vtk.org/pipermail/vtkusers/2009-February/050560.html
  • https://public.kitware.com/pipermail/vtkusers/2006-July/036328.html
like image 178
MrPedru22 Avatar answered Feb 03 '23 21:02

MrPedru22