You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QMainWindow关闭时QWidget内部控件不显示问题求助

解决QMainWindow关闭时Loader窗口控件不显示的问题

问题根源

你的代码中,uploadFile是同步阻塞操作,在close_event里调用它时,主线程会被完全占用,无法处理Loader窗口的UI绘制事件,导致窗口弹出但内部控件无法渲染。

解决方案

把FTP上传操作放到子线程中执行,让主线程能继续处理UI更新。具体实现如下:

修改后的主窗口与Loader控件代码

import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel
from PySide6.QtGui import QFont
from PySide6.QtCore import Qt, QThread, Signal
import upload  # 导入你的上传模块

class UploadThread(QThread):
    # 定义信号,用于上传完成或出错时通知主线程
    upload_finished = Signal()
    upload_failed = Signal(str)

    def __init__(self, filename, index):
        super().__init__()
        self.filename = filename
        self.index = index

    def run(self):
        try:
            upload.uploadFile(self.filename, self.index)
            self.upload_finished.emit()
        except Exception as e:
            self.upload_failed.emit(str(e))

class Loader(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('ManagerBee - Loader') 
        self.resize(250, 130)
        self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowTitleHint)
        self.setAttribute(Qt.WA_DeleteOnClose)

        h1 = QFont()
        h1.setPointSize(9)
        h1.setBold(True)

        layout = QVBoxLayout(self)

        self.loaderText = QLabel("Auto Backup is in progress.<br/>System will close automatically.")
        self.loaderText.setFont(h1)
        self.loaderText.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.loaderText)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("My Main Window")
        # 示例初始化userData,实际根据你的业务逻辑赋值
        self.userData = ["123"]

    def closeEvent(self, event):
        # 先阻止窗口关闭,等待上传完成
        event.ignore()
        
        # 创建并显示Loader窗口
        self.closingLoader = Loader()
        self.closingLoader.show()

        # 创建上传线程并启动
        self.upload_thread = UploadThread('db.sqlite3', str(self.userData[0]))
        self.upload_thread.upload_finished.connect(self.on_upload_finished)
        self.upload_thread.upload_failed.connect(self.on_upload_failed)
        self.upload_thread.start()

    def on_upload_finished(self):
        # 上传完成,关闭Loader并真正关闭主窗口
        self.closingLoader.close()
        self.close()

    def on_upload_failed(self, error_msg):
        # 上传失败,关闭Loader并处理错误
        self.closingLoader.close()
        # 这里可替换为你的错误提示框逻辑
        print(f"上传失败: {error_msg}")
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()

修改后的FTP上传代码

import ftplib
import os
import shutil
import datetime
from alertbox import AlertBox
import db

FTP_HOST = "ftp.domain.com"
FTP_USER = "user@domain.com"
FTP_PASS = "iCQL^7;eIpbD"


def uploadFile(filename, index):
     try:
          ftp = ftplib.FTP(FTP_HOST, FTP_USER, FTP_PASS)
     except Exception as e:
          # 抛出异常让线程捕获
          raise Exception("无法连接网络:无互联网连接,自动备份失败") from e
     ftp.encoding = "utf-8"
     local_file = f"{index}_{filename}"
     shutil.copy(filename, local_file) 

     with open(local_file, "rb") as file:
          ftp.storbinary(f"STOR {local_file}", file)

     os.remove(local_file)
     ftp.quit()

# downloadFile代码保持不变,此处省略

关键修改点

  1. 新增UploadThread类,将上传逻辑移到子线程执行,避免阻塞主线程UI更新
  2. 在closeEvent中先忽略窗口关闭事件,启动线程后再显示Loader
  3. 通过线程信号通知主线程上传状态,完成后再关闭Loader和主窗口
  4. 修改uploadFile使其抛出异常,方便线程捕获并处理错误场景

内容的提问来源于stack exchange,提问作者Sayan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:34:57