diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-09-12 14:45:19 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-09-19 13:20:41 +0200 |
commit | eec936657938e1c19ab70c562fc5eff5e1cec4b9 (patch) | |
tree | c999adab353b7167560858ba92807e6bf0045fae /examples/opengl | |
parent | fb2ecf5e8577353c2317c7e103d11c52d473d024 (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.rst | 14 | ||||
-rw-r--r-- | examples/opengl/hellogl2/hellogl2.pyproject | 2 | ||||
-rw-r--r-- | examples/opengl/hellogl2/main.py | 5 | ||||
-rw-r--r-- | examples/opengl/hellogl2/mainwindow.py | 29 | ||||
-rw-r--r-- | examples/opengl/hellogl2/window.py | 73 |
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() |