PyQt5:QMediaplayer,QVideowidget播放视频(3)
PyQt5:QMediaplayer,QVideowidget播放视频(3)
简介
在 PyQt5:QMediaplayer,QVideowidget播放视频(2)上一篇中完善了界面的布局,快进,慢进。在本篇更新中做了代码做了重构,架构的好坏就另说了,python 没有做过成熟的项目,一直自己写的玩。在本篇中主要更新了UI、播放列表、配置项、媒体文件管理、布局、子控件,还有快进、快退、音量等等一些基础功能。
代码结构
模块架构
文件结构
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020/9/21 20:52 __pycache__
-a---- 2020/5/18 22:28 761 audio.py
-a---- 2020/5/18 22:23 2008 audio.ui
-a---- 2020/9/22 22:13 379 config.json
-a---- 2020/5/6 23:31 2371 itemWidget.ui
-a---- 2020/9/22 22:15 7805 MediaPlayer.py
-a---- 2020/5/18 23:03 1776 MediaPlayer.pyproj
-a---- 2020/9/21 20:52 9788 MediaPlayer.ui
-a---- 2020/9/21 20:52 8664 ui.py
-a---- 2020/5/18 22:01 2281 ui_audio.py
-a---- 2020/5/14 21:10 5533 ui_url.py
-a---- 2020/5/18 23:03 991 urlWidget.py
-a---- 2020/5/14 21:10 7030 urlWidget.ui
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
在上图中可以看到,主要分为三个模块,MediaPlayer、audio、urlWidget 三个模块。其中 MediaPlayer为主窗口,主体界面布局、逻辑功能、播放窗口、播放列表都在其中实现。audio模块主要负责音量条。urlWidget模块主要负责网络url弹窗输入。
源码介绍
Audio
在文件结构中可以看到,主要有三个文件。audio.ui,ui_audio.py,audio.py 分别是 UI设计文件,UIpy文件,code文件。
Audio.ui
UI设计文件:
Widget类型,布局全部用UI布局,不使用代码,原则是,尽量少用代码设置,方便后期修改维护。布局时,使用Frame嵌套,方便子控件修改。提高易用性,可读性。
Audio_ui.py
FileName = os.path.basename(sys.argv[0])
FilePath = sys.argv[0].replace(FileName,"")
UiName = FileName.replace(".py",".ui")
UiPath = FilePath +UiName
Ui_pyName = FilePath+"ui_audio.py"
FileFlag = os.path.isfile(Ui_pyName)
if FileFlag == 0:
sys_cmd = os.popen("pyuic5"+" -o "+Ui_pyName+" "+UiPath)
time.sleep(1)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
还是采用之前的方法,使用命令转换,在更新UI后,删除之前的 ui_xxx.py文件,下次会自动生成。记得将对应的audio.py 设置为启动文件。然后在切回去。
audio.py
from ui_audio import Ui_Audio
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class audioWidget(QWidget):
def __init__(self):
super(audioWidget,self).__init__()
global ui
ui = Ui_Audio()
ui.setupUi(self)
self.audio = ui
def getSlider(self):
return self.audio.verticalSlider
def getMuteBtn(self):
return self.audio.pushButton
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
对外接口主要有两个 音量输出,静音输出。
urlWidget
与audio模块相同也是拥有三个对应文件. ui 和 ui.py 不做介绍
urlWidget.ui
urlWidget_ui.py
urlWidget.py
from ui_url import Ui_urlWidget
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class urlWidget(QWidget):
fileInfo_Signle = pyqtSignal(list)
def __init__(self):
super(urlWidget,self).__init__()
global ui
ui = Ui_urlWidget()
ui.setupUi(self)
self.url = ui
ui.pushButton_2.clicked.connect(self.sltConfirm)
def getFileInfo(self):
return [self.url.lineEdit_url.text(),self.url.lineEdit.text()]
def sltConfirm(self):
self.fileInfo_Signle.emit([self.url.lineEdit_url.text(),self.url.lineEdit.text()])
self.hide()
def sltCancel(self):
self.hide()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
其功能主要是添加网络媒体资源时,提供单独的窗口,有两个输入的LineEidt ,一个是 url 路径,一个 媒体资源名称。
提供了两种方式对外输出urlhe 媒体文件名称。调用接口与信号槽
def getFileInfo(self):
return [self.url.lineEdit_url.text(),self.url.lineEdit.text()]
- 1
- 2
fileInfo_Signle = pyqtSignal(list)
def sltConfirm(self):
self.fileInfo_Signle.emit([self.url.lineEdit_url.text(),self.url.lineEdit.text()])
self.hide()
- 1
- 2
- 3
- 4
MediaPlayer
该模块主窗口模块,主要负责逻辑部分即业务部分。还有一些 listwdiget,videowidget 主要功能实现,其实按照设计模式应该也做单独的 模块,主窗口负责调用。
下面介绍MediaPlayer
初始化
init
def __init__(self):
super(m_window,self).__init__()
self.setupUi(self)
self.videoframe = QVideoWidget(self) # videoWidget 初始化
self.layout_videoframe.addWidget(self.videoframe) # 布局添加videoWidget
self.player = QMediaPlayer(self) #播放器初始化 -- 只负责播放功能
self.player.setVideoOutput(self.videoframe) #设置播放窗体
self.playListInit() #播放列表初始化
self.connectBind() # 初始化槽函数绑定,适用于全局,以及全流程
self.bindPlaylistAnddListWidget() # 绑定播放列表与ListWidget
self.initAudioAndFile() #音频设置初始化
self.fileBtnMenuInit() # 文件菜单初始化
self.readConfig() #载入配置文件
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
音频设置初始化,文件添加初始化
#音频设置初始化,文件添加初始化
def initAudioAndFile(self):
self.urlWidget = urlWidget()
self.urlWidget.fileInfo_Signle.connect(self.sltUrlWidget)
self.audio = audioWidget()
self.audio.getSlider().valueChanged.connect(self.sltSetAudioValue)
self.audio.getMuteBtn().clicked.connect(self.sltSetAudioMute)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
播放列表初始化
#播放列表初始化 - 声明/定义/播放模式设置
def playListInit(self):
self.playList = QMediaPlaylist()
self.player.setPlaylist(self.playList)
self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
self.player.positionChanged.connect(self.sltShowPlayTime)
- 1
- 2
- 3
- 4
- 5
- 6
文件菜单初始化
#文件按钮绑定菜单/本地文件/网络资源
def fileBtnMenuInit(self):
btnMenu=QMenu(self)
btnMenu.addAction("本地文件")
btnMenu.addAction("网络资源")
self.pushButton_file.setMenu(btnMenu)
btnMenu.triggered.connect(self.sltFile)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
全局信号槽
#信号槽绑定函数 -- 主要功能按键 播放/上一个/下一个/音频/文件/设置
def connectBind(self):
self.pushButton_play.clicked.connect(self.sltPlayState)
self.pushButton_befor.clicked.connect(self.sltPlayBefore)
self.pushButton_next.clicked.connect(self.sltPlayNext)
self.pushButton_audio.clicked.connect(self.sltAudio)
self.pushButton_setup.clicked.connect(self.sltSetup) # 设置ListWidget 右键菜单模式
self.listWidget_playlist.setContextMenuPolicy(Qt.CustomContextMenu)
self.listWidget_playlist.customContextMenuRequested.connect(self.listWidgetRightMenu)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
文件添加
按钮初始化
#文件按钮绑定菜单/本地文件/网络资源
def fileBtnMenuInit(self):
btnMenu=QMenu(self)
btnMenu.addAction("本地文件")
btnMenu.addAction("网络资源")
self.pushButton_file.setMenu(btnMenu)
btnMenu.triggered.connect(self.sltFile)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
本地资源添加
#添加本地文件
def addLoadFile(self):
str = QFileDialog.getOpenFileName(self,"选择媒体文件","D:/","video files(*.avi *.mp4 *.wmv)")
filePath = str[0]
fileName = (filePath.split('/')[-1]).split('.')[0]
return [filePath,fileName]
- 1
- 2
- 3
- 4
- 5
- 6
网络资源
#添加网络文件
def addNetFile(self):
self.urlWidget.show()
def sltUrlWidget(self,list):
config['playlist'].append({'filepath':list[0],'filename':list[1]})
self.addFile(list[0],list[1])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
槽函数 -按钮添加文件
#槽函数-添加文件
def sltFile(self,action):
if action.text() == "本地文件": fileInfo = self.addLoadFile() config['playlist'].append({'filepath':fileInfo[0],'filename':fileInfo[1]}) self.addFile(fileInfo[0],fileInfo[1])
elif action.text() == "网络资源": self.addNetFile()
def addFile(self,filePath,fileName):
self.playList.addMedia(QMediaContent(QUrl.fromLocalFile(filePath)))
self.createItem(fileName)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
音频设置
#音频设置
def sltAudio(self):
pos = self.pushButton_audio.mapTo(self,QPoint(0,0)) #获取相对主窗口坐标 #计算 X ,Y
x = pos.x() + self.pushButton_audio.width()/2 - self.audio.width() / 2
y = pos.y() - self.audio.height() - 6
self.audio.move(x,y)
if self.audio.isHidden() == True: self.audio.show()
else: self.audio.hide()
def sltSetAudioValue(self,value): #设置音量值
self.player.setVolume(value)
def sltSetAudioMute(self): #设置静音
self.player.setMuted(bool(1 - self.player.isMuted()))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
播放列表
QMediaPlayList
#播放列表初始化 - 声明/定义/播放模式设置
def playListInit(self):
self.playList = QMediaPlaylist()
self.player.setPlaylist(self.playList) #播放器绑定播放列表
self.playList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) #设置播放模式
self.player.positionChanged.connect(self.sltShowPlayTime) #显示播放位置即进度
- 1
- 2
- 3
- 4
- 5
- 6
添加列表文件
#创建QListWidgetItem
def createItem(self,str):
self.item = QListWidgetItem(str)
self.listWidget_playlist.addItem(self.item)
#绑定QPlayList与QListWidget -- 利用playlist与widgetlist 的 index 索引 一一对应即实现绑定
def bindPlaylistAnddListWidget(self):
self.listWidget_playlist.itemDoubleClicked.connect(self.doublePressPlayMedia)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
ListWidget-双击播放
def doublePressPlayMedia(self,item):
self.player.stop()
self.playList.setCurrentIndex(self.listWidget_playlist.row(item))
self.player.play()
self.pushButton_play.setText("暂停")
- 1
- 2
- 3
- 4
- 5
ListWidget-右键菜单
def listWidgetRightMenu(self,point):
self.menu = QMenu(self.listWidget_playlist)
self.currentItem = self.listWidget_playlist.itemAt(point)
play_action = QAction('播放')
del_action = QAction('删除')
self.menu.addAction(play_action)
self.menu.addAction(del_action)
play_action.triggered.connect(self.actionPlay)
del_action.triggered.connect(self.actionDel)
self.menu.exec(QCursor.pos())
#右键播放槽函数
def actionPlay(self):
self.player.stop()
self.playList.setCurrentIndex(self.listWidget_playlist.row(self.currentItem))
self.player.play()
self.pushButton_play.setText("暂停") #右键删除槽函数
def actionDel(self):
index = self.listWidget_playlist.row(self.currentItem)
if index == self.playList.currentIndex(): self.player.stop()
self.delCurrentIndex(index)
def delCurrentIndex(self,index):
current = self.playList.currentIndex()
if current == index: self.playList.setCurrentIndex(0) self.player.stop()
self.playList.removeMedia(index)
self.listWidget_playlist.takeItem(index)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
播放设置
播放状态设置
def sltPlayState(self):
if self.player.state() == QMediaPlayer.StoppedState or self.player.state() == QMediaPlayer.PausedState: self.player.play() self.pushButton_play.setText("暂停")
else: self.player.pause() self.pushButton_play.setText("播放")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
上一首、下一首
def sltPlayBefore(self):
self.player.stop()
self.playList.setCurrentIndex((self.playList.currentIndex()-1 < 0) and 0 or self.playList.currentIndex()-1 )
self.player.play()
def sltPlayNext(self):
self.player.stop()
self.playList.setCurrentIndex((self.playList.currentIndex() + 1 == self.playList.mediaCount()) and 0 or (self.playList.currentIndex() + 1))
self.player.play()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
播放进度
#显示播放时长
def sltShowPlayTime(self,postion):
self.lcdNumber_progress.display(round(postion/1000))
- 1
- 2
- 3
配置文件
配置文件格式
config = {'playlist':[],'playCurrent':{'index':0,'audio':30,'postion':0}}
- 1
{
"playlist": [{
"filepath": "D:/13-\u5c0f\u53ef\u7231/df839b27228fa56f81925bd3a619dc96.mp4",
"filename": "df839b27228fa56f81925bd3a619dc96"
}, {
"filepath": "D:/13-\u5c0f\u53ef\u7231/1569254169777.mp4",
"filename": "1569254169777"
}, {
"filepath": "D:/13-\u5c0f\u53ef\u7231/1569254169777.mp4",
"filename": "1569254169777"
}],
"playCurrent": {
"index": 0,
"audio": 30,
"postion": 2.035
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
读取配置文件
#配置文件初始化
def readConfig(self):
file = open("./config.json","r+",encoding='UTF-8')
json_str_str = json.load(file)
for fileInfo in json_str_str['playlist']: self.addFile(fileInfo["filepath"],fileInfo["filename"]) config['playlist'].append({'filepath':fileInfo["filepath"],'filename':fileInfo["filename"]})
self.playList.setCurrentIndex(json_str_str["playCurrent"]["index"])
self.audio.getSlider().setValue(json_str_str["playCurrent"]["audio"])
self.player.setVolume(json_str_str["playCurrent"]["audio"])
self.player.setPosition(json_str_str["playCurrent"]["postion"] * 1000)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
写入配置文件
#写入配置文件
def writeConfig(self):
print("Write ConfigFile!")
for i in range(0,self.playList.mediaCount()): path = "" if self.playList.media(i).canonicalUrl().isLocalFile(): path = self.playList.media(i).canonicalUrl().toLocalFile() else: path = self.playList.media(i).canonicalUrl().toString() config['playlist'][i]["filepath"] = path config['playlist'][i]["filename"] = self.listWidget_playlist.item(i).text()
config['playCurrent']['index'] = self.playList.currentIndex()
config['playCurrent']['audio'] = self.player.volume()
config['playCurrent']['postion'] = self.player.position() / 1000
with open("./config.json",'w') as f: json.dump(config,f)
#关闭事件,再退出前重写config配置文件
def closeEvent(self,event):
self.writeConfig()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
运行结果
UI布局
音频设置
本地文件导入
网络
下载
Git:https://github.com/WQuit/pyqt-qmediaplayer/tree/qmediaplayer-v0.1
CSDN:https://download.csdn.net/download/u011218356/12885123
后续
下期更新,不围着PyQt5 打转了,最近搭好了OpenCv 框架,将搭配OpenCv 进行 图像处理。
文章来源: blog.csdn.net,作者:何其不顾四月天,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/u011218356/article/details/108785986
- 点赞
- 收藏
- 关注作者
评论(0)