Issue with Multiple QML Engines and Signal-Slot Connections
-
Hi everyone,
I'm encountering an issue with my Qt6/PySide6 application where I'm using multiple QML engines to display content on multiple screens. I'm trying to achieve independent video playback on each screen, but I'm running into a problem where the same video plays on all displays despite setting different sources.
Here's a simplified overview of my application structure:
main py: Creates a QApplication and multiple QQmlApplicationEngine instances, one for each connected display.
NetworkManager: Handles network requests to fetch media information from a server.
MediaManager: Processes the server response, downloads media files, and updates a configuration file with media paths for each screen.
main.qml: Contains the UI elements, including a Video object for video playback.
Initial Approach (Problem):
Initially, I had a single instance of MediaManager that was shared across all QML engines. The NetworkManager would emit a requestFinished signal with the server response, and the MediaManager would handle the response, download the media, and update the configuration. However, this resulted in the same video being played on all displays because the mediaReady signal (emitted by MediaManager) was received by all QML engines.Modified Approach:
To address this, I modified the main.py to create a separate instance of MediaManager for each QML engine within the loop that creates the engines. This ensures that each display has its own independent media manager and configuration.Here's a snippet of the relevant code:
Before (Single MediaManager):
class DisplayApp(QApplication): def __init__(self, argv): # ... self.media_manager = MediaManager() # Single instance # ... for index, screen in enumerate(self.screens()): engine = QQmlApplicationEngine() # ... engine.rootContext().setContextProperty("mediaManager", self.media_manager) # Shared instance # ... self.network_manager.requestFinished.connect(self.media_manager.save_media_info) # ...
After (Separate MediaManager Instances):
class DisplayApp(QApplication): def __init__(self, argv): # ... for index, screen in enumerate(self.screens()): engine = QQmlApplicationEngine() # ... media_manager = MediaManager() # Separate instance for each engine engine.rootContext().setContextProperty("mediaManager", media_manager) # ... self.network_manager.requestFinished.connect(media_manager.save_media_info) # ...
However, after making this change, the signal emission seems to have stopped working. The MediaManager methods are no longer being triggered, and video playback functionality is not working as expected.
I've verified that:
The file paths are correct and include the file:// scheme.The signal-slot connections are established for each individual MediaManager instance within the loop in main.py.
The context property names match between main . py and the QML code.
Despite these checks, the signal emission issue persists. I would be grateful for any insights or suggestions on what might be causing this problem and how to further debug it.
Thank you!
Here is the simplified version of my code.
My network_manager.py which works and emits the signal which is not working anymore:from PySide6.QtCore import QObject, Signal from PySide6.QtNetwork import QNetworkAccessManager class NetworkManager(QObject): requestFinished = Signal(str) def __init__(self): super().__init__() self.manager = QNetworkAccessManager() self.manager.finished.connect(self.handle_response) def submit_pin(self, pin, screen_index): # (URL construction omitted for privacy) request = QNetworkRequest(QUrl(url)) self.manager.get(request) # Send the request def handle_response(self): reply = self.sender() if not isinstance(reply, QNetworkReply): return if reply.error() != QNetworkReply.NoError: print("Network Error:", reply.errorString()) self.requestFinished.emit("Error") else: response_data = reply.readAll().data().decode("utf-8") print("Server Response:", response_data) self.requestFinished.emit(response_data) reply.deleteLater()
and my media_manager.py:
import json import os from PySide6.QtCore import QObject, Slot, Signal from PySide6.QtNetwork import QNetworkAccessManager class MediaManager(QObject): mediaSaved = Signal(bool) mediaReady = Signal(str) def __init__(self): super().__init__() self.manager = QNetworkAccessManager(self) self.config_file = "autoload.cfg" self.media_folder = "media" # ... (folder creation) ... @Slot(str) def save_media_info(self, response_data): # ... (JSON parsing and PIN/screenIndex extraction) ... # ... (filename generation and file_path construction) ... self.download_media(media_url, file_path) # ... (update config file) ... self.mediaSaved.emit(True) def download_media(self, url, file_path): request = QNetworkRequest(QUrl(url)) reply = self.manager.get(request) reply.finished.connect(lambda: self.handle_download_finished(reply, file_path)) def handle_download_finished(self, reply, file_path): # ... (download handling and mediaReady emission) ...
-
Hi,
One thing to test: keep a reference of your MediaManager objects in your application class. I am currently wondering whether the Python garbage collection is at work with your issue.