Fix cross-thread : queue + QTimer polling au lieu de signal
Thread Flask met les photos dans une queue.Queue(). QTimer(500ms) dans le thread principal Qt poll la queue et appelle le callback. Approche fiable et simple. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import queue
|
||||
from flask import Flask, request, jsonify, render_template_string
|
||||
from PyQt6.QtCore import QObject, pyqtSignal
|
||||
from PyQt6.QtCore import QObject, pyqtSignal, QTimer
|
||||
|
||||
UPLOAD_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "data", "photos")
|
||||
ALLOWED_EXTENSIONS = {"jpg", "jpeg", "png", "bmp", "tiff", "tif", "webp", "heic"}
|
||||
@@ -280,10 +281,16 @@ class UploadServer:
|
||||
self.port = port
|
||||
self.signals = UploadSignals()
|
||||
self._callback = None
|
||||
self._queue = queue.Queue()
|
||||
self.app = Flask(__name__)
|
||||
self._setup_routes()
|
||||
self._thread = None
|
||||
|
||||
# Timer Qt qui poll la queue depuis le thread principal
|
||||
self._poll_timer = QTimer()
|
||||
self._poll_timer.timeout.connect(self._poll_queue)
|
||||
self._poll_timer.start(500)
|
||||
|
||||
os.makedirs(UPLOAD_DIR, exist_ok=True)
|
||||
|
||||
def _setup_routes(self):
|
||||
@@ -309,11 +316,7 @@ class UploadServer:
|
||||
saved.append(path)
|
||||
|
||||
if saved:
|
||||
# QTimer.singleShot est thread-safe et exécute dans le thread principal
|
||||
from PyQt6.QtCore import QTimer
|
||||
from functools import partial
|
||||
if self._callback:
|
||||
QTimer.singleShot(0, partial(self._callback, saved))
|
||||
self._queue.put(saved)
|
||||
|
||||
return jsonify({"ok": True, "count": len(saved)})
|
||||
|
||||
@@ -321,6 +324,16 @@ class UploadServer:
|
||||
"""Définit le callback appelé quand des photos sont uploadées."""
|
||||
self._callback = callback
|
||||
|
||||
def _poll_queue(self):
|
||||
"""Appelé par QTimer dans le thread principal Qt."""
|
||||
while not self._queue.empty():
|
||||
try:
|
||||
photos = self._queue.get_nowait()
|
||||
if self._callback:
|
||||
self._callback(photos)
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
def start(self):
|
||||
"""Démarre le serveur dans un thread daemon."""
|
||||
self._thread = threading.Thread(
|
||||
|
||||
Reference in New Issue
Block a user