python - 将 PyQt3D 窗口集成到 QMainWindow

标签 python qt pyqt pyqt5

我们可以使用QWidget.createWindowContainer将 3D View 添加到 QMainWindow(带有菜单、状态栏等的窗口)。

但是,我发现这种方法不起作用,窗口打开但无法呈现 3D 内容。

它也显示错误

QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined

这是一个示例代码,将此方法与原生 PyQt3D(无法使用 QWidgets 构建完整的 UI)进行比较

from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QWidget, QPushButton, qApp, QLabel, QHBoxLayout, QVBoxLayout, QSplitter
from PyQt5.QtGui import QIcon, QPixmap, QPainter, QImage, QMatrix4x4, QQuaternion, QVector3D, QColor, QGuiApplication
from PyQt5.QtCore import QSize, Qt
import sys
from PyQt5.Qt3DCore import QEntity, QTransform, QAspectEngine
from PyQt5.Qt3DRender import QCamera, QCameraLens, QRenderAspect
from PyQt5.Qt3DInput import QInputAspect
from PyQt5.Qt3DExtras import QForwardRenderer, QPhongMaterial, QCylinderMesh, QSphereMesh, QTorusMesh, Qt3DWindow, QOrbitCameraController

class View3D(QWidget):
    def __init__(self):
        super(View3D, self).__init__()
        self.view = Qt3DWindow()
        self.container = self.createWindowContainer(self.view)

        vboxlayout = QHBoxLayout()
        vboxlayout.addWidget(self.container)
        self.setLayout(vboxlayout)

        scene = createScene()

        # Camera.
        initialiseCamera(self.view, scene)

        self.view.setRootEntity(scene)

def initialiseCamera(view, scene):
    # Camera.
    camera = view.camera()
    camera.lens().setPerspectiveProjection(45.0, 16.0 / 9.0, 0.1, 1000.0)
    camera.setPosition(QVector3D(0.0, 0.0, 40.0))
    camera.setViewCenter(QVector3D(0.0, 0.0, 0.0))

    # For camera controls.
    camController = QOrbitCameraController(scene)
    camController.setLinearSpeed(50.0)
    camController.setLookSpeed(180.0)
    camController.setCamera(camera)

def createScene():
    # Root entity.
    rootEntity = QEntity()

    # Material.
    material = QPhongMaterial(rootEntity)

    # Torus.
    torusEntity = QEntity(rootEntity)
    torusMesh = QTorusMesh()
    torusMesh.setRadius(5)
    torusMesh.setMinorRadius(1)
    torusMesh.setRings(100)
    torusMesh.setSlices(20)

    torusTransform = QTransform()
    torusTransform.setScale3D(QVector3D(1.5, 1.0, 0.5))
    torusTransform.setRotation(
            QQuaternion.fromAxisAndAngle(QVector3D(1.0, 0.0, 0.0), 45.0))

    torusEntity.addComponent(torusMesh)
    torusEntity.addComponent(torusTransform)
    torusEntity.addComponent(material)

    # Sphere.
    sphereEntity = QEntity(rootEntity)
    sphereMesh = QSphereMesh()
    sphereMesh.setRadius(3)

    sphereEntity.addComponent(sphereMesh)
    sphereEntity.addComponent(material)

    return rootEntity

class Application(QMainWindow):
    def __init__(self):
        super().__init__()
        #
        view3d = View3D()
        self.setCentralWidget(view3d)
        self.show()

# Approach 1 - Integrate Qt3DWindow into a QMainWindow
if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Application()
    sys.exit(app.exec_())

'''
# Approach 2 - A native Qt3DWindow
if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    view = Qt3DWindow()

    scene = createScene()
    initialiseCamera(view, scene)

    view.setRootEntity(scene)
    view.show()

    sys.exit(app.exec_())
'''

关于如何正确使用 QWidget.createWindowContainer 将 3D View 添加到经典 QMainWindow 的任何想法?

最佳答案

在方法 1 中,您在 View3D 中的 scene 变量在 __init__() 方法结束后立即超出范围。然后由 Python 进行垃圾回收,不留下任何可显示的内容。

在方法 2 中,场景 在整个程序执行过程中都保持在范围内,因此没有问题。

我将 __init__() 中出现的三个 scene 更改为 self.scene,从而保留对它的引用。方法 1 和方法 2 现在都按预期工作。

方法一还是报错

QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined

但它似乎不会引起问题。

关于python - 将 PyQt3D 窗口集成到 QMainWindow,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48262716/

相关文章:

python - 使用 PyQT Python 显示 EMG(肌电图)

python - Pyqt获取鼠标点击图片时的像素位置和值

python - 信息检索中的语言模型

python - Python 中的 Xpath 。获取语​​法错误 ("invalid predicate")

python - 如何将传输语法uid添加到数据集的filemeta

c++ - 如何将具有指针成员的非 QObject 类公开给 QML?

c++ - QNetworkProxy - 绕过某些地址

python - 如何生成此自定义字母数字序列?

c++ - 诺基亚qt sdk问题

c++ - 在Qt中从父节点中查找子节点