diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/graphs/2d/graphsaudio/GraphsAudio/Main.qml | 50 | ||||
-rw-r--r-- | examples/graphs/2d/graphsaudio/GraphsAudio/qmldir | 2 | ||||
-rw-r--r-- | examples/graphs/2d/graphsaudio/doc/graphsaudio.rst | 8 | ||||
-rw-r--r-- | examples/graphs/2d/graphsaudio/doc/graphsaudio.webp | bin | 0 -> 12908 bytes | |||
-rw-r--r-- | examples/graphs/2d/graphsaudio/graphsaudio.pyproject | 3 | ||||
-rw-r--r-- | examples/graphs/2d/graphsaudio/main.py | 80 | ||||
-rw-r--r-- | examples/xml/dombookmarks/dombookmarks.py | 20 |
7 files changed, 153 insertions, 10 deletions
diff --git a/examples/graphs/2d/graphsaudio/GraphsAudio/Main.qml b/examples/graphs/2d/graphsaudio/GraphsAudio/Main.qml new file mode 100644 index 000000000..51bf3ef12 --- /dev/null +++ b/examples/graphs/2d/graphsaudio/GraphsAudio/Main.qml @@ -0,0 +1,50 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import QtQuick +import QtQuick.Controls +import QtGraphs + +ApplicationWindow { + visible: true + width: 1000 + height: 800 + title: "Data from the microphone (" + device_name + ")" + + GraphsView { + id: graph + anchors.fill: parent + + LineSeries { + id: audio_series + width: 2 + color: "#007acc" + } + + axisX: ValueAxis { + min: 0 + max: 2000 + tickInterval : 500 + labelFormat: "%g" + titleText: "Samples" + } + + axisY: ValueAxis { + min: -1 + max: 1 + tickInterval : 0.5 + labelFormat: "%0.1f" + titleText: "Audio level" + } + } + + Connections { + target: audio_bridge + function onDataUpdated(buffer) { + audio_series.clear() + for (let i = 0; i < buffer.length; ++i) { + audio_series.append(buffer[i]) + } + } + } +} diff --git a/examples/graphs/2d/graphsaudio/GraphsAudio/qmldir b/examples/graphs/2d/graphsaudio/GraphsAudio/qmldir new file mode 100644 index 000000000..cc5408a66 --- /dev/null +++ b/examples/graphs/2d/graphsaudio/GraphsAudio/qmldir @@ -0,0 +1,2 @@ +module GraphsAudio +Main 1.0 Main.qml diff --git a/examples/graphs/2d/graphsaudio/doc/graphsaudio.rst b/examples/graphs/2d/graphsaudio/doc/graphsaudio.rst new file mode 100644 index 000000000..f19b28caf --- /dev/null +++ b/examples/graphs/2d/graphsaudio/doc/graphsaudio.rst @@ -0,0 +1,8 @@ +GraphsAudio Example +=================== + +This example shows the drawing of dynamic data (microphone input) using QtGraphs and Qml. + +.. image:: graphsaudio.webp + :width: 400 + :alt: GraphsAudio Screenshot diff --git a/examples/graphs/2d/graphsaudio/doc/graphsaudio.webp b/examples/graphs/2d/graphsaudio/doc/graphsaudio.webp Binary files differnew file mode 100644 index 000000000..bb57b18e5 --- /dev/null +++ b/examples/graphs/2d/graphsaudio/doc/graphsaudio.webp diff --git a/examples/graphs/2d/graphsaudio/graphsaudio.pyproject b/examples/graphs/2d/graphsaudio/graphsaudio.pyproject new file mode 100644 index 000000000..eff791919 --- /dev/null +++ b/examples/graphs/2d/graphsaudio/graphsaudio.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["main.py", "GraphsAudio/Main.qml", "GraphsAudio/qmldir"] +} diff --git a/examples/graphs/2d/graphsaudio/main.py b/examples/graphs/2d/graphsaudio/main.py new file mode 100644 index 000000000..239aee036 --- /dev/null +++ b/examples/graphs/2d/graphsaudio/main.py @@ -0,0 +1,80 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +from __future__ import annotations + +import sys +from pathlib import Path +from PySide6.QtCore import QObject, QPointF, Slot, Signal +from PySide6.QtMultimedia import QAudioFormat, QAudioSource, QMediaDevices +from PySide6.QtWidgets import QMessageBox +from PySide6.QtQml import QQmlApplicationEngine +from PySide6.QtGui import QGuiApplication + + +SAMPLE_COUNT = 2000 +RESOLUTION = 4 + + +class Audio(QObject): + dataUpdated = Signal(list) + + def __init__(self, device): + super().__init__() + + format_audio = QAudioFormat() + format_audio.setSampleRate(8000) + format_audio.setChannelCount(1) + format_audio.setSampleFormat(QAudioFormat.UInt8) + + self.device_name = device.description() + + self._audio_input = QAudioSource(device, format_audio, self) + self._io_device = self._audio_input.start() + self._io_device.readyRead.connect(self._readyRead) + + self._buffer = [QPointF(x, 0) for x in range(SAMPLE_COUNT)] + + def closeEvent(self, event): + if self._audio_input is not None: + self._audio_input.stop() + event.accept() + + @Slot() + def _readyRead(self): + data = self._io_device.readAll() + available_samples = data.size() // RESOLUTION + start = 0 + if (available_samples < SAMPLE_COUNT): + start = SAMPLE_COUNT - available_samples + for s in range(start): + self._buffer[s].setY(self._buffer[s + available_samples].y()) + + data_index = 0 + for s in range(start, SAMPLE_COUNT): + value = (ord(data[data_index]) - 128) / 128 + self._buffer[s].setY(value) + data_index = data_index + RESOLUTION + + self.dataUpdated.emit(self._buffer) + + +if __name__ == '__main__': + app = QGuiApplication(sys.argv) + engine = QQmlApplicationEngine() + + input_devices = QMediaDevices.audioInputs() + if not input_devices: + QMessageBox.warning(None, "audio", "There is no audio input device available.") + sys.exit(-1) + + audio_bridge = Audio(input_devices[0]) + engine.rootContext().setContextProperty("audio_bridge", audio_bridge) + + device = input_devices[0] + device_name = device.description() + engine.rootContext().setContextProperty("device_name", device_name) + + engine.addImportPath(Path(__file__).parent) + engine.loadFromModule("GraphsAudio", "Main") + + sys.exit(app.exec()) diff --git a/examples/xml/dombookmarks/dombookmarks.py b/examples/xml/dombookmarks/dombookmarks.py index f5afdeef8..f02251849 100644 --- a/examples/xml/dombookmarks/dombookmarks.py +++ b/examples/xml/dombookmarks/dombookmarks.py @@ -7,7 +7,7 @@ from __future__ import annotations import sys -from PySide6.QtCore import QDir, QFile, Qt, QTextStream +from PySide6.QtCore import QDir, QFile, QObject, Qt, QTextStream from PySide6.QtGui import QAction, QIcon, QKeySequence from PySide6.QtWidgets import (QApplication, QFileDialog, QHeaderView, QMainWindow, QMessageBox, QStyle, QTreeWidget, @@ -93,6 +93,7 @@ class XbelTree(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) + self._update_conn_id = None self.header().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) self.setHeaderLabels(("Title", "Location")) @@ -111,11 +112,12 @@ class XbelTree(QTreeWidget): self._bookmark_icon.addPixmap(style.standardPixmap(QStyle.StandardPixmap.SP_FileIcon)) def read(self, device): - ok, errorStr, errorLine, errorColumn = self._dom_document.setContent(device, True) - if not ok: + result = self._dom_document.setContent(device, + QDomDocument.ParseOption.UseNamespaceProcessing) + if not result: QMessageBox.information(self.window(), "DOM Bookmarks", - f"Parse error at line {errorLine}, " - f"column {errorColumn}:\n{errorStr}") + f"Parse error at line {result.errorLine}, " + f"column {result.errorColumn}:\n{result.errorMessage}") return False root = self._dom_document.documentElement() @@ -131,17 +133,15 @@ class XbelTree(QTreeWidget): self.clear() # It might not be connected. - try: - self.itemChanged.disconnect(self.update_dom_element) - except RuntimeError: - pass + if self._update_conn_id: + QObject.disconnect(self._update_conn_id) child = root.firstChildElement('folder') while not child.isNull(): self.parse_folder_element(child) child = child.nextSiblingElement('folder') - self.itemChanged.connect(self.update_dom_element) + self._update_conn_id = self.itemChanged.connect(self.update_dom_element) return True |