由于电脑上的短视频太多了,并且分别存放在各个子目录下,每次更新后想要整理视频比较麻烦,因此想用Python编写程序来辅助管理视频文件。其实写个Python脚本程序即可实现大器的需求,但为了多练习PyQt和交互的方便,还是编写个桌面程序更易于使用。
本程序的主要功能代码实际上是比较少的,大部分代码都是辅助界面设计和控件交互逻辑的。
def playVideo(self):
'''查找符合条件的视频并播放'''
day_secs = 24*60*60
NOW = time.time() # 当前时间戳
# 扫描指定目录的视频文件
files = []
for d in self.dirs:
if d[-1] not in ('\', '/'):
d += '/'
files += glob(d + '**/*.mp4', recursive=True)
# 过滤指定时间范围内的文件
recent = {}
for file in files:
if '创建时间' in self.timeAttr.currentText():
stamp = os.path.getctime(file)
else:
stamp = os.path.getmtime(file)
condition = self.timeRange.currentText()
span = int(condition.strip('过去天')) * day_secs
if stamp > NOW - span:
recent[stamp] = file
# 文件按创建时间倒序排序
files = [recent[k] for k in sorted(recent, reverse=True)]
# 创建播放列表
if not files:
return
with open(self.listFile, 'w', encoding='utf-8') as fp:
fp.write('n'.join(files))
# 调用外部播放器打开播放列表
subprocess.Popen([self.player.text(), self.listFile])
值得一提的是,这里调用外部程序用的是subprocess.Popen(),也可以用os.system()代替。通常在执行os.system()函数时会阻塞它的调用者,直到所启动的命令行程序退出,此问题可以通过以下方式解决。
在linux平台上需要在命令末尾加上shell后台运算符&:
os.system('python test.py &')
在windows中用DOS的start命令使命令并行启动:
os.system('start python test.py')
def _centerOnScreen(self):
'''窗口在屏幕居中'''
screen = QDesktopWidget().screenGeometry()
size = self.geometry()
x = (screen.width() - size.width()) / 2
y = (screen.height() - size.height()) / 2
self.move(int(x), int(y))
如果需要将窗口设置稍微偏上一点,可以修改y的计算值,比如将2修改为3,根据自己的偏好进行调整。
在关闭程序前,有时需要对设置数据进行保存或者对临时文件进行清理。PyQt5虽然内置了很多信号,但对于此需求却爱莫能助,需要我们自定义信号。可以使用pyqtSignal()方法定义新的信号,信号的定义需要放在__init__()之前作为类的属性。
在界面类中重载closeEvent事件,发射自定义的退出信号,然后将此信号连接到槽函数(自定义的处理方法)。
class View(QWidget):
'''应用图形界面'''
closing = pyqtSignal() # 窗口关闭信号
def __init__(self):
super(View, self).__init__()
self.setWindowTitle('最新短视频查看器')
# 省略部分代码
def closeEvent(self, event):
'''关闭前发送信号清理临时文件'''
self.closing.emit()
event.accept()
Qt的布局管理器非常的强大和方便,各种布局都可以相互嵌套。如果指定了stretch=1,那么此控件会根据布局的空间进行自动调整长度或者高度(取决于是横向布局还是纵向布局)。以下控件定义和布局是通过代码实现,未使用Qt界面设计工具,简单的界面推荐直接用代码定义。
def _createWidgets(self):
'''创建窗口部件'''
layout = QHBoxLayout(self) # 全局布局
layout.setContentsMargins(18, 12, 18, 12)
l1 = QVBoxLayout()
self.dirList = QListWidget()
self.player = QLineEdit()
l11 = QHBoxLayout()
self.label1 = QLabel('时间范围')
self.timeRange = QComboBox()
self.label2 = QLabel('排序依据')
self.timeAttr = QComboBox()
l11.addWidget(self.label1)
l11.addWidget(self.timeRange,stretch=1)
l11.addSpacing(20)
l11.addWidget(self.label2)
l11.addWidget(self.timeAttr, stretch=1)
l1.addWidget(self.dirList)
l1.addWidget(self.player)
l1.addLayout(l11)
l2 = QVBoxLayout()
self.add = QPushButton('添加路径')
self.remove = QPushButton('移除路径')
self.openPath = QPushButton('选择播放器')
self.play = QPushButton('查找并播放')
l2.addWidget(self.add)
l2.addWidget(self.remove)
l2.addStretch()
l2.addWidget(self.openPath)
l2.addWidget(self.play)
layout.addLayout(l1)
layout.addLayout(l2)
PyQt的信号和槽函数的连接非常简洁方便,不同于C++的冗长。
def _connectSignals(self):
'''连接信号和槽'''
self.add.clicked.connect(self.addDir)
self.remove.clicked.connect(self.rmDir)
self.openPath.clicked.connect(self.openPlayerPath)
self.play.clicked.connect(self.playVideo)
self.closing.connect(self.saveConfig)
根据指定路径和文件读取配置,如果文件不存在则创建新的配置文件,用于记录当前使用的扫描目录和播放器的路径,这样下次运行程序时无需重新添加路径。
def loadConfig(self):
'''导入配置数据'''
self.config = ConfigObj(self.configFile, encoding='utf-8')
try:
self.dirs = self.config['程序设置']['扫描路径']
self.dirList.addItems(self.dirs)
self.player.setText(self.config['程序设置']['播放器路径'])
except KeyError:
self.config['程序设置'] = {}
self.config['程序设置']['扫描路径'] = []
self.config['程序设置']['播放器路径'] = ''
self.dirs = self.config['程序设置']['扫描路径']
总体而言,本程序还是比较简单的,基本实现了大器的需求。还有一点可以改进的是,由于扫描文件比较多时可能耗时比较长,程序界面会有几秒时间显示程序无响应,影响使用体验。可以将这部分另开一个线程处理,处理完再触发信号通知播放器播放文件。由于文章篇幅有限,未贴出全部代码,需要完整代码的可以关注后私信大器。
我是大器,正在建立自己的知识库,并将这些经验分享给你,请关注我,一起交流学习。