PyQt5 实现滚动字幕效果且字幕可以更新 可直接简单套用(甚至无需理解)

Pyqt5实现滚动字幕效果

效果演示

话不多说先看效果
在这里插入图片描述

当然,这里我只是简单演示了一下效果,你只需要在我的代码上改动对应的变量,你可以把它按照自己的想法改为新的形式

本文参考了此篇博客:
参考博客

代码讲解

可以直接套用的滚动字幕的class
这里是做的滚动字幕的类,你可以直接把这部分放在你项目里用,具体细节部分可以直接看代码注释
你可以改对应的代码,调整字体、速度、颜色等等
每次更改字幕内容时,只需要调用setText()函数就行了,具体可看我后面的调用方法

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys

class ScrollTextWindow(QWidget):
    """ 滚动字幕 """
    def __init__(self, parent=None):
        super().__init__(parent)
        # 设置两段字符串之间留白的宽度
        self.spacing = 100
        # 滚动字幕字体选择
        self.font_style = QFont('Microsoft YaHei', 14, 400)
        self.max_len_text = 400
        # 设置刷新时间和移动距离
        self.timeStep = 20
        self.moveStep = 1
        """ 初始化界面 """
        self.setFixedHeight(115)
        self.setAttribute(Qt.WA_StyledBackground)

        # 下面这部分只是初始化,显示字幕具体内容在setText决定
        # 初始化Text为空
        self.Text = ''
        # 实例化定时器
        self.timer_label = QTimer(self)
        self.TextCurrentIndex = 0
        # 设置字符串溢出标志位
        self.isTextAllOut = False

    def setText(self,Text):
        self.Text = Text
        # 加上下一句是放置更新字幕后之前的timer依旧存在,导致滚动越来越快,不信你可以删了试试
        self.timer_label.deleteLater()
        self.timer_label = QTimer(self)
        self.TextCurrentIndex = 0
        # 设置字符串溢出标志位
        self.isTextAllOut = False
        # 调整窗口宽度
        self.adjustWindowWidth()
        # 初始化定时器
        self.timer_label.setInterval(self.timeStep)
        self.timer_label.timeout.connect(self.updateIndex)
        # 只要有一个字符串宽度大于窗口宽度就开启滚动:
        if self.isTextTooLong:
            self.timer_label.start()

    def move_pose(self,object):
        x,y,w,h = object.x(), object.y(), object.width(), object.height()
        self.move(x+w*0.02, y-h*0.6)  # 移动字幕条的位置,让他处于label框内
        self.max_len_text = w*0.96  # 让字幕显示在框里(略小)

    def getTextWidth(self):
        """ 计算文本的总宽度 """
        songFontMetrics = QFontMetrics(self.font_style)
        self.TextWidth = songFontMetrics.width(self.Text)

    def adjustWindowWidth(self):
        """ 根据字符串长度调整窗口宽度 """
        self.getTextWidth()
        maxWidth = self.TextWidth
        # 判断是否有字符串宽度超过设定的滚动阈值
        self.isTextTooLong = self.TextWidth > self.max_len_text
        # 设置窗口的宽度
        self.setFixedWidth(min(maxWidth, self.max_len_text))

    def updateIndex(self):
        """ 更新下标 """
        self.update()
        self.TextCurrentIndex += 1
        # 设置下标重置条件
        resetTextIndexCond = self.TextCurrentIndex * self.moveStep >= self.TextWidth + self.spacing * self.isTextAllOut
        # 只要条件满足就要重置下标并将字符串溢出置位,保证在字符串溢出后不会因为留出的空白而发生跳变
        if resetTextIndexCond:
            self.TextCurrentIndex = 0
            self.isTextAllOut = True

    def paintEvent(self, e):
        """ 绘制文本 """
        # super().paintEvent(e)
        painter = QPainter(self)
        painter.setPen(Qt.black)
        # 绘制歌名
        painter.setFont(self.font_style)
        if self.isTextTooLong:
            # 实际上绘制了两段完整的字符串
            # 从负的横坐标开始绘制第一段字符串
            painter.drawText(self.spacing * self.isTextAllOut - self.moveStep *
                             self.TextCurrentIndex, 54, self.Text)
            # 绘制第二段字符串
            painter.drawText(self.TextWidth - self.moveStep * self.TextCurrentIndex +
                             self.spacing * (1 + self.isTextAllOut), 54, self.Text)
        else:
            painter.drawText(0, 54, self.Text)

滚动字幕类的调用方法
这里滚动字幕class的输入有一个self.label就是一个Qlabel对象,主要是想实现在滚动字幕外面有一个框,对于滚动字幕的class只有一个辅助定位的作用(详见move_pose()函数)。如果你不想按照这样的方法做,你可以改滚动字幕class里面的move_pose()函数,自己给他一个确定的位置就行了

这里我绑定了一个按钮事件,每次按下按钮就会执行show_another()函数,这个就会改变显示的内容

class Test_window(QtWidgets.QMainWindow, Test_UI.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Test_window, self).__init__(parent)
        self.setupUi(self)
        # 设置边框样式
        self.label.setFrameShape(QtWidgets.QFrame.Box)
        # 设置阴影 据说只有加了这步才能设置边框颜色。///可选样式有Raised、Sunken、Plain(这个无法设置颜色)等
        self.label.setFrameShadow(QtWidgets.QFrame.Raised)
        # 设置边框样式
        self.label.setStyleSheet('border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);')
        self.label.setText('')
        self.pushButton.clicked.connect(self.show_another)
        text = '字幕短的时候不滚动'
        # self.show_move_new(text)
        self.scrollTextWindow = ScrollTextWindow(self)
        self.scrollTextWindow.move_pose(self.label)
        self.scrollTextWindow.setText(text)

    def show_another(self):
        text = '字幕长的时候就滚动 哈哈哈哈哈哈'
        self.scrollTextWindow.setText(text)

完整代码

想要直接跑我刚才的效果,创建一个python文件,复制如下代码
这里import Test_UI是调用用qtdesigner做的界面生成的代码,直接见后面的Test_UI.py文件
有这两个文件,直接跑test.py就行了
test.py

import Test_UI
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys

class ScrollTextWindow(QWidget):
    """ 滚动字幕 """
    def __init__(self, parent=None):
        super().__init__(parent)
        # 设置两段字符串之间留白的宽度
        self.spacing = 100
        # 滚动字幕字体选择
        self.font_style = QFont('Microsoft YaHei', 14, 400)
        self.max_len_text = 400
        # 设置刷新时间和移动距离
        self.timeStep = 20
        self.moveStep = 1
        """ 初始化界面 """
        self.setFixedHeight(115)
        self.setAttribute(Qt.WA_StyledBackground)

        # 下面这部分只是初始化,显示字幕具体内容在setText决定
        # 初始化Text为空
        self.Text = ''
        # 实例化定时器
        self.timer_label = QTimer(self)
        self.TextCurrentIndex = 0
        # 设置字符串溢出标志位
        self.isTextAllOut = False

    def setText(self,Text):
        self.Text = Text
        # 加上下一句是放置更新字幕后之前的timer依旧存在,导致滚动越来越快,不信你可以删了试试
        self.timer_label.deleteLater()
        self.timer_label = QTimer(self)
        self.TextCurrentIndex = 0
        # 设置字符串溢出标志位
        self.isTextAllOut = False
        # 调整窗口宽度
        self.adjustWindowWidth()
        # 初始化定时器
        self.timer_label.setInterval(self.timeStep)
        self.timer_label.timeout.connect(self.updateIndex)
        # 只要有一个字符串宽度大于窗口宽度就开启滚动:
        if self.isTextTooLong:
            self.timer_label.start()

    def move_pose(self,object):
        x,y,w,h = object.x(), object.y(), object.width(), object.height()
        self.move(x+w*0.02, y-h*0.6)  # 移动字幕条的位置,让他处于label框内
        self.max_len_text = w*0.96  # 让字幕显示在框里(略小)

    def getTextWidth(self):
        """ 计算文本的总宽度 """
        songFontMetrics = QFontMetrics(self.font_style)
        self.TextWidth = songFontMetrics.width(self.Text)

    def adjustWindowWidth(self):
        """ 根据字符串长度调整窗口宽度 """
        self.getTextWidth()
        maxWidth = self.TextWidth
        # 判断是否有字符串宽度超过设定的滚动阈值
        self.isTextTooLong = self.TextWidth > self.max_len_text
        # 设置窗口的宽度
        self.setFixedWidth(min(maxWidth, self.max_len_text))

    def updateIndex(self):
        """ 更新下标 """
        self.update()
        self.TextCurrentIndex += 1
        # 设置下标重置条件
        resetTextIndexCond = self.TextCurrentIndex * self.moveStep >= self.TextWidth + self.spacing * self.isTextAllOut
        # 只要条件满足就要重置下标并将字符串溢出置位,保证在字符串溢出后不会因为留出的空白而发生跳变
        if resetTextIndexCond:
            self.TextCurrentIndex = 0
            self.isTextAllOut = True

    def paintEvent(self, e):
        """ 绘制文本 """
        # super().paintEvent(e)
        painter = QPainter(self)
        painter.setPen(Qt.black)
        # 绘制歌名
        painter.setFont(self.font_style)
        if self.isTextTooLong:
            # 实际上绘制了两段完整的字符串
            # 从负的横坐标开始绘制第一段字符串
            painter.drawText(self.spacing * self.isTextAllOut - self.moveStep *
                             self.TextCurrentIndex, 54, self.Text)
            # 绘制第二段字符串
            painter.drawText(self.TextWidth - self.moveStep * self.TextCurrentIndex +
                             self.spacing * (1 + self.isTextAllOut), 54, self.Text)
        else:
            painter.drawText(0, 54, self.Text)


class Test_window(QtWidgets.QMainWindow, Test_UI.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Test_window, self).__init__(parent)
        self.setupUi(self)
        # 设置边框样式
        self.label.setFrameShape(QtWidgets.QFrame.Box)
        # 设置阴影 据说只有加了这步才能设置边框颜色。///可选样式有Raised、Sunken、Plain(这个无法设置颜色)等
        self.label.setFrameShadow(QtWidgets.QFrame.Raised)
        # 设置边框样式
        self.label.setStyleSheet('border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);')
        self.label.setText('')
        self.pushButton.clicked.connect(self.show_another)
        text = '字幕短的时候不滚动'
        # self.show_move_new(text)
        self.scrollTextWindow = ScrollTextWindow(self)
        self.scrollTextWindow.move_pose(self.label)
        self.scrollTextWindow.setText(text)

    def show_another(self):
        text = '字幕长的时候就滚动 哈哈哈哈哈哈'
        self.scrollTextWindow.setText(text)

    def show_move_new(self,text):
        print(len(text))
        self.label.setText(text)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    test_window = Test_window()
    test_window.show()

    sys.exit(app.exec_())

Test_UI.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'Test_UI.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(230, 230, 311, 41))
        self.label.setAutoFillBackground(False)
        self.label.setTextFormat(QtCore.Qt.AutoText)
        self.label.setScaledContents(False)
        self.label.setWordWrap(False)
        self.label.setOpenExternalLinks(False)
        self.label.setObjectName("label")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(270, 460, 93, 28))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "新闻测试"))
        self.pushButton.setText(_translate("MainWindow", "切换"))

猜你喜欢

转载自blog.csdn.net/qin_liang/article/details/127580906