Anonymous
Открытие всплывающего окна при возникновении ошибки работника, работающего в Qthread, полностью зависает программа
Сообщение
Anonymous » 12 ноя 2025, 21:04
Я пытался создать небольшую программу на Python с графическим интерфейсом, используя Pyside6. Я столкнулся с проблемой при создании потока для выполнения задачи воркером (проверка файлов с определенным условием и последующее копирование их в другую папку).
Проблема в следующем: я хочу обрабатывать ошибки, исходящие от воркера, чтобы появлялось всплывающее окно для выхода из приложения. Однако, когда ошибка обнаружена и выдан сигнал, появляется всплывающее окно, но приложение полностью зависает, и мне приходится закрыть его вручную.
Вот соответствующий код (используется DualOutput, поэтому я могу видеть отпечатки в графическом интерфейсе; проблема сохраняется даже без него):
Код: Выделить всё
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from pathlib import Path
import sys
import transfer
import datetime
import os
import atexit
import traceback
class Ui_MainWindow(object):
@Slot()
def cancel(self,worker):
worker.stop()
def start_search_and_Copy(self):
self.plainTextEdit.clear()
# check if overwrite files or not
if self.checkBox.isChecked():
self.overwrite = True
else :
self.overwrite = False
# Thread + Worker
self.thread = QThread()
self.workers1 = Worker1(self.lineEdit.text(), self.lineEdit_3.text(), self.dateEdit.date(), self.overwrite)
self.workers1.moveToThread(self.thread)
self.workers1.finished.connect(lambda: self.setAllEnabled(True))
# Connect signals
self.thread.started.connect(self.workers1.run)
self.workers1.errorOccurred.connect(self.worker_error,type=Qt.QueuedConnection)
#self.workers1.finished.connect(self.test)
self.workers1.finished.connect(lambda: self.setAllEnabled(True))
self.workers1.finished.connect(self.thread.quit)
self.workers1.finished.connect(self.workers1.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
# Start thread
self.thread.start()
def worker_error(self, msg):
log_caught_exception(msg)
messageBox = QMessageBox()
messageBox.setWindowTitle("Error")
messageBox.setText("An error occurred:")
messageBox.setInformativeText(str(msg))
messageBox.setIcon(QMessageBox.Critical)
messageBox.setStandardButtons(QMessageBox.Ok)
messageBox.setWindowModality(Qt.ApplicationModal)
messageBox.exec()
messageBox.raise_()
messageBox.activateWindow()
QApplication.processEvents()
messageBox.buttonClicked.connect(lambda _: QApplication.instance().quit())
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(900, 7223)
self.actionSearch_Folder = QAction(MainWindow)
self.actionSearch_Folder.setObjectName(u"actionSearch_Folder")
self.actionSearch_Folder.setCheckable(False)
icon = QIcon(QIcon.fromTheme(u"folder"))
self.actionSearch_Folder.setIcon(icon)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.centralwidget.setMinimumSize(QSize(800, 549))
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.frame = QFrame(self.centralwidget)
self.frame.setObjectName(u"frame")
self.pushButton = QPushButton(self.frame)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(9, 63, 91, 24))
self.pushButton.clicked.connect(self.start_search_and_Copy)
self.pushButton.clicked.connect(lambda: self.setAllEnabled(False))
(...)
self.plainTextEdit = QPlainTextEdit(self.frame)
self.plainTextEdit.setObjectName(u"plainTextEdit")
self.plainTextEdit.setGeometry(QRect(10, 530, 861, 131))
self.plainTextEdit.setReadOnly(True)
dual_output = DualOutput(self.plainTextEdit)
sys.stdout = dual_output
sys.stderr = dual_output
sys.excepthook = log_uncaught_exceptions
(...)
self.lineEdit = QLineEdit(self.frame)
self.lineEdit.setObjectName(u"lineEdit")
self.lineEdit.setGeometry(QRect(48, 9, 311, 21))
self.lineEdit.textEdited.connect(self.path_change)
(...)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
(...)
# retranslateUi
class SearchMixin:
def search_files(self,date_lim, path):
filtered_files = []
(...)
return filtered_files
class Worker1(QObject, SearchMixin):
errorOccurred = Signal(object)
finished = Signal()
files = None
plainTextEdit = None
path = None
date_lim = None
destination = None
def __init__(self, path, destination, date_lim,overwrite):
super().__init__()
self.path = path
self.destination = destination
self.date_lim = date_lim
self._running = True
self.overwrite = overwrite
def run(self) -> None:
try:
(...)
filtered_files = self.search_files(self.date_lim, self.path)
if self._running:
if filtered_files:
self.files = filtered_files
total = len(self.files)
(...)
else :
print("No files")
i = 0
total=len(filtered_files)
for file in self.files: #
Подробнее здесь: [url]https://stackoverflow.com/questions/79818084/opening-a-pop-up-window-when-error-from-a-worker-running-in-qthread-occurs-compl[/url]
1762970657
Anonymous
Я пытался создать небольшую программу на Python с графическим интерфейсом, используя Pyside6. Я столкнулся с проблемой при создании потока для выполнения задачи воркером (проверка файлов с определенным условием и последующее копирование их в другую папку). Проблема в следующем: я хочу обрабатывать ошибки, исходящие от воркера, чтобы появлялось всплывающее окно для выхода из приложения. Однако, когда ошибка обнаружена и выдан сигнал, появляется всплывающее окно, но приложение полностью зависает, и мне приходится закрыть его вручную. Вот соответствующий код (используется DualOutput, поэтому я могу видеть отпечатки в графическом интерфейсе; проблема сохраняется даже без него): [code]from PySide6.QtCore import * from PySide6.QtGui import * from PySide6.QtWidgets import * from pathlib import Path import sys import transfer import datetime import os import atexit import traceback class Ui_MainWindow(object): @Slot() def cancel(self,worker): worker.stop() def start_search_and_Copy(self): self.plainTextEdit.clear() # check if overwrite files or not if self.checkBox.isChecked(): self.overwrite = True else : self.overwrite = False # Thread + Worker self.thread = QThread() self.workers1 = Worker1(self.lineEdit.text(), self.lineEdit_3.text(), self.dateEdit.date(), self.overwrite) self.workers1.moveToThread(self.thread) self.workers1.finished.connect(lambda: self.setAllEnabled(True)) # Connect signals self.thread.started.connect(self.workers1.run) self.workers1.errorOccurred.connect(self.worker_error,type=Qt.QueuedConnection) #self.workers1.finished.connect(self.test) self.workers1.finished.connect(lambda: self.setAllEnabled(True)) self.workers1.finished.connect(self.thread.quit) self.workers1.finished.connect(self.workers1.deleteLater) self.thread.finished.connect(self.thread.deleteLater) # Start thread self.thread.start() def worker_error(self, msg): log_caught_exception(msg) messageBox = QMessageBox() messageBox.setWindowTitle("Error") messageBox.setText("An error occurred:") messageBox.setInformativeText(str(msg)) messageBox.setIcon(QMessageBox.Critical) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setWindowModality(Qt.ApplicationModal) messageBox.exec() messageBox.raise_() messageBox.activateWindow() QApplication.processEvents() messageBox.buttonClicked.connect(lambda _: QApplication.instance().quit()) def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") MainWindow.resize(900, 7223) self.actionSearch_Folder = QAction(MainWindow) self.actionSearch_Folder.setObjectName(u"actionSearch_Folder") self.actionSearch_Folder.setCheckable(False) icon = QIcon(QIcon.fromTheme(u"folder")) self.actionSearch_Folder.setIcon(icon) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.centralwidget.setMinimumSize(QSize(800, 549)) self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(u"gridLayout") self.frame = QFrame(self.centralwidget) self.frame.setObjectName(u"frame") self.pushButton = QPushButton(self.frame) self.pushButton.setObjectName(u"pushButton") self.pushButton.setGeometry(QRect(9, 63, 91, 24)) self.pushButton.clicked.connect(self.start_search_and_Copy) self.pushButton.clicked.connect(lambda: self.setAllEnabled(False)) (...) self.plainTextEdit = QPlainTextEdit(self.frame) self.plainTextEdit.setObjectName(u"plainTextEdit") self.plainTextEdit.setGeometry(QRect(10, 530, 861, 131)) self.plainTextEdit.setReadOnly(True) dual_output = DualOutput(self.plainTextEdit) sys.stdout = dual_output sys.stderr = dual_output sys.excepthook = log_uncaught_exceptions (...) self.lineEdit = QLineEdit(self.frame) self.lineEdit.setObjectName(u"lineEdit") self.lineEdit.setGeometry(QRect(48, 9, 311, 21)) self.lineEdit.textEdited.connect(self.path_change) (...) self.retranslateUi(MainWindow) QMetaObject.connectSlotsByName(MainWindow) # setupUi def retranslateUi(self, MainWindow): (...) # retranslateUi class SearchMixin: def search_files(self,date_lim, path): filtered_files = [] (...) return filtered_files class Worker1(QObject, SearchMixin): errorOccurred = Signal(object) finished = Signal() files = None plainTextEdit = None path = None date_lim = None destination = None def __init__(self, path, destination, date_lim,overwrite): super().__init__() self.path = path self.destination = destination self.date_lim = date_lim self._running = True self.overwrite = overwrite def run(self) -> None: try: (...) filtered_files = self.search_files(self.date_lim, self.path) if self._running: if filtered_files: self.files = filtered_files total = len(self.files) (...) else : print("No files") i = 0 total=len(filtered_files) for file in self.files: # Подробнее здесь: [url]https://stackoverflow.com/questions/79818084/opening-a-pop-up-window-when-error-from-a-worker-running-in-qthread-occurs-compl[/url]