在 PyQT5 窗口中嵌入 VTK 对象

Posted

技术标签:

【中文标题】在 PyQT5 窗口中嵌入 VTK 对象【英文标题】:Embedding VTK object in PyQT5 window 【发布时间】:2018-06-14 19:06:42 【问题描述】:

我正在从事 3D 模型的衍生式设计项目。我需要创建一个简单的 QT 应用程序,该应用程序允许用户使用 VTK 查看网格,并包含一些用于反馈到生成算法的按钮。

GUI 对我来说是全新的东西,所以我很困惑如何将 here 的代码集成到更广泛的程序中。现在我只是想在查看器中创建一个按钮和一个 3D 圆锥体。

到目前为止,我的代码在运行时崩溃。它使用给定链接中的 QVTKRenderWindowInteractor() 对象,该对象直接粘贴到文件中。

尝试:
    导入系统
    进口vtk
    从 PyQt5.QtWidgets 导入 QWidget、QSizePolicy、QApplication、QPushButton、QVBoxLayout
    从 PyQt5.QtCore 导入 Qt、pyqtSignal、QTimer、QObject、QSize、QEvent
导入错误除外:
    raise ImportError("无法加载 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()

【问题讨论】:

【参考方案1】:

当您调用Start() 方法时,您正在启动事件循环,这意味着将不会执行以下指令。通常,您在完成 VTK 管道后启动事件循环,即在您定义您的演员、映射器等之后。

你在这里检查过这个例子吗? https://www.vtk.org/Wiki/VTK/Examples/Python/Widgets/EmbedPyQt

它工作正常,但假设你有 PyQt4。为了使用 PyQt5,我做了一些更改。试试这个:

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

重要提示:如果您的 qt 应用程序变得越来越复杂,并且您将在其中使用多个 QVTKRenderWindowInteractor 对象,请不要通过 Start() 方法调用交互器。否则,正如我之前提到的,您将在 qt 应用程序中创建另一个不必要的事件循环(app.exec() 启动 qt 循环)。在这种情况下,我认为您应该在声明了必要的对象后调用app.exec()。更多信息可以在这些链接中找到:

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

【讨论】:

非常非常非常感谢,您不仅节省了我的时间,还节省了我的几周时间。最好的问候 顺便说一句,应该是“from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor”而不是“from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor”

以上是关于在 PyQT5 窗口中嵌入 VTK 对象的主要内容,如果未能解决你的问题,请参考以下文章

无法在 pyqt5 中嵌入的 matplotlib 上绘制线条

PyQt5 常用窗口总结

在 pyqt5 的继承窗口上创建新组件

PyQt5的信号和槽

PySide2(PyQt5)根据屏幕大小初始化窗口大小

Matplotlib 将图形嵌入到 UI PyQt5