PySide6线程结束后更新GUI时程序无响应崩溃求助
PySide6线程执行后更新GUI导致程序崩溃问题
问题描述
使用PySide6开发GUI程序,界面通过Qt Designer设计并单独存放。线程执行完成后尝试更新GUI时,程序无响应直接关闭,运行过程无报错信息。
主线程代码
class interact(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, *args, **kwargs): super(interact, self).__init__( *args, **kwargs) self.setupUi(self) self.scaleX = 800 self.scaleY = 800 self.index = 0 self.newIndex = 0 self.translatedFiles = [] self.files = [] self.isClicked = False self.upload.clicked.connect(self.upload1)#connecting button to self.upload1 self.upload.clicked.connect(self.change1) self.rightArrow.clicked.connect(self.moveRight) #button self.leftArrow.clicked.connect(self.moveLeft) #button self.translate.clicked.connect(self.translate1) #button self.translate.clicked.connect(self.change) def upload1(self): filenames, _ = QFileDialog.getOpenFileNames( None, "QFileDialog.getOpenFileNames()", "", "Image files (*.jpg *.png)" ) for file in filenames: self.files.append(file) self.showImage() def moveRight(self): if self.isClicked == True: if self.newIndex >= len(self.translatedFiles)-1: self.newIndex = len(self.translatedFiles)-1 else: self.newIndex += 1 else: if self.index >= len(self.files)-1: self.index = len(self.files)-1 else: self.index += 1 self.showImage() def moveLeft(self): if self.isClicked == True: if self.newIndex <= 0: self.newIndex = 0 else: self.newIndex -= 1 else: if self.index <= 0: self.index = 0 else: self.index -= 1 self.showImage() def showImage(self): if self.isClicked == True: if not self.translatedFiles: return im = self.translatedFiles[self.newIndex] im = im.convert("RGB") data = im.tobytes("raw","RGB") qim = QImage(data, im.size[0], im.size[1], QImage.Format_RGB888) pix = QPixmap(qim) self.Image.setPixmap(pix) print("change") else: if not self.files: return pix = QPixmap(self.files[self.index]) self.Image.setPixmap(pix) print(self.files[self.index]) print("KC") def afterThread(self, s): myarray = np.array(s) img = im.fromarray(myarray) self.translatedFiles.append(img) # 更新索引到最新添加的图片 self.newIndex = len(self.translatedFiles) - 1 print("THREAD COMPLETE!") def change(self): self.isClicked = True def change1(self): self.isClicked = False def translate1(self): self.thread = QThread() self.worker = Translate(self.files[self.index]) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.afterThread) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.thread.finished.connect(self.showImage) self.thread.start() if __name__ == "__main__": import sys app =QtWidgets.QApplication(sys.argv) w = interact() w.show() sys.exit(app.exec())
线程代码
import cv2 import numpy as np from PIL import Image import os import time from PySide6.QtCore import QObject, Signal from MangaOcr import MangaOcr import easyocr import ts # 假设这是翻译模块 class Translate(QObject): # 修正信号类型:传递numpy数组而非list finished = Signal(np.ndarray) def __init__(self, img_path): super(Translate, self).__init__() self.img_path = img_path self.mocr = MangaOcr() def chronos(func): def get_time(*args, **kawrgs): start = time.time() x = func(*args, **kawrgs) end = time.time() print("{} took {} seconds".format(func, (end-start))) return x return get_time @chronos def get_text(self, image): reader = easyocr.Reader(['ja'], gpu=False) result = reader.readtext(image, paragraph=True) myDict = {} for (bbox, text) in result: (tl, tr, br, bl) = bbox tl = (int(tl[0]), int(tl[1])) tr = (int(tr[0]), int(tr[1])) br = (int(br[0]), int(br[1])) bl = (int(bl[0]), int(bl[1])) myDict[str(bl)] = ([tl , br ]) return myDict @chronos def get_japanese(self, diction): newList = {} et = {} ts_dict = {} directory = os.path.join(os.getcwd(), 'MangaTranslation', 'cropText') os.makedirs(directory, exist_ok=True) # 确保目录存在 for x in diction: cropped_image = self.image[diction[x][0][1]:diction[x][1][1], diction[x][0][0]:diction[x][1][0]] save_path = os.path.join(directory, f"{x}.jpg") if not os.path.exists(save_path): cv2.imwrite(save_path, cropped_image) et[str(x)] = save_path # 只遍历当前目录的文件,避免递归遍历子目录 for x in os.listdir(directory): file_path = os.path.join(directory, x) if not os.path.isfile(file_path): continue try: img = Image.open(file_path.strip()) text = self.mocr(img) ts_dict[file_path.strip()] = text except Exception as e: print(f"处理图片失败: {e}") # 优化匹配逻辑,避免双重循环 for coor, direct in et.items(): if direct in ts_dict: newList[coor] = ts_dict[direct] return newList @chronos def translate(self, original): for jap in original: original[jap] = str(ts.bing(original[jap])) return original def segment(self, list1): for line in list1: chars = list(str(list1[line])) s = '' count = 0 for c in chars: if c == " ": count += 1 if count == 3: s += "\n" count = 0 else: s += c list1[line] = s return list1 def write(self, img, dict1, list1): fontSize = .5 # 复制原图像避免修改原始数据 image = img.copy() for value in dict1: cv2.rectangle(image, dict1[value][0], dict1[value][1], (0, 255, 255), 2) # 假设add_text_to_image是自定义函数,确保它返回修改后的图像 image = add_text_to_image( image, list1[value], font_color_rgb=(255, 0, 0), top_left_xy=(dict1[value][0][0], dict1[value][1][1]), font_scale= fontSize, font_face=cv2.FONT_HERSHEY_DUPLEX ) return image def run(self): # 将图片读取逻辑移到run方法,避免阻塞主线程 self.img1 = cv2.imread(self.img_path) self.image = cv2.cvtColor(self.img1, cv2.COLOR_BGR2RGB) gotten_text = self.get_text(self.image) finalText = self.get_japanese(gotten_text) newList = self.translate(finalText) addNewLine = self.segment(newList) final = self.write(self.image, gotten_text, addNewLine) self.finished.emit(final)
运行日志
<function Translate.get_text at 0x0000013C5D880B80> took 10.577515602111816 seconds <function Translate.get_japanese at 0x0000013C5DA03E50> took 6.2078752517700195 seconds <function Translate.translate at 0x0000013C5DA03EE0> took 8.287482023239136 seconds THREAD COMPLETE!
问题解决要点
修正信号类型不匹配:原代码中
finished信号定义为Signal(list),但实际发射的是numpy数组,类型不匹配会触发未捕获异常导致程序崩溃,改为Signal(np.ndarray)即可。将IO操作移到线程中:原
Translate类的__init__方法中直接读取图片,这部分代码会在主线程执行,可能阻塞GUI;将图片读取和转换逻辑移到run方法,确保在子线程中执行。添加空值判断:在
showImage方法中增加对translatedFiles和files的空值判断,避免索引越界错误。更新显示索引:线程完成后,将
newIndex设置为translatedFiles的最后一个元素索引,确保显示最新生成的翻译图片。优化文件处理逻辑:在
get_japanese方法中,使用os.makedirs确保目录存在,避免递归遍历子目录,优化匹配逻辑减少双重循环,同时添加异常捕获的具体信息便于调试。
内容的提问来源于stack exchange,提问作者Andrew Nketsiah
相关产品推荐
相关产品推荐

