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

QGIS多窗口应用退出触发QBasicTimer错误的排查求助

QGIS多窗口应用退出报错与窗口关闭方式疑问

问题描述

  • 开发QGIS多窗口应用时,每次退出都会弹出错误提示:QBasicTimer::start: QBasicTimer can only be used with threads started with QThread。尝试退出时关闭所有窗口,错误仍会出现,且错误行数随退出窗口不同而变化。
  • 咨询:通过表单按钮关闭窗口与点击窗口右上角叉号关闭是否存在区别?

原始代码

from qgis.core import *
from qgis.gui import *
import os
import sys

from PyQt5 import *

import mainSubSysWin_design

import mapAndCharWin
import mapAndCharWin_design

import compTechWin
import compTechWin_design

import locNetWin
import locNetWin_design


class mainSubSysWin (QtWidgets.QDialog, mainSubSysWin_design.Ui_Dialog) :
    
    def __init__(self):
        QtWidgets.QDialog.__init__(self)
        self.setupUi(self)

        self.compTechButt.clicked.connect(self.compTechWin)
        self.compTech_window = compTechWin.compTechWin()
        self.compTech_window.backToMainButt.clicked.connect(self.toMainWin)
        
        self.charLocalButt.clicked.connect(self.netWin)
        self.locNet_window = locNetWin.locNetWin()
        self.locNet_window.toMainButt.clicked.connect(self.toMainWin)

        
        self.mapButt.clicked.connect(self.mapChar)
        self.mapChar_window = mapAndCharWin.mapAndCharWin()
        self.mapChar_window.backMapButt.clicked.connect(self.toMainWin)
        


    def compTechWin(self):
        self.compTech_window.show()
        self.hide()

    def netWin(self):
        self.locNet_window.show()
        self.hide()

    def mapChar(self):
        self.mapChar_window.show()
        self.hide()

    def toMainWin(self):
        self.show()
        self.compTech_window.hide()
        self.mapChar_window.hide()
        self.locNet_window.hide()

    def closeWin(self):
        self.compTech_window.close()
        self.mapChar_window.close()
        self.locNet_window.close()
        self.close()
        
def main():
    QgsApplication.setPrefixPath("qgis-ltr-dev", True)
    qgs=QgsApplication([],True)
    QgsCredentials.instance()
    qgs.initQgis()    
    dir_path = os.path.dirname(os.path.realpath(__file__))
    QgsProject.instance().read(dir_path+'/NEWproject/qgis222.qgz')
    print("yep")
    main_app = QApplication(sys.argv)
    #main_app.aboutToQuit.connect(exitHandler())
    window = mainSubSysWin()
    window.show()
    sys.exit(main_app.exec_())
    exit_code = qgs.exec_()
    qgs.exitQgis()


if __name__ == '__main__':
    main()

修改后的main函数代码

def main():
    QgsApplication.setPrefixPath("qgis-ltr-dev", True)
    qgs=QgsApplication([],True)
    QgsCredentials.instance()
    qgs.initQgis()    
    dir_path = os.path.dirname(os.path.realpath(__file__))
    QgsProject.instance().read(dir_path+'/NEWproject/qgis222.qgz')
    print("yep")
    window = mainSubSysWin()
    window.show()
    sys.exit(qgs.exec_())

if __name__ == '__main__':
    main()

问题解决与说明

1. 退出报错的修复

原始代码中同时创建QApplication和QgsApplication是核心问题——QGIS应用必须以QgsApplication作为主应用实例,不能单独创建QApplication,否则会引发线程管理冲突,触发QBasicTimer错误。

修改后的代码已移除多余的QApplication,但还需补充资源清理逻辑:

  • 重写主窗口的closeEvent方法,确保子窗口先被正确关闭
  • 保证qgs.exitQgis()被执行,清理QGIS核心资源

调整后的完整关键代码示例:

class mainSubSysWin (QtWidgets.QDialog, mainSubSysWin_design.Ui_Dialog) :
    # 保留原有代码...
    
    def closeEvent(self, event):
        # 关闭所有子窗口
        self.compTech_window.close()
        self.mapChar_window.close()
        self.locNet_window.close()
        event.accept()

def main():
    QgsApplication.setPrefixPath("qgis-ltr-dev", True)
    qgs=QgsApplication([],True)
    QgsCredentials.instance()
    qgs.initQgis()    
    dir_path = os.path.dirname(os.path.realpath(__file__))
    QgsProject.instance().read(dir_path+'/NEWproject/qgis222.qgz')
    print("yep")
    window = mainSubSysWin()
    window.show()
    exit_code = qgs.exec_()
    qgs.exitQgis()
    sys.exit(exit_code)

if __name__ == '__main__':
    main()

额外注意:若子窗口类(如compTechWin)存在定时器或线程资源,需在其closeEvent中停止相关资源,避免残留。

2. 两种窗口关闭方式的区别

  • 点击右上角叉号:触发窗口的closeEvent事件,Qt按默认流程处理(如检查窗口是否可关闭、释放资源等),若为主窗口,还会触发应用的aboutToQuit信号。
  • 按钮调用close():同样触发closeEvent事件,但可在按钮点击槽函数中添加自定义逻辑(如保存数据、确认关闭)后再调用close();若直接调用hide()则仅隐藏窗口,不释放资源。

简言之:两种方式最终都会触发closeEvent,但按钮关闭可提前加入自定义逻辑,叉号是系统默认触发的关闭流程。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:17:31