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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 04:50:19