最近在一个项目中遇到pyqt5界面调用getOpenFileName后卡死闪退,以下是一些记录。
运行环境
python 3.10
pyqt5 5.15.11
pywinauto 0.6.9
项目介绍
项目中实现界面按钮选择本地软件,然后使用pywinauto库连接该软件,并获取该软件界面信息。
代码实现
1. ui文件转换后的py文件代码,界面中仅包含一个按钮
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(623, 468) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setObjectName("pushButton") self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 623, 23)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "PushButton"))
2. 连接软件线程
from PyQt5.QtCore import QThread, pyqtSignal import pywinauto class ConnectExeLogic(QThread): exe_status = pyqtSignal(bool) def __init__(self): super(ConnectExeLogic, self).__init__() self.exe_path = '' # 软件路径 self.exe_window = None def run(self): print(self.exe_path) try: self.exe_window = pywinauto.application.Application().connect(path=self.exe_path) except pywinauto.application.ProcessNotFoundError: self.exe_status.emit(False) else: self.exe_status.emit(True)
2. 界面初始化
from UI.test import Ui_MainWindow from Logic.ConnectExe import ConnectExeLogic from PyQt5 import QtWidgets class WindowMarkAssis(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(WindowMarkAssis, self).__init__(parent) self.setupUi(self) self.logic_connect_exe = ConnectExeLogic() self.pushButton.clicked.connect(lambda: self.start_connect_exe()) def start_connect_exe(self): exe_path = QtWidgets.QFileDialog.getOpenFileName(self, '选择软件', '', 'Exe (*.exe)')[0] if exe_path == '': self.statusbar.showMessage('未选择软件', 3000) return False self.logic_connect_exe.exe_path = exe_path self.logic_connect_exe.start()
问题描述
运行上述代码,通过点击按钮选择软件,界面会卡死然后闪退。
问题分析
在界面初始化文件中,导入了ConnectExeLogic类,在该类的文件中导入了pywinauto库。所以界面初始化完成就导入了pywinauto库,再点击按钮调用getOpenFileName则会导致界面卡死闪退。
问题解决
思路:在调用getOpenFileName后再导入pywinauto库连接软件
代码修改:在选择完软件后启动的连接线程中导入pywinauto库
from PyQt5.QtCore import QThread, pyqtSignal class ConnectExeLogic(QThread): exe_status = pyqtSignal(bool) def __init__(self): super(ConnectExeLogic, self).__init__() self.exe_path = '' # 分析软件路径 self.exe_window = None def run(self): print(self.exe_path) import pywinauto try: self.exe_window = pywinauto.application.Application().connect(path=self.exe_path) except pywinauto.application.ProcessNotFoundError: self.exe_status.emit(False) else: self.exe_status.emit(True)
经过如上修改后的项目代码,可实现项目要求,解决了界面卡死闪退问题。
进一步查看pywinauto库的源代码,发现界面卡死与库中几行代码相关,感兴趣的可以自行测试。