作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载。

最近研究了Python的两个GUI包,Tkinter和PyQT。这两个GUI包的底层分别是Tcl/Tk和QT。相比之下,我觉得PyQT使用起来更加方便,功能也相对丰富。这一篇用PyQT实现一个视频播放器,并借此来说明PyQT的基本用法。

视频播放器

先把已经完成的代码放出来。代码基于Python 3.5:

import time
import sys from PyQt4 import QtGui, QtCore
from PyQt4.phonon import Phonon class PollTimeThread(QtCore.QThread):
"""
This thread works as a timer.
"""
update = QtCore.pyqtSignal() def __init__(self, parent):
super(PollTimeThread, self).__init__(parent) def run(self):
while True:
time.sleep(1)
if self.isRunning():
# emit signal
self.update.emit()
else:
return class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self) # media
self.media = Phonon.MediaObject(self)
self.media.stateChanged.connect(self.handleStateChanged)
self.video = Phonon.VideoWidget(self)
self.video.setMinimumSize(200, 200)
self.audio = Phonon.AudioOutput(Phonon.VideoCategory, self)
Phonon.createPath(self.media, self.audio)
Phonon.createPath(self.media, self.video) # control button
self.button = QtGui.QPushButton('选择文件', self)
self.button.clicked.connect(self.handleButton) # for display of time lapse
self.info = QtGui.QLabel(self) # layout
layout = QtGui.QGridLayout(self)
layout.addWidget(self.video, 1, 1, 3, 3)
layout.addWidget(self.info, 4, 1, 1, 3)
layout.addWidget(self.button, 5, 1, 1, 3) # signal-slot, for time lapse
self.thread = PollTimeThread(self)
self.thread.update.connect(self.update) def update(self):
# slot
lapse = self.media.currentTime()/1000.0
self.info.setText("%4.2f 秒" % lapse) def startPlay(self):
if self.path:
self.media.setCurrentSource(Phonon.MediaSource(self.path)) # use a thread as a timer
self.thread = PollTimeThread(self)
self.thread.update.connect(self.update)
self.thread.start()
self.media.play() def handleButton(self):
if self.media.state() == Phonon.PlayingState:
self.media.stop()
self.thread.terminate()
else:
self.path = QtGui.QFileDialog.getOpenFileName(self, self.button.text())
self.startPlay() def handleStateChanged(self, newstate, oldstate):
if newstate == Phonon.PlayingState:
self.button.setText('停止')
elif (newstate != Phonon.LoadingState and
newstate != Phonon.BufferingState):
self.button.setText('选择文件')
if newstate == Phonon.ErrorState:
source = self.media.currentSource().fileName()
print ('错误:不能播放:', source.toLocal8Bit().data())
print (' %s' % self.media.errorString().toLocal8Bit().data()) if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
app.setApplicationName('视频播放')
window = Window()
window.show()
sys.exit(app.exec_())

代码实现了一个有GUI窗口的应用,用来播放视频文件。视频播放利用了PyQT中的Phonon模块。此外,还有一个进程每隔一秒发出一个信号。窗口在接收到信号后,更新视频播放的时间。这个应用的效果如下:

测试运行环境为Mac OSX El Capitan。

视图部分

写完这个代码之后,我发现这个代码虽然简单,但涉及了几个重要机制,可以用PyQT的练习题。下面对代码进行一些简要的说明,首先是主程序部分:

app = QtGui.QApplication(sys.argv)
...
window = Window()
window.show()
sys.exit(app.exec_())

在PyQT程序中,QApplication是最上层的对象,指代整个GUI应用。我们在程序的一开始创建了一个应用对象,在程序最后调用exec_()来运行这个应用。sys.exit()用来要求应用的主循环结束后干净地退出程序。PyQT程序的开始和结尾都是类似的固定套路。关键就在于其间定义的QWidget对象。

我们自定义的Window类继承自QWidget。其实QWidget是所有用户界面对象的基类,并不单单指代一个窗口。表格、输入框、按钮都继承自QWidget。在一个Window对象中,我们还组合有QPushButton和QLabel这样的对象,分别代表一个按钮和一个文本框。它们通过QGridLayout的方式,布局在Window的界面上,即下面一部分代码:

# layout
layout = QtGui.QGridLayout(self)
...
layout.addWidget(self.info, 4, 1, 1, 3)
layout.addWidget(self.button, 5, 1, 1, 3)

QGridLayout把界面分成网格,并把某个视图对象附着在特定的网格位置。比如说,addWidget()(self.info, 4, 1, 1, 3)表示把一个文本框对象放在第4排、第1列的位置。该文本框纵向将占据1排,横向占据3列。这样,上下层视图的位置关系就通过布局确定了下来。除了网格式的布局,PyQT还支持其他形式的布局,如横向堆砌、纵向堆砌等等,可以进一步了解。

除了QWidget,PyQT还提供了常用的对话框,如:

self.path = QtGui.QFileDialog.getOpenFileName(self, self.button.text())

这里的QFileDialog对话框用于选择文件。对话框将访问所选文件的路径。除了文件选择,对话框还有确认对话框、文件输入对话框、色彩对话框。这些对话框实现了不少常用的GUI输入功能。通过利用这些对话框,可以减少程序员从头开发的工作量。

多线程

GUI界面的主线程通常留给应用做主循环。其他的很多工作要通过其他的线程来完成。PyQT多线程编程很简单,只需要重写QThread的run()方法就可以了:

class PollTimeThread(QtCore.QThread):
def __init__(self, parent):
super(PollTimeThread, self).__init__(parent) def run(self):
...

创建线程后,只需要调用start()方法,就可以运行:

self.thread = PollTimeThread()
...
self.thread.start() # 启动线程
...
self.thread.terminate() # 终止线程

信号与槽

GUI经常要用到异步处理。比如说点击某个按钮,然后调用相应的回调函数。QT的“信号与槽”(signal-slot)机制就是为了解决异步处理问题。我们在线程中创建了信号,并通过emit()方法来发出信号:

class PollTimeThread(QtCore.QThread):
"""
This thread works as a timer.
"""
update = QtCore.pyqtSignal() def __init__(self, parent):
super(PollTimeThread, self).__init__(parent) def run(self):
while True:
time.sleep(1)
if self.isRunning():
# emit signal
self.update.emit()
else:
return

有了信号,我们就可以给该信号连接到一个“槽”,其实就是对应于该信号的回调函数:

self.thread.update.connect(self.update)

每当信号被发出时,“槽”就会被调用。在这个例子中,就是更新视频播放时间。QT中的“信号与槽”是普遍存在的机制。一些组建如按键,预设了“点击”这样的信号,可以直接对应到“槽”。如代码中的:

self.button.clicked.connect(self.handleButton)

此外,Phonon是一个很好用的多媒体模块,使用方法也很简单,可以参考代码本身,这里不再赘述。

欢迎继续阅读“Python快速教程

Python应用03 使用PyQT制作视频播放器的更多相关文章

  1. PyQT制作视频播放器

    Python应用03 使用PyQT制作视频播放器   作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载. 最近研究了Python的两个GUI包,Tki ...

  2. Python编程使用PyQT制作视频播放器

    最近研究了Python的两个GUI包,Tkinter和PyQT.这两个GUI包的底层分别是Tcl/Tk和QT.相比之下,我觉得PyQT使用起来更加方便,功能也相对丰富.这一篇用PyQT实现一个视频播放 ...

  3. Pyqt 音视频播放器

    在寻找如何使用Pyqt做一个播放器时首先找到的是openCV2 openCV2 貌似太强大了,各种关于图像处理的事情它都能完成,如 读取摄像头.图像识别.人脸识别.  图像灰度处理 . 播放视频等,强 ...

  4. HTML5,CSS3 与 Javascript 制作视频播放器

    早一段时间,有一直研究 HTML5 和 CSS3 ,自己也做了不少 Demo ,只是 HTML5 Video 和 Audio 由于自己平时比较喜欢留意不同的播放器,因此特别想做一个自己喜欢的设计,考虑 ...

  5. 使用ALVideoPlayerSurface制作视频播放器

    头两天介绍了开源控件包alcinoe,现在利用其中的ALVideoPlayerSurface视频播放控件,实作一个视频播放器. 首先,建一个fmx项目,然后从组件面版,拖放一个TAlVideoPlay ...

  6. 利用python制作在线视频播放器遇到的一些问题

    经过前期的调研,我准备使用PyQT+PyAV+PyAudio+pillow.期间也尝试过使用ffmpeg-python,但最后还是选择了av这个更底层,自由度更大的库来完成音视频的处理.   ==== ...

  7. 小强的HTML5移动开发之路(5)——制作一个漂亮的视频播放器

    来自:http://blog.csdn.net/dawanganban/article/details/17679069 在前面几篇文章中介绍了HTML5的特点和需要掌握的基础知识,下面我们开始真正的 ...

  8. 制作VR视频播放器

    最近VR火的不要不要的,但是综合起来,VR资源最多的还是全景图片和全景视频,今天在这里给大家简单介绍一下如何用Unity制作简单的VR视频播放器. 首先找到EasyMovieTexture这个插件,A ...

  9. c# 如何制作RealPlayer 视频播放器

      c# 如何制作RealPlayer 视频播放器 主要介绍了如何使用 RealPlayer G2 Control 控件 那么我们怎么获得到这个控件呢,很简单,操作方法如下 右单击工具箱对话框的[所有 ...

随机推荐

  1. 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

    阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...

  2. .Net多线程编程—任务Task

    1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...

  3. C++中的命名空间

    一,命名空间(namespace)的基本概念以及由来 1.什么是标识符: 在C++中,标识符可以是基本的变量,类,对象,结构体,函数,枚举,宏等. 2.什么是命名空间: 所谓的命名空间是指标识符的可见 ...

  4. 用javascript 写个函数返回一个页面里共使用了多少种HTML 标签

    今天我无意间看到一个面试题: 如何用javascript 写个函数返回一个页面里共使用了多少种HTML 标签? 不知你看到 是否蒙B了,如果是我 面试,肯定脑子嗡嗡的响.... 网上搜了搜也没有找到答 ...

  5. Mybatis XML配置

    Mybatis常用带有禁用缓存的XML配置 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE ...

  6. bzoj1723--前缀和(水题)

    题目大意: 你难以想象贝茜看到一只妖精在牧场出现时是多么的惊讶.她不是傻瓜,立即猛扑过去,用她那灵活的牛蹄抓住了那只妖精.     "你可以许一个愿望,傻大个儿!"妖精说.     ...

  7. Android之SQLite数据存储

    一.SQLite保存数据介绍 将数据库保存在数据库对于重复或者结构化数据(比如契约信息)而言是理想之选.SQL数据库的主要原则之一是架构:数据库如何组织正式声明.架构体现于用于创建数据库的SQL语句. ...

  8. linux常用命令(1)cd命令

    1 命令格式:cd [目录名]2 命令功能切换当前目录至dirName3 常用范例3.1 进入系统根目录cd /3.2 进入上级目录cd ..   或者 cd ..//3.3 进入当前用户主目录当前用 ...

  9. 机器指令翻译成 JavaScript —— No.7 过渡语言

    上一篇,我们决定使用 LLVM 来优化程序,并打算用 C 作为输入语言.现在我们来研究一下,将 6502 指令转换成 C 的可行性. 跳转支持 翻译成 C 语言,可比 JS 容易多了.因为 C 支持 ...

  10. 使用C# 和Consul进行分布式系统协调

    随着大数据时代的到来,分布式是解决大数据问题的一个主要手段,随着越来越多的分布式的服务,如何在分布式的系统中对这些服务做协调变成了一个很棘手的问题.今天我们就来看看如何使用C# ,利用开源对分布式服务 ...