将 PyQt3D 窗口集成到 QMainWindow 中 [英] Integrating a PyQt3D window into a QMainWindow

查看:60
本文介绍了将 PyQt3D 窗口集成到 QMainWindow 中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We can use QWidget.createWindowContainer to add a 3D view into a QMainWindow (a window with menus, status bar, etc).

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

However, I found that this approach does not work, the windows opens up but fails to render the 3D contents.

它还显示错误

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

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

Here is a sample code that compares this approach with a native PyQt3D (that is not capable of using QWidgets to build a complete 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 视图添加到经典 QMainWindow 的任何想法?

Any ideas on how to correctly use QWidget.createWindowContainer for adding a 3D view to a classic QMainWindow ?

推荐答案

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

In Approach 1, your scene variable in View3D goes out of scope as soon as the __init__() method ends. It is then garbage collected by Python, leaving nothing to be displayed.

在方法 2 中,scene 在整个程序执行过程中都保持在范围内,所以没有问题.

In Approach 2, scene remains in scope throughout the execution of the program, so there's no problem.

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

I changed the three occurrences of scene in __init__() to self.scene, thereby keeping a reference to it. Approach 1 and Approach 2 now both work as expected.

方法一仍然报错

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

但它似乎不会引起问题.

but it doesn't seem to cause problems.

这篇关于将 PyQt3D 窗口集成到 QMainWindow 中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆