我们可以使用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/