使用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
相关产品推荐
相关产品推荐

