PyInstaller打包Tkinter多进程程序时弹出重复主窗口而非Ping窗口
带颜色标识的Ping应用打包后进程异常问题
- 开发的Ping应用具备颜色标识功能:Ping响应失败时窗口显示红色,成功则显示绿色
- 程序分为两个文件:
main_window.py:主窗口代码,包含URL输入框、Ping参数输入框和启动按钮ping_window.py:Ping窗口代码,负责执行Ping逻辑并更新窗口颜色
- 运行逻辑:点击主窗口的启动按钮,会创建继承自
multiprocessing.Process的NewProcessPingWindow实例,其run()方法启动独立Ping窗口;Ping逻辑放在线程中执行,避免UI冻结 - 异常现象:在PyCharm中运行正常,但使用
pyinstaller --onefile main_window.py打包成exe后,点击按钮无法打开Ping窗口,反而生成主窗口副本,原窗口冻结,问题可重复触发 - 已尝试的排查:添加了
if __name__ == '__main__':语句,在Stack Overflow搜索相关问题,排查两天未解决
主窗口代码(main_window.py)
import sys import multiprocessing from PyQt5.QtWidgets import (QApplication, QWidget, QLineEdit, QPushButton, QVBoxLayout, QLabel) from ping_window import PingWindow class NewProcessPingWindow(multiprocessing.Process): def __init__(self, url, ping_args): super().__init__() self.url = url self.ping_args = ping_args def run(self): app = QApplication(sys.argv) window = PingWindow(self.url, self.ping_args) window.show() sys.exit(app.exec_()) class MainWindow(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('Ping Launcher') self.setGeometry(100, 100, 300, 150) layout = QVBoxLayout() self.url_label = QLabel('目标URL/IP:') self.url_input = QLineEdit() self.url_input.setText('google.com') self.ping_args_label = QLabel('Ping参数(如 -n 4):') self.ping_args_input = QLineEdit() self.ping_args_input.setText('-n 4') self.launch_btn = QPushButton('启动Ping窗口') self.launch_btn.clicked.connect(self.launch_ping_window) layout.addWidget(self.url_label) layout.addWidget(self.url_input) layout.addWidget(self.ping_args_label) layout.addWidget(self.ping_args_input) layout.addWidget(self.launch_btn) self.setLayout(layout) def launch_ping_window(self): url = self.url_input.text() ping_args = self.ping_args_input.text() ping_process = NewProcessPingWindow(url, ping_args) ping_process.start() if __name__ == '__main__': multiprocessing.freeze_support() app = QApplication(sys.argv) main_win = MainWindow() main_win.show() sys.exit(app.exec_())
Ping窗口代码(ping_window.py)
import sys import subprocess import threading from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel from PyQt5.QtGui import QPalette, QColor class PingWindow(QWidget): def __init__(self, url, ping_args): super().__init__() self.url = url self.ping_args = ping_args self.initUI() self.start_ping_thread() def initUI(self): self.setWindowTitle(f'Ping {self.url}') self.setGeometry(200, 200, 300, 100) self.layout = QVBoxLayout() self.status_label = QLabel(f'正在Ping {self.url}...') self.layout.addWidget(self.status_label) self.setLayout(self.layout) def set_window_color(self, is_success): palette = self.palette() if is_success: palette.setColor(QPalette.Window, QColor(0, 255, 0, 50)) else: palette.setColor(QPalette.Window, QColor(255, 0, 0, 50)) self.setPalette(palette) def ping_target(self): while True: try: # Windows系统的ping命令,Linux/macOS需要换成-c参数 result = subprocess.run( ['ping'] + self.ping_args.split() + [self.url], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=10 ) success = result.returncode == 0 self.status_label.setText(f'Ping {self.url} {"成功" if success else "失败"}') self.set_window_color(success) except subprocess.TimeoutExpired: self.status_label.setText(f'Ping {self.url} 超时') self.set_window_color(False) except Exception as e: self.status_label.setText(f'Ping错误: {str(e)}') self.set_window_color(False) def start_ping_thread(self): ping_thread = threading.Thread(target=self.ping_target, daemon=True) ping_thread.start() if __name__ == '__main__': from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) window = PingWindow('google.com', '-n 4') window.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者MIku
相关产品推荐
相关产品推荐

