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

如何通过按钮终止Tkinter中RTSP摄像头播放循环并关闭窗口?

问题修复:Tkinter中RTSP摄像头播放无法关闭及按钮终止功能实现

问题背景

开发了基于Tkinter的RTSP协议IP摄像头切换应用,核心代码如下:

主应用代码

def __init__(self, parent):
    Frame.__init__(self, parent, background="black")
    self.initUI()

def initUI(self):
    self.btn_file = tk.Button(text="Home", command=self.Btn)
    self.btn_file.grid(row=1,column=1, padx=5, pady=5, sticky="e")

def Btn(self):
    self.btn_file.destroy()
    cmr1 = tk.Button(text="cam1-1", command=lambda: self.cmr("rtsp://LOG:PASS@IP/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"))
    cmr1.grid(row=1,column=1, padx=5, pady=5, sticky="e")

def cmr(self, path):
    a = Camera_Open(path)

Camera_Open类代码

class Camera_Open(object,):
    def __init__(self, path):
        self.connect(path, 0)

    def connect(self, path, a):        
        player = vlc.Instance()
        # creating a new media
        media = player.media_new(path)
        # creating a media player object
        media_player = player.media_player_new()
        media_player.set_media(media)
        # setting video scale
        media_player.video_set_scale(0)
        # start playing video
        media_player.play()
        value = media_player.event_manager()
        value = str(value)
        while a == 0:
            if keyboard.is_pressed('esc'):
                print('asdasd')
                break
            pass

遇到的问题:单独使用Camera_Open类时按ESC键可终止播放,但在Tkinter环境内调用时,摄像头输出窗口无法关闭,同时需要实现按钮终止播放的功能。


问题原因

  1. 阻塞Tkinter主事件循环:Camera_Open.connect中的while死循环会卡住Tkinter主线程,导致GUI无法响应任何操作,包括ESC按键捕获和按钮点击。
  2. 无法外部控制播放器:media_player是connect方法的局部变量,外部无法访问调用停止方法。
  3. keyboard模块兼容性问题:在Tkinter主事件循环运行时,keyboard.is_pressed无法正常捕获按键事件。

解决方案

1. 重构Camera_Open类

  • 将media_player设为实例变量,保存播放器引用
  • 移除阻塞的while循环,添加可外部调用的停止方法
  • 增加播放状态标记,避免重复初始化

2. 修改Tkinter主应用

  • 保存Camera_Open实例引用,方便后续控制
  • 添加停止播放按钮,绑定停止逻辑
  • 绑定Tkinter的ESC按键事件,实现按键停止功能

修改后的完整代码

重构后的Camera_Open类

import vlc

class Camera_Open(object):
    def __init__(self, path):
        self.player_instance = vlc.Instance()
        self.media_player = None
        self.is_playing = False
        self.connect(path)

    def connect(self, path):
        if self.is_playing:
            self.stop()
        
        # 创建媒体和播放器实例
        media = self.player_instance.media_new(path)
        self.media_player = self.player_instance.media_player_new()
        self.media_player.set_media(media)
        self.media_player.video_set_scale(0)
        self.media_player.play()
        self.is_playing = True

    def stop(self):
        if self.is_playing and self.media_player:
            self.media_player.stop()
            self.is_playing = False

修改后的Tkinter主应用

import tkinter as tk
from tkinter import Frame

class CameraApp(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent, background="black")
        self.parent = parent
        self.current_camera = None
        self.initUI()
        # 绑定ESC按键停止播放
        self.parent.bind('<Escape>', lambda e: self.stop_camera())

    def initUI(self):
        self.btn_home = tk.Button(self, text="Home", command=self.show_home)
        self.btn_home.grid(row=1, column=1, padx=5, pady=5, sticky="e")

    def show_home(self):
        # 返回主页前先停止当前播放
        self.stop_camera()
        # 清空现有控件,重新初始化主页
        for widget in self.winfo_children():
            widget.destroy()
        self.initUI()

    def show_camera_buttons(self):
        # 清空现有控件,显示摄像头按钮和停止按钮
        for widget in self.winfo_children():
            widget.destroy()
        
        btn_cam1 = tk.Button(self, text="cam1-1", command=lambda: self.start_camera("rtsp://LOG:PASS@IP/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"))
        btn_cam1.grid(row=1, column=1, padx=5, pady=5, sticky="e")
        
        btn_stop = tk.Button(self, text="停止播放", command=self.stop_camera)
        btn_stop.grid(row=1, column=2, padx=5, pady=5, sticky="w")

    def start_camera(self, path):
        # 启动新摄像头前停止当前播放
        self.stop_camera()
        self.current_camera = Camera_Open(path)

    def stop_camera(self):
        if self.current_camera:
            self.current_camera.stop()
            self.current_camera = None

# 运行应用
if __name__ == "__main__":
    root = tk.Tk()
    app = CameraApp(root)
    app.pack(fill=tk.BOTH, expand=1)
    root.mainloop()

关键改进点

  • 移除阻塞主循环的while逻辑,改用Tkinter自身事件循环处理用户操作
  • Camera_Open类提供stop方法,外部可直接调用终止播放
  • Tkinter主应用保存摄像头实例,支持通过按钮或ESC按键触发停止
  • 切换摄像头或返回主页时自动停止当前播放,避免资源泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:41:17