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

Python Tkinter中thread.join()未正常工作问题求助

Tkinter中thread.join()未按预期工作的问题解决

问题根源

你在Tkinter主线程中调用了thread.join(),这会直接阻塞Tkinter的主事件循环,导致整个GUI程序卡死,后续的print("worked")根本没有执行机会。同时你创建的视频/音频线程只是启动播放动作后立即结束,join()本应快速完成,但主线程被阻塞后事件循环停摆,反而引发程序无响应。

另外你的VideoPlayerWithSound类继承了threading.Thread但并未实际使用该线程能力,属于冗余设计,反而容易造成误解。

修复方案

1. 移除主线程中的join()调用

主线程必须保持Tkinter事件循环的运行,绝对不能被join()这类阻塞操作占用。

2. 使用回调机制监听播放结束事件

分别为视频和音频设置播放结束的回调,当两者都完成后再执行后续操作。

修改后的主程序代码

self.path = r'src\files\iki'
# 新增:跟踪播放完成状态
self.video_finished = False
self.sound_finished = False

self.play_video(self.path)

def play_video(self, path):
    self.video_thread = threading.Thread(target=self.video_player.play_video, args=(path + ".mp4",))
    self.sound_thread = threading.Thread(target=self.video_player.play_sound, args=(path + ".mp3",))

    self.sound_thread.start()
    self.video_thread.start()

# 视频播放结束回调
def on_video_end(self, event):
    self.video_finished = True
    self._check_all_finished()

# 音频播放结束回调
def on_sound_end(self):
    self.sound_finished = True
    self._check_all_finished()

# 检查是否两者都播放完毕
def _check_all_finished(self):
    if self.video_finished and self.sound_finished:
        print("worked")

修改后的脚本文件代码

import threading
import tkinter as tk

import pygame
from tkVideoPlayer import TkinterVideo


class VideoPlayerWithSound:
    # 移除不必要的threading.Thread继承
    def __init__(self, parent_frame, sound_end_callback):
        self.parent_frame = parent_frame
        self.sound_end_callback = sound_end_callback
        
        self.videoplayer = TkinterVideo(master=self.parent_frame, scaled=True)
        self.videoplayer.pack(expand=True, fill="both")
        
        pygame.init()

    def play_video(self, video_path):
        self.videoplayer.load(video_path)
        # 绑定视频结束事件,通知主线程
        self.videoplayer.bind("<<End>>", lambda e: self.parent_frame.event_generate("<<VideoEnd>>"))
        self.videoplayer.play()
    
    def play_sound(self, sound_path):
        pygame.mixer.music.load(sound_path)
        pygame.mixer.music.play()
        # 在子线程中监听音频结束,避免阻塞主线程
        threading.Thread(target=self._listen_sound_finish, daemon=True).start()

    def _listen_sound_finish(self):
        while pygame.mixer.music.get_busy():
            pygame.time.wait(100)
        # 音频结束后触发回调
        self.sound_end_callback()

主程序初始化VideoPlayerWithSound时的绑定

# 初始化时传入音频结束回调
self.video_player = VideoPlayerWithSound(parent_frame=self, sound_end_callback=self.on_sound_end)
# 绑定视频结束事件到主程序的回调
self.bind("<<VideoEnd>>", self.on_video_end)

核心要点

  • Tkinter是单线程模型,所有GUI相关操作必须在主线程执行,主线程不能被长时间阻塞。
  • 视频播放结束通过TkinterVideo内置的<<End>>事件监听,音频结束通过子线程循环检查pygame.mixer.music.get_busy()实现。
  • 用状态标志位跟踪两个媒体的播放进度,当两者都完成时再执行后续逻辑。

内容的提问来源于stack exchange,提问作者Umut Topalak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 01:04:57