openTARS / app /tars_qt /fio.py
ProjectOpenTARS4's picture
Mirror of openTARS 5.2 Ranger (revision 2026110101)
2695555 verified
Raw History Blame Contribute Delete
1.91 kB
"""Entrega, na thread da janela, o que as threads de trabalho querem mostrar.
Emitir um sinal do Qt de uma thread comum do Python cria uma c贸pia do argumento (dict, lista, objeto) FORA da thread
dona do objeto; com algumas vers玫es do PySide6 isso corrompe a mem贸ria e o app cai em pontos aleat贸rios (em `stat`,
em `readinto`...). Aqui as threads s贸 colocam o trabalho numa fila do Python, e um QTimer da thread da janela o executa:
nenhum objeto do Qt 茅 tocado fora da thread dele."""
import queue
import sys
import threading
from PySide6.QtCore import QObject, QTimer
_fila = queue.SimpleQueue()
_relogio = None
_PRINCIPAL = threading.main_thread()
def _drenar():
for _ in range(500): # um lote por tique: a janela n茫o engasga com uma enxurrada
try:
funcao, args = _fila.get_nowait()
except queue.Empty:
return
try:
funcao(*args)
except RuntimeError: # o objeto C++ j谩 foi destru铆do (janela fechando)
pass
except Exception:
import traceback
traceback.print_exc(file=sys.__stderr__)
def iniciar(pai=None):
"""Liga o rel贸gio que esvazia a fila. Chamar uma vez, na thread da janela, depois de criar o QApplication."""
global _relogio
if _relogio is None:
_relogio = QTimer(pai if isinstance(pai, QObject) else None)
_relogio.setInterval(10)
_relogio.timeout.connect(_drenar)
_relogio.start()
return _relogio
def no_principal(funcao, *args):
"""Roda `funcao(*args)` na thread da janela (j谩, se for ela quem chama)."""
if threading.current_thread() is _PRINCIPAL and _relogio is not None:
funcao(*args)
else:
_fila.put((funcao, args))
def emitir(sinal, *args):
"""sinal.emit(*args), mas sempre na thread da janela."""
no_principal(sinal.emit, *args)