aboutsummaryrefslogtreecommitdiffstats
path: root/examples/opengl
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2023-09-12 14:45:19 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2023-09-19 13:20:41 +0200
commiteec936657938e1c19ab70c562fc5eff5e1cec4b9 (patch)
treec999adab353b7167560858ba92807e6bf0045fae /examples/opengl
parentfb2ecf5e8577353c2317c7e103d11c52d473d024 (diff)
Add multiwindow functionality from the C++ example
Pick-to: 6.6 Task-number: PYSIDE-2460 Task-number: PYSIDE-2206 Change-Id: I6644e098c15885271bd4bc1188ae44e6c984b369 Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
Diffstat (limited to 'examples/opengl')
-rw-r--r--examples/opengl/hellogl2/doc/hellogl2.rst14
-rw-r--r--examples/opengl/hellogl2/hellogl2.pyproject2
-rw-r--r--examples/opengl/hellogl2/main.py5
-rw-r--r--examples/opengl/hellogl2/mainwindow.py29
-rw-r--r--examples/opengl/hellogl2/window.py73
5 files changed, 110 insertions, 13 deletions
diff --git a/examples/opengl/hellogl2/doc/hellogl2.rst b/examples/opengl/hellogl2/doc/hellogl2.rst
index 1223e138c..3471ebf30 100644
--- a/examples/opengl/hellogl2/doc/hellogl2.rst
+++ b/examples/opengl/hellogl2/doc/hellogl2.rst
@@ -4,6 +4,20 @@ Hello GL2 Example
The Hello GL2 example demonstrates the basic use of the OpenGL-related classes
provided with Qt.
+In this example the widget's corresponding top-level window can change several
+times during the widget's lifetime. Whenever this happens, the QOpenGLWidget's
+associated context is destroyed and a new one is created, requiring us to clean
+up the GL resources.
+
+The equivalent C++ example does this cleanup on emission of the
+QOpenGLContext.aboutToBeDestroyed() signal. However, in Qt for Python, we
+cannot rely on this signal when it is emitted from the destructor.
+
+Therefore, we do the cleanup in GLWidget.hideEvent().
+
+This will be followed by an invocation of initializeGL() where we can recreate
+all resources.
+
.. image:: hellogl2.png
:width: 400
:alt: Hello GL2 Screenshot
diff --git a/examples/opengl/hellogl2/hellogl2.pyproject b/examples/opengl/hellogl2/hellogl2.pyproject
index c9cd23c97..d85a139e4 100644
--- a/examples/opengl/hellogl2/hellogl2.pyproject
+++ b/examples/opengl/hellogl2/hellogl2.pyproject
@@ -1,3 +1,3 @@
{
- "files": ["main.py", "glwidget.py", "logo.py", "window.py"]
+ "files": ["main.py", "glwidget.py", "logo.py", "mainwindow.py", "window.py"]
}
diff --git a/examples/opengl/hellogl2/main.py b/examples/opengl/hellogl2/main.py
index ea35c0077..c7eb78a82 100644
--- a/examples/opengl/hellogl2/main.py
+++ b/examples/opengl/hellogl2/main.py
@@ -12,7 +12,7 @@ from PySide6.QtWidgets import (QApplication, QMessageBox)
try:
- from window import Window
+ from mainwindow import MainWindow
from glwidget import GLWidget
except ImportError:
app = QApplication(sys.argv)
@@ -47,12 +47,11 @@ if __name__ == '__main__':
GLWidget.set_transparent(options.transparent)
- main_window = Window()
+ main_window = MainWindow()
if options.transparent:
main_window.setAttribute(Qt.WA_TranslucentBackground)
main_window.setAttribute(Qt.WA_NoSystemBackground, False)
- main_window.resize(main_window.sizeHint())
main_window.show()
res = app.exec()
diff --git a/examples/opengl/hellogl2/mainwindow.py b/examples/opengl/hellogl2/mainwindow.py
new file mode 100644
index 000000000..d19053a26
--- /dev/null
+++ b/examples/opengl/hellogl2/mainwindow.py
@@ -0,0 +1,29 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+from PySide6.QtCore import Slot, Qt
+from PySide6.QtGui import QKeySequence
+from PySide6.QtWidgets import QMainWindow, QMessageBox
+
+from window import Window
+
+
+class MainWindow(QMainWindow):
+
+ def __init__(self):
+ super().__init__()
+ menuWindow = self.menuBar().addMenu("Window")
+ menuWindow.addAction("Add new", QKeySequence(Qt.CTRL | Qt.Key_N),
+ self.onAddNew)
+ menuWindow.addAction("Quit", QKeySequence(Qt.CTRL | Qt.Key_Q),
+ qApp.closeAllWindows)
+
+ self.onAddNew()
+
+ @Slot()
+ def onAddNew(self):
+ if not self.centralWidget():
+ self.setCentralWidget(Window(self))
+ else:
+ QMessageBox.information(self, "Cannot Add Window()",
+ "Already occupied. Undock first.")
diff --git a/examples/opengl/hellogl2/window.py b/examples/opengl/hellogl2/window.py
index 0d38fc490..c7b9946e0 100644
--- a/examples/opengl/hellogl2/window.py
+++ b/examples/opengl/hellogl2/window.py
@@ -2,15 +2,28 @@
# Copyright (C) 2013 Riverbank Computing Limited.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-from PySide6.QtCore import Qt
-from PySide6.QtWidgets import (QHBoxLayout, QSlider, QWidget)
+from PySide6.QtCore import Slot, Qt
+from PySide6.QtGui import QGuiApplication
+from PySide6.QtWidgets import (QApplication, QHBoxLayout, QMainWindow,
+ QMessageBox, QPushButton, QSlider,
+ QVBoxLayout, QWidget)
from glwidget import GLWidget
+def _main_window():
+ for t in qApp.topLevelWidgets():
+ if isinstance(t, QMainWindow):
+ return t
+ return None
+
+
class Window(QWidget):
+ instances = [] # Keep references when undocked
+
def __init__(self, parent=None):
super().__init__(parent)
+ self.instances.append(self)
self._gl_widget = GLWidget()
@@ -26,12 +39,18 @@ class Window(QWidget):
self._z_slider.valueChanged.connect(self._gl_widget.set_zrotation)
self._gl_widget.z_rotation_changed.connect(self._z_slider.setValue)
- main_layout = QHBoxLayout()
- main_layout.addWidget(self._gl_widget)
- main_layout.addWidget(self._x_slider)
- main_layout.addWidget(self._y_slider)
- main_layout.addWidget(self._z_slider)
- self.setLayout(main_layout)
+ mainLayout = QVBoxLayout(self)
+ w = QWidget()
+ container = QHBoxLayout(w)
+ container.addWidget(self._gl_widget)
+ container.addWidget(self._x_slider)
+ container.addWidget(self._y_slider)
+ container.addWidget(self._z_slider)
+
+ mainLayout.addWidget(w)
+ self._dock_btn = QPushButton("Undock")
+ self._dock_btn.clicked.connect(self.dock_undock)
+ mainLayout.addWidget(self._dock_btn)
self._x_slider.setValue(15 * 16)
self._y_slider.setValue(345 * 16)
@@ -49,8 +68,44 @@ class Window(QWidget):
slider.setTickPosition(QSlider.TicksRight)
return slider
+ def closeEvent(self, event):
+ self.instances.remove(self)
+ event.accept()
+
def keyPressEvent(self, event):
- if event.key() == Qt.Key_Escape:
+ if self.isWindow() and event.key() == Qt.Key_Escape:
self.close()
else:
super().keyPressEvent(event)
+
+ @Slot()
+ def dock_undock(self):
+ if self.parent():
+ self.undock()
+ else:
+ self.dock()
+
+ def dock(self):
+ mainWindow = _main_window()
+ if not mainWindow or not mainWindow.isVisible():
+ QMessageBox.information(self, "Cannot Dock",
+ "Main window already closed")
+ return
+ if mainWindow.centralWidget():
+ QMessageBox.information(self, "Cannot Dock",
+ "Main window already occupied")
+ return
+
+ self.setAttribute(Qt.WA_DeleteOnClose, False)
+ self._dock_btn.setText("Undock")
+ mainWindow.setCentralWidget(self)
+
+ def undock(self):
+ self.setParent(None)
+ self.setAttribute(Qt.WA_DeleteOnClose)
+ geometry = self.screen().availableGeometry()
+ x = geometry.x() + (geometry.width() - self.width()) / 2
+ y = geometry.y() + (geometry.height() - self.height()) / 2
+ self.move(x, y)
+ self._dock_btn.setText("Dock")
+ self.show()