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

使用sounddevice与tkinter开发录音器时GUI冻结问题求助

问题解决:Tkinter录音器窗口冻结

问题根源

你的代码里record()函数的while stoprec == False循环直接在Tkinter主线程中执行,而Tkinter是单线程框架,主线程被这个循环占满后,无法处理窗口的事件(比如按钮点击、界面刷新),导致窗口冻结。同时原录音逻辑存在缺陷:每次循环调用sd.rec(lst[-1] * freq)会录制time秒的音频,不仅会重复覆盖同一文件,还没有等待录音完成就继续循环,实际录音效果不符合预期。

修复方案

使用threading模块把录音逻辑放到子线程中执行,让主线程专注处理Tkinter的界面事件。同时调整录音逻辑,用sd.InputStream实时采集音频数据,直到触发停止信号后再统一保存文件。

修改后的完整代码

from tkinter import *
import threading
import sounddevice as sd
from scipy.io.wavfile import write

win = Tk()
win.title("Voice Recording")
win.geometry('400x500')
win.resizable(False, False)
# win.iconbitmap('Logo.ico')  # 可根据实际文件路径保留
# img = PhotoImage(file='Microphone.png')  # 可根据实际文件路径保留

stoprec = False
time = 0
audio_data = []  # 存储实时采集的音频数据
freq = 44100

def start(startbtn):
    global stoprec, audio_data, time
    stoprec = False
    audio_data.clear()
    time = 0
    
    startbtn.config(state='disabled')
    btnstop.config(state='normal')
    
    def stop():
        global stoprec
        stoprec = True
        btnstop.config(state='disabled')
        startbtn.config(state='normal')
    
    btnstop.config(command=stop)
    
    def count():
        global time, stoprec
        if not stoprec:
            time += 1
            win.after(1000, count)
    
    count()
    
    def record():
        global stoprec, audio_data
        # 音频回调函数,实时采集数据
        def callback(indata, frames, time, status):
            if status:
                print(status)
            if not stoprec:
                audio_data.append(indata.copy())
        
        # 启动输入流持续采集
        with sd.InputStream(samplerate=freq, channels=2, callback=callback):
            while not stoprec:
                sd.sleep(100)  # 避免空循环占用过多资源
        
        # 停止后拼接并保存音频
        if audio_data:
            audio_data = sd.concatenate(audio_data)
            write('recording.wav', freq, audio_data)
    
    # 启动录音子线程,避免阻塞主线程
    threading.Thread(target=record, daemon=True).start()

# lbl = Label(win, image=img)
# lbl.pack()
startbtn = Button(win, text='Start Recording', font=('times new roman', 15), cursor='hand2', command=lambda: start(startbtn))
startbtn.pack(pady=10)
btnstop = Button(win, text='Stop Recording', font=('times new roman', 15), cursor='hand2', state='disabled')
btnstop.pack()

win.mainloop()

关键修改说明

  • 引入threading模块,将录音逻辑放到子线程运行,彻底避免阻塞Tkinter主线程。
  • 使用sd.InputStream配合回调函数实现真正的持续录音,替代原有的循环调用sd.rec的错误逻辑。
  • 优化按钮状态管理:开始录音时禁用开始按钮、启用停止按钮,停止后恢复开始按钮可点击状态。
  • 设置子线程为守护线程(daemon=True),确保关闭窗口时子线程自动退出,避免残留进程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:11:26