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

PyQt5 UDP视频播放器按钮状态重置功能实现求助

解决PyQt5 UDP视频播放器按钮状态重置与视频停止问题

我来帮你搞定这个问题!你需要实现的核心是:当点击新的SD类或Source类按钮时,自动重置之前所有按钮的选中状态、停止当前播放的视频,并只激活对应类别的TP按钮,避免出现多个按钮同时启用的混乱情况。下面是具体的实现方案和修改后的完整代码:

实现思路

  1. 按钮分组管理:把SD类按钮、Source类按钮、TP按钮分别归类到列表中,方便后续批量操作状态。
  2. 统一重置函数:编写一个专门的函数,负责停止视频、重置所有按钮状态、关闭指示灯、清空节目名称。
  3. 绑定按钮点击事件:给每个SD/Source按钮绑定点击事件,触发时先执行重置,再激活对应组的TP按钮并标记自己为选中状态。
  4. 初始化TP按钮状态:默认所有TP按钮都是禁用的,只有点击对应类别按钮后才启用。

修改后的完整代码

import vlc
import os
import sys
import threading
from QLed import QLed
from functools import partial
from PyQt5.QtGui import QColor, QFont
from PyQt5.QtGui import QPainter, QPen
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QDir, Qt, QUrl, QSize, QPoint, QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QMainWindow
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QGridLayout, QLCDNumber

class MainProg(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainProg, self).__init__(parent)
        self.setObjectName("MainWindow")
        self.setFixedSize(1280, 768)
        self.setStyleSheet("")
        self.setWindowTitle("video player ")
        self.instance = vlc.Instance()
        self.mediaplayer = self.instance.media_player_new()

        ################# The Test Points LEDs ######################
        self.TPL1 = QLed(self, onColour=QLed.Orange, shape=QLed.Round)
        self.TPL1.setGeometry(QtCore.QRect(190, 500, 35, 25))
        self.TPL3 = QLed(self, onColour=QLed.Orange, shape=QLed.Round)
        self.TPL3.setGeometry(QtCore.QRect(440, 525, 35, 25))

        ######################## Test Points Geo ##############################################
        self.Testpunk1 = QtWidgets.QPushButton(self)
        self.Testpunk1.setGeometry(QtCore.QRect(190, 460, 31, 31))
        self.Testpunk1.setObjectName("TP1")
        self.Testpunk2 = QtWidgets.QPushButton(self)
        self.Testpunk2.setGeometry(QtCore.QRect(190, 530, 31, 31))
        self.Testpunk2.setObjectName("TP2")
        self.Testpunk5 = QtWidgets.QPushButton(self)
        self.Testpunk5.setGeometry(QtCore.QRect(440, 490, 31, 31))
        self.Testpunk5.setObjectName("TP5")
        self.Testpunk6 = QtWidgets.QPushButton(self)
        self.Testpunk6.setGeometry(QtCore.QRect(440, 550, 31, 31))
        self.Testpunk6.setObjectName("TP6")

        # 初始化TP按钮为禁用状态
        self.Testpunk1.setEnabled(False)
        self.Testpunk2.setEnabled(False)
        self.Testpunk5.setEnabled(False)
        self.Testpunk6.setEnabled(False)

        ##########set text
        self.Testpunk1.setText(("TP1"))
        self.Testpunk2.setText(("TP2"))
        self.Testpunk5.setText(("TP5"))
        self.Testpunk6.setText(("TP6"))

        ############################ The Video and frame #################################
        self.videoframe = QtWidgets.QFrame(self)
        self.videoframe.setGeometry(QtCore.QRect(850, 40, 391, 291))
        self.videoframe.setFrameShape(QtWidgets.QFrame.Box)
        self.videoframe.setFrameShadow(QtWidgets.QFrame.Raised)
        self.vboxlayout = QVBoxLayout()
        self.vboxlayout.addWidget(self.videoframe)
        self.mediaplayer.set_hwnd(int(self.videoframe.winId()))

        ########################################################################################
        ########################## SD and HD buttons############################################
        self.EspSD = QtWidgets.QToolButton(self, text="SD1", checkable=True)
        self.EspSD.setGeometry(QtCore.QRect(140, 170, 31, 32))
        self.EspSD.setObjectName("SD")
        self.DeuSD = QtWidgets.QToolButton(self, text="SD2", checkable=True)
        self.DeuSD.setGeometry(QtCore.QRect(140, 220, 31, 32))
        self.DeuSD.setObjectName("DeSD")
        self.DeupSD = QtWidgets.QToolButton(self, text="SD3", checkable=True)
        self.DeupSD.setGeometry(QtCore.QRect(140, 270, 31, 32))
        self.DeupSD.setObjectName("DpSD")

        ##########################source buttons############################################
        self.IntS = QtWidgets.QToolButton(self, text="Source5", checkable=True)
        self.IntS.setGeometry(QtCore.QRect(240, 170, 65, 32))
        self.IntS.setObjectName("5")
        self.AstD = QtWidgets.QToolButton(self, text="Source6", checkable=True)
        self.AstD.setGeometry(QtCore.QRect(240, 220, 65, 32))
        self.AstD.setObjectName("6")
        self.IntSdep = QtWidgets.QToolButton(self, text="Source7", checkable=True)
        self.IntSdep.setGeometry(QtCore.QRect(240, 270, 65, 32))
        self.IntSdep.setObjectName("7")

        ################################### The Main Window Labels ############################
        self.CurrentPro = QtWidgets.QLabel(self)
        self.CurrentPro.setFont(QFont('Arial', 10))
        self.CurrentPro.setGeometry(QtCore.QRect(580, 55, 140, 35))
        self.CurrentPro.setText("Current Program :")
        self.CurrentProL = QtWidgets.QLabel(self)
        self.CurrentProL.setFont(QFont('Arial', 10))
        self.CurrentProL.setGeometry(QtCore.QRect(690, 55, 155, 35))

        # 按钮分组:方便批量管理状态
        self.sd_buttons = [self.EspSD, self.DeuSD, self.DeupSD]
        self.source_buttons = [self.IntS, self.AstD, self.IntSdep]
        self.tp_enc_buttons = [self.Testpunk1, self.Testpunk2]
        self.tp_mux_buttons = [self.Testpunk5, self.Testpunk6]

        #################################### 绑定按钮点击事件 ######################################
        # TP按钮点击事件
        self.Testpunk1.clicked.connect(self.on_tp_clicked_Enc)
        self.Testpunk2.clicked.connect(self.on_tp_clicked_Enc)
        self.Testpunk5.clicked.connect(self.on_tp_clicked_Mux)
        self.Testpunk6.clicked.connect(self.on_tp_clicked_Mux)

        # SD按钮点击事件
        self.EspSD.clicked.connect(partial(self.on_sd_source_clicked, is_sd=True, button=self.EspSD))
        self.DeuSD.clicked.connect(partial(self.on_sd_source_clicked, is_sd=True, button=self.DeuSD))
        self.DeupSD.clicked.connect(partial(self.on_sd_source_clicked, is_sd=True, button=self.DeupSD))

        # Source按钮点击事件
        self.IntS.clicked.connect(partial(self.on_sd_source_clicked, is_sd=False, button=self.IntS))
        self.AstD.clicked.connect(partial(self.on_sd_source_clicked, is_sd=False, button=self.AstD))
        self.IntSdep.clicked.connect(partial(self.on_sd_source_clicked, is_sd=False, button=self.IntSdep))

    def reset_all_states(self):
        """重置所有状态:停止视频、重置按钮、关闭LED、清空节目名"""
        # 停止当前播放的视频
        if self.mediaplayer.is_playing():
            self.mediaplayer.stop()
        
        # 取消所有SD和Source按钮的选中状态
        for btn in self.sd_buttons + self.source_buttons:
            btn.setChecked(False)
        
        # 禁用所有TP按钮
        for btn in self.tp_enc_buttons + self.tp_mux_buttons:
            btn.setEnabled(False)
        
        # 关闭LED指示灯
        self.TPL1.setValue(False)
        self.TPL3.setValue(False)
        
        # 清空节目名称标签
        self.CurrentProL.setText("")

    def on_sd_source_clicked(self, is_sd, button):
        """处理SD或Source按钮的点击事件"""
        # 先重置所有状态
        self.reset_all_states()
        
        # 标记当前按钮为选中状态
        button.setChecked(True)
        
        # 激活对应组的TP按钮
        if is_sd:
            for btn in self.tp_enc_buttons:
                btn.setEnabled(True)
        else:
            for btn in self.tp_mux_buttons:
                btn.setEnabled(True)

    def on_tp_clicked_Enc(self):
        self.TPL1.setValue(True)
        if self.EspSD.isChecked():
            urls_map = {
                self.Testpunk1: "udp://@239.168.1.6:1113",
                self.Testpunk2: "udp://@239.168.1.7:1117",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program4")
        elif self.DeuSD.isChecked():
            urls_map = {
                self.Testpunk1: "udp://@239.168.1.6:1123",
                self.Testpunk2: "udp://@239.168.1.7:1127",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program5")
        elif self.DeupSD.isChecked():
            urls_map = {
                self.Testpunk1: "udp://@239.168.1.6:1121",
                self.Testpunk2: "udp://@239.168.1.7:1125",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program6")

    @QtCore.pyqtSlot()
    def on_tp_clicked_Mux(self):
        self.TPL3.setValue(True)
        if self.IntS.isChecked():
            urls_map = {
                self.Testpunk5: "udp://@239.168.2.6:2113",
                self.Testpunk6: "udp://@239.168.2.7:2123",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program3 Source3")
        elif self.AstD.isChecked():
            urls_map = {
                self.Testpunk5: "udp://@239.168.2.6:2117",
                self.Testpunk6: "udp://@239.168.2.7:2127",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program4 Source4")
        elif self.IntSdep.isChecked():
            urls_map = {
                self.Testpunk5: "udp://@239.168.2.6:2113",
                self.Testpunk6: "udp://@239.168.2.7:2123",
            }
            url = urls_map.get(self.sender(), "")
            if url:
                self.play(url)
                self.CurrentProL.setText("Program4 Source5")

    def play(self, url):
        print('the url arrived')
        self.media = self.instance.media_new(url)
        self.media.get_mrl()
        self.mediaplayer.set_media(self.media)
        print('last step before video viewing')
        self.mediaplayer.play()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainProg()
    w.show()
    sys.exit(app.exec_())

关键修改说明

  • 按钮分组:新增了sd_buttons、source_buttons等列表,把同类别按钮归类,方便批量操作状态。
  • 重置函数:reset_all_states函数统一处理状态重置逻辑,避免重复代码。
  • SD/Source按钮事件绑定:用partial传递参数,点击时先重置所有状态,再激活对应TP按钮。
  • TP按钮初始状态:默认禁用,只有点击对应类别按钮后才启用,避免误操作。
  • 优化条件判断:把TP按钮事件中的if改为elif,避免多个条件同时触发(虽然之前逻辑也没问题,但这样更严谨)。

这样修改后,当你点击任意SD或Source按钮时,之前的视频会停止,所有按钮状态会重置,只有当前点击的按钮处于选中状态,且对应组的TP按钮会被激活,完美解决你遇到的问题!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 19:42:32