URL 未在不同类中使用信号和插槽 PyQt5 定义



我正在尝试使用线程并行运行带有其参数的视频 因此,当我单击SD按钮时,它会激活TP1和TP2按钮,并且每个按钮都有不同的URL。

我想显示视频并启动进度条并在最后显示结果。

from multiprocessing import Process
import sys
import json
import shlex
import threading
import subprocess
import webbrowser
from QLed import QLed
from functools import partial
from PyQt5.QtGui import QColor,QFont
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtGui import QPainter, QPen
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtCore import QDir, Qt, QUrl, QSize, QPoint, QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QMainWindow
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets
from PyQt5.QtWidgets import (QWidget, QPushButton, QApplication,QGridLayout, QLCDNumber)
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QGridLayout, QLCDNumber


class Analyzer(QtCore.QObject):

result_ready = QtCore.pyqtSignal(object)
def do_work(self, myurl):

cmd = "ffprobe -v quiet -print_format json -show_streams"
args = shlex.split(cmd)
args.append(myurl)
ffprobeOutput = subprocess.check_output(args).decode('utf-8')
ffprobeOutput = json.loads(ffprobeOutput)
result = ffprobeOutput['streams'][0]
self.result_ready.emit(result)

class MainProg(QtWidgets.QMainWindow):
def __init__(self):

super(MainProg, self).__init__()
self.resize(870, 525)
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
############################      The Viedeo and frame  ######
self.frame = QtWidgets.QFrame(self)
self.frame.setGeometry(QtCore.QRect(450, 40, 391, 291))
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.mediaPlayer = QtMultimedia.QMediaPlayer(self.frame)
self.viewer1 = QtMultimediaWidgets.QVideoWidget(self.frame)
self.mediaPlayer.setVideoOutput(self.viewer1)
layout1 = QtWidgets.QGridLayout(self.frame)
layout1.addWidget(self.viewer1, 0, 0, 1, 2)
#############################################################
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(110, 470, 143, 25))
self.progressBar.setProperty("value", 0)
self.progressBar.setTextVisible(True)
self.lcd = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd.setGeometry(QtCore.QRect(220, 50, 146, 50))
self.lcd1 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd1.setGeometry(QtCore.QRect(220, 100, 146, 50))
self.lcd2 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd2.setGeometry(QtCore.QRect(220, 150, 146, 50))
self.lcd3 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd3.setGeometry(QtCore.QRect(220, 200, 146, 50))
self.lcd4 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd4.setGeometry(QtCore.QRect(220, 250, 146, 50))
self.lcd5 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd5.setGeometry(QtCore.QRect(220, 300, 146, 50))
self.lcd6 = QtWidgets.QLCDNumber(self.centralwidget)
self.lcd6.setGeometry(QtCore.QRect(220, 350, 146, 50))

self.txtt = QtWidgets.QLabel(self.centralwidget)
self.txtt.setFont(QFont('Arial', 12))
self.txtt.setGeometry(QtCore.QRect(20, 0, 300, 400))
self.txtt.setText("Video"
"nCode Name .................."
"nnHorizont........................"
"nnVertical.........................."
"nnDisplay Aspect Ratio......"
"nnRefrence........................."
"nnB frames........................."
"nnStart Bits......................."
"nnSample Aspect ratio......."
"nnBit Rate.........................")
self.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(self)
self.statusbar.setObjectName("statusbar")
self.setStatusBar(self.statusbar)


#########################The buttons#################################
self.AASD = QtWidgets.QToolButton(self)
self.AASD.setGeometry(QtCore.QRect(140, 20, 31, 32))
self.AASD.setObjectName("AASD")
self.AASD.setText("SD")
self.AASD.clicked.connect(self.funcchoos)
QTimer.singleShot(5000, lambda: self.AASD.setDisabled(False))
self.Testpunk1 = QtWidgets.QToolButton(self)
self.Testpunk1.setGeometry(QtCore.QRect(150, 400, 31, 32))
self.Testpunk2 = QtWidgets.QToolButton(self)
self.Testpunk2.setGeometry(QtCore.QRect(150, 430, 31, 32))
self.Testpunk1.setText("TP1")
self.Testpunk2.setText("TP2")
self.Testpunk1.setObjectName("TP1")
self.Testpunk2.setObjectName("TP2")
self.Tp1 = QLed(self, onColour=QLed.Orange, shape=QLed.Circle)
self.Tp1.setGeometry(QtCore.QRect(185, 415, 25, 25))
self.Tp1.value = False
########################### the functions############################
def funcchoos (self):
QtCore.QTimer.singleShot(500, self.TPLed) # Using timer as QLed uses it in its tests
if self.sender().objectName() == "AASD":
self.Testpunk1.clicked.connect(self.MyUrl)
self.Testpunk2.clicked.connect(self.MyUrl)
return
def MyUrl(self):
TP1 = "293.168.1.6:1115"
TP2 = "239.168.1.7:1116"

if self.sender().objectName() == "TP1":
myurl = TP1
print("TP1 is playing")
self.dep3(myurl)
return
if self.sender().objectName() == "TP2":
myurl = TP2
self.dep3(myurl)
print(myurl)
print("TP2 is playing")
return
##############################################################
def TPLed(self):
self.Tp1.setValue(True)  # the LED ON code

#########################################################################
def dep3(self,myurl):
# set progress bar to undetermined state and disable button
self.progressBar.setRange(0,0)
self.Testpunk1.setEnabled(False)
self.mediaPlayer.setMedia(QMediaContent(QUrl(myurl)))
self.mediaPlayer.play()
# create thread for doing heavy work
self.thread = QtCore.QThread()
self.worker = Analyzer()
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.do_work(myurl))
self.thread.finished.connect(self.worker.deleteLater)
self.worker.result_ready.connect(self.process_result)
self.worker.result_ready.connect(self.worker.do_work(myurl))

self.thread.start()
def process_result(self, result):
codec_name = result['codec_name']
width = result['width']
height = result['height']
display_aspect_ratio = result['display_aspect_ratio']
sample_aspect_ratio = result['sample_aspect_ratio']
refs = result['refs']
has_b_frames = result['has_b_frames']
self.lcd.display(has_b_frames)
self.lcd1.display(codec_name)
self.lcd2.display(width)
self.lcd3.display(height)
self.lcd4.display(display_aspect_ratio)
self.lcd5.display(sample_aspect_ratio)
self.lcd6.display(refs)
# reset progress bar and push button
self.progressBar.setRange(0,100)
self.progressBar.setValue(100)
self.pushButton.setEnabled(True)

print("done!!")

if __name__ == "__main__":
import sys

app = QtWidgets.QApplication(sys.argv)

player = MainProg()
player.show()
sys.exit(app.exec_())

主要问题是当您使用时:

foo.signal.connect(function(args))

等于

value = function(args)
foo.signal.connect(value)

这会导致错误,因为 connect 需要可调用对象,并且在您的情况下,值为 None 导致错误。

解决方案通常是使用 lambda 或 parts,但第一个会导致函数在主线程中执行,因为它是在该线程中调用的,因此必须丢弃它,而不是 partes 只添加参数。

  • λ:
foo.signal.connect(lambda *_, args=args : function(args))
  • functools.partial
foo.signal.connect(functools.partial(function, args))

此外,您还有其他错误,例如每次调用"funcchoos"时,都会在"TestpunkX"和MyUrl之间创建一个新连接,导致每次按"TestpunkX"时,"MyUrl"被调用的次数与"调用funcchoos"一样多。

考虑到上述情况,我重写了您的代码,因为可能存在其他错误。

from functools import partial
import json
import shlex
import subprocess
import sys

from QLed import QLed
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets

class Analyzer(QtCore.QObject):
result_ready = QtCore.pyqtSignal(object)
@QtCore.pyqtSlot(str)
def do_work(self, myurl):
cmd = "ffprobe -v quiet -print_format json -show_streams"
args = shlex.split(cmd)
args.append(myurl)
ffprobeOutput = subprocess.check_output(args).decode("utf-8")
ffprobeOutput = json.loads(ffprobeOutput)
result = ffprobeOutput["streams"][0]
self.result_ready.emit(result)

class MainProg(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainProg, self).__init__(parent)
self.setFont(QtGui.QFont("Arial", 12))
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
hlay = QtWidgets.QHBoxLayout(central_widget)
left_widget = QtWidgets.QWidget()
self.mediaPlayer = QtMultimedia.QMediaPlayer()
self.video_widget = QtMultimediaWidgets.QVideoWidget()
self.video_widget.setContentsMargins(30, 30, 30, 30)
self.mediaPlayer.setVideoOutput(self.video_widget)
self.sd_button = QtWidgets.QToolButton(text="SD", checkable=True)
self.sd_button.setFixedSize(31, 32)
self.code_lcd = QtWidgets.QLCDNumber()
self.horizontal_lcd = QtWidgets.QLCDNumber()
self.vertical_lcd = QtWidgets.QLCDNumber()
self.display_aspect_ratio_lcd = QtWidgets.QLCDNumber()
self.reference_lcd = QtWidgets.QLCDNumber()
self.b_frames_lcd = QtWidgets.QLCDNumber()
self.start_bits_lcd = QtWidgets.QLCDNumber()
self.sample_aspect_ratio_lcd = QtWidgets.QLCDNumber()
self.bit_rate_lcd = QtWidgets.QLCDNumber()
self.tp1_button = QtWidgets.QToolButton(text="TP1")
self.tp2_button = QtWidgets.QToolButton(text="TP2")
self.led = QLed(self, onColour=QLed.Orange, shape=QLed.Circle)
self.progressbar = QtWidgets.QProgressBar()
for lcd in (
self.code_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.reference_lcd,
self.b_frames_lcd,
self.start_bits_lcd,
self.sample_aspect_ratio_lcd,
self.bit_rate_lcd,
):
lcd.setFixedSize(146, 50)
hlay.addWidget(left_widget)
hlay.addWidget(self.video_widget, stretch=1)
lay = QtWidgets.QGridLayout(left_widget)
lay.setVerticalSpacing(5)
for i, (text, widget) in enumerate(
zip(
(
"Video",
"Codec Name:",
"Horizontal:",
"Vertical:",
"Display Aspect Ratio:",
"Refrence:",
"B frames:",
"Start Bits:",
"Sample Aspect ratio:",
"Bit Rate:",
),
(
self.sd_button,
self.code_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.reference_lcd,
self.b_frames_lcd,
self.start_bits_lcd,
self.sample_aspect_ratio_lcd,
self.bit_rate_lcd,
),
)
):
label = QtWidgets.QLabel(text)
lay.addWidget(label, i, 0)
lay.addWidget(widget, i, 1, alignment=QtCore.Qt.AlignCenter)
vlay = QtWidgets.QVBoxLayout()
vlay.addWidget(self.tp1_button)
vlay.addWidget(self.tp2_button)
hlay2 = QtWidgets.QHBoxLayout()
hlay2.addStretch(0)
hlay2.addLayout(vlay)
hlay2.addWidget(self.led)
hlay2.addStretch(0)
lay.addLayout(hlay2, lay.rowCount(), 0, 1, 2)
lay.addWidget(self.progressbar, lay.rowCount(), 0, 1, 2)
lay.setRowStretch(lay.rowCount(), 1)
self.resize(960, 480)
self.sd_button.toggled.connect(self.led.setValue)
self.tp1_button.clicked.connect(self.on_tp_clicked)
self.tp2_button.clicked.connect(self.on_tp_clicked)
self.current_button = None
thread = QtCore.QThread(self)
thread.start()
self.worker = Analyzer()
self.worker.moveToThread(thread)
self.worker.result_ready.connect(self.process_result)
@QtCore.pyqtSlot()
def on_tp_clicked(self):
if self.sd_button.isChecked():
urls_map = {
self.tp1_button: "293.168.1.6:1115",
self.tp2_button: "239.168.1.7:1116",
}
url = urls_map.get(self.sender(), "")
if url:
self.play(url)
self.current_button = self.sender()
self.current_button.setEnabled(False)
def play(self, url):
self.progressbar.setRange(0, 0)
self.mediaPlayer.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl(url)))
self.mediaPlayer.play()
wrapper = partial(self.worker.do_work, url)
QtCore.QTimer.singleShot(0, wrapper)
@QtCore.pyqtSlot(object)
def process_result(self, result):
self.current_button.setEnabled(True)
self.current_button = None
self.progressbar.setRange(0, 1)
self.progressbar.setValue(0)
for lcd, key in zip(
(
self.code_lcd,
self.b_frames_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.sample_aspect_ratio_lcd,
self.reference_lcd,
),
(
"codec_name",
"has_b_frames",
"width",
"height",
"display_aspect_ratio",
"sample_aspect_ratio",
"refs",
),
):
value = result.get(key, 0)
lcd.display(value)

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

虽然我认为不需要使用线程,但在这种情况下,使用 QProcess 更容易。

from functools import partial
import json
import shlex
import sys

from QLed import QLed
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia, QtMultimediaWidgets

class MainProg(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainProg, self).__init__(parent)
self.setFont(QtGui.QFont("Arial", 12))
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
hlay = QtWidgets.QHBoxLayout(central_widget)
left_widget = QtWidgets.QWidget()
self.mediaPlayer = QtMultimedia.QMediaPlayer()
self.video_widget = QtMultimediaWidgets.QVideoWidget()
self.video_widget.setContentsMargins(30, 30, 30, 30)
self.mediaPlayer.setVideoOutput(self.video_widget)
self.sd_button = QtWidgets.QToolButton(text="SD", checkable=True)
self.sd_button.setFixedSize(31, 32)
self.code_lcd = QtWidgets.QLCDNumber()
self.horizontal_lcd = QtWidgets.QLCDNumber()
self.vertical_lcd = QtWidgets.QLCDNumber()
self.display_aspect_ratio_lcd = QtWidgets.QLCDNumber()
self.reference_lcd = QtWidgets.QLCDNumber()
self.b_frames_lcd = QtWidgets.QLCDNumber()
self.start_bits_lcd = QtWidgets.QLCDNumber()
self.sample_aspect_ratio_lcd = QtWidgets.QLCDNumber()
self.bit_rate_lcd = QtWidgets.QLCDNumber()
self.tp1_button = QtWidgets.QToolButton(text="TP1")
self.tp2_button = QtWidgets.QToolButton(text="TP2")
self.led = QLed(self, onColour=QLed.Orange, shape=QLed.Circle)
self.progressbar = QtWidgets.QProgressBar()
for lcd in (
self.code_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.reference_lcd,
self.b_frames_lcd,
self.start_bits_lcd,
self.sample_aspect_ratio_lcd,
self.bit_rate_lcd,
):
lcd.setFixedSize(146, 50)
hlay.addWidget(left_widget)
hlay.addWidget(self.video_widget, stretch=1)
lay = QtWidgets.QGridLayout(left_widget)
lay.setVerticalSpacing(5)
for i, (text, widget) in enumerate(
zip(
(
"Video",
"Codec Name:",
"Horizontal:",
"Vertical:",
"Display Aspect Ratio:",
"Refrence:",
"B frames:",
"Start Bits:",
"Sample Aspect ratio:",
"Bit Rate:",
),
(
self.sd_button,
self.code_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.reference_lcd,
self.b_frames_lcd,
self.start_bits_lcd,
self.sample_aspect_ratio_lcd,
self.bit_rate_lcd,
),
)
):
label = QtWidgets.QLabel(text)
lay.addWidget(label, i, 0)
lay.addWidget(widget, i, 1, alignment=QtCore.Qt.AlignCenter)
vlay = QtWidgets.QVBoxLayout()
vlay.addWidget(self.tp1_button)
vlay.addWidget(self.tp2_button)
hlay2 = QtWidgets.QHBoxLayout()
hlay2.addStretch(0)
hlay2.addLayout(vlay)
hlay2.addWidget(self.led)
hlay2.addStretch(0)
lay.addLayout(hlay2, lay.rowCount(), 0, 1, 2)
lay.addWidget(self.progressbar, lay.rowCount(), 0, 1, 2)
lay.setRowStretch(lay.rowCount(), 1)
self.resize(960, 480)
self.sd_button.toggled.connect(self.led.setValue)
self.tp1_button.clicked.connect(self.on_tp_clicked)
self.tp2_button.clicked.connect(self.on_tp_clicked)
self.current_button = None
self.process = QtCore.QProcess(self)
self.process.finished.connect(self.on_finish)
@QtCore.pyqtSlot()
def on_tp_clicked(self):
if self.sd_button.isChecked():
urls_map = {
self.tp1_button: "293.168.1.6:1115",
self.tp2_button: "239.168.1.7:1116",
}
url = urls_map.get(self.sender(), "")
if url:
self.play(url)
self.current_button = self.sender()
self.current_button.setEnabled(False)
def play(self, url):
self.progressbar.setRange(0, 0)
self.mediaPlayer.setMedia(QtMultimedia.QMediaContent(QtCore.QUrl(url)))
self.mediaPlayer.play()
cmd = "ffprobe -v quiet -print_format json -show_streams"
program, *args = shlex.split(cmd)
args.append(url)
self.process.start(program, args)
@QtCore.pyqtSlot()
def on_finish(self):
data = self.process.readAllStandardOutput().data()
if data:
ffprobeOutput = json.loads(data)
result = ffprobeOutput['streams'][0]
for lcd, key in zip(
(
self.code_lcd,
self.b_frames_lcd,
self.horizontal_lcd,
self.vertical_lcd,
self.display_aspect_ratio_lcd,
self.sample_aspect_ratio_lcd,
self.reference_lcd,
),
(
"codec_name",
"has_b_frames",
"width",
"height",
"display_aspect_ratio",
"sample_aspect_ratio",
"refs",
),
):
value = result.get(key, 0)
lcd.display(value)

self.current_button.setEnabled(True)
self.current_button = None
self.progressbar.setRange(0, 1)
self.progressbar.setValue(0)

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

最新更新