PyInstaller打包exe后关闭命令窗仍运行的延迟问题求助
解决PyInstaller打包exe后关闭命令窗口程序延迟终止的问题
直接运行.py格式的定时器程序一切正常,但用PyInstaller打包成单文件exe(打包命令:pyinstaller timer.py --name=timer --onefile --icon=icon.ico --hidden-import plyer.platforms.win.notification)后,关闭命令窗口后程序不会立刻终止,要等约6秒才停,期间还能听到音效。以下是具体解决方案:
方案1:监听Windows控制台关闭信号,强制终止进程
Windows控制台程序关闭时会发送CTRL_CLOSE_EVENT信号,我们可以通过ctypes注册信号处理函数,收到信号后立刻终止所有线程并退出进程。
在代码开头导入模块后添加以下内容:
import ctypes import sys # 定义信号处理函数,收到关闭信号直接退出 def handler(sig, func=None): sys.exit(0) # 注册控制台关闭信号监听 if sys.platform == 'win32': kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) CTRL_CLOSE_EVENT = 2 kernel32.SetConsoleCtrlHandler(ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_uint)(handler), True)
方案2:修复线程参数传递错误
你的代码中创建th2线程时存在参数传递问题:
th2 = threading.Thread(target=wait, args=(waitTime), daemon=True)
这里args=(waitTime)不是元组,Python会把waitTime当成可迭代对象拆分参数,导致wait函数接收参数异常。正确写法应为:
th2 = threading.Thread(target=wait, args=(waitTime,), daemon=True) th2.start() # 补充启动线程的代码,原代码遗漏了这一步
方案3:优化资源路径(打包单文件必备)
单文件打包时,PyInstaller会把资源解压到临时目录,需通过sys._MEIPASS获取正确路径,避免音效文件找不到:
# 替换原路径获取代码 if getattr(sys, 'frozen', False): path = pathlib.Path(sys._MEIPASS) else: path = pathlib.Path().resolve()
完整修改后的代码示例
import time import random import winsound import pathlib import threading from plyer import notification from os import system import ctypes import sys # 处理Windows控制台关闭信号 def handler(sig, func=None): sys.exit(0) if sys.platform == 'win32': kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) CTRL_CLOSE_EVENT = 2 kernel32.SetConsoleCtrlHandler(ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_uint)(handler), True) system("title " + "Timer") # 获取正确的资源路径 if getattr(sys, 'frozen', False): path = pathlib.Path(sys._MEIPASS) else: path = pathlib.Path().resolve() print(str(path)) def wait(waitTime): time.sleep(waitTime*60) notification.notify(title='Timer', message='Boinga coinga timer done', app_icon=None, timeout=90) eMsg = ["Um, think you got a typo there, bud.", "Um...that's not a number...", "What do they even teach kids in school these days, anyway?"] waitTime = 1 print("Greetings, human.") print("Behold, the ultimate timer app.") print("Unlike certain other timers I will not mention by name, this one will actually go off eventually.") print("Yeah, Google sure is a great company.") print("Anyway. So. You probably want to set a timer, right?") flag = False canContinue = False while True: print("How many minutes should I wait before I harass you?") waitTime_input = input() try: waitTime = float(waitTime_input) canContinue = True except Exception as e: print(random.choice(eMsg)) continue if canContinue: if flag: print("Now we're talking!") print(f"Timer set for {waitTime} minutes.") print("See ya then!") else: print(f"Aight! See ya in {waitTime} minutes, bud.") # 修复线程参数并启动 th2 = threading.Thread(target=wait, args=(waitTime,), daemon=True) th2.start() # 计时循环 try: for i in range(0, int(60*waitTime)): time.sleep(1) f = str(path) + "\\sfx\\tick" + str(random.randrange(2,5))+".wav" threading.Thread(target=winsound.PlaySound, args=(f, winsound.SND_FILENAME), daemon=True).start() print(i) except KeyboardInterrupt: sys.exit(0) print("Time's up!") notification.notify(title='', message="Time's up, asshat!", app_icon="icon.ico", timeout=90) print("Nice.") flag = False
内容的提问来源于stack exchange,提问作者Ang_d
相关产品推荐
相关产品推荐

