天天看點

pyqt5-滾動條

滾動字幕的視覺效果

網上有很多部落格介紹了滾動字幕的實作方法,懂得都懂,大部是 ​

​Ctrl C​

​ + ​

​Ctrl V​

​,效果還很差,最後還是得靠自己。主要思路就是通過定時器定時重新整理+繪制兩段完整的字元串來達到 蒙蔽雙眼 滾動的效果,具體效果如下圖所示

​​

pyqt5-滾動條
具體實作方式

ScrollTextWindow 類

視窗 ​

​ScrollTextWindow​

​ 上顯示歌名和歌手名。通過 ​

​QFontMetrics​

​ 來計算歌名和歌手名字元串的寬度,選出最大者,再和視窗最大寬度作比較,以設定視窗寬度并決定是否啟用滾動效果。在構造函數裡面設定了一個 ​

​spacing​

​ 屬性,用來隔開兩段相同的字元串,還設定了兩個用于标志位 ​

​isSongNameAllOut​

​ 和 ​

​isSongerNameAllOut​

​ 來标記字元串是否已經全部移出過視窗,這兩個标志位很重要,沒弄好标志位的話之後會出現字元串位置的跳變。前面說過,實作滾動效果就是靠繪制兩段相同的字元串,是以這兩段字元串的第一個字元的橫坐标就很重要,通過設定的标志位​

​isXXXAllOut​

​、​

​spacing​

​、定時器的溢出次數 ​

​currentIndex​

​ 以及字元串的移動步長 ​

​moveStep​

​ 來決定這兩個字元串的的橫坐标,具體代碼如下:

複制import sys

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont, QFontMetrics, QPainter,QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QWidget


class ScrollTextWindow(QWidget):
""" 滾動字幕 """

def __init__(self, songName, songerName, parent=None):
super().__init__(parent)
self.songName = songName
self.songerName = songerName
# 執行個體化定時器
self.timer = QTimer(self)
# 設定重新整理時間和移動距離
self.timeStep = 20
self.moveStep = 1
self.songCurrentIndex = 0
self.songerCurrentIndex = 0
# 設定字元串溢出标志位
self.isSongNameAllOut = False
self.isSongerNameAllOut = False
# 設定兩段字元串之間留白的寬度
self.spacing = 25
# 初始化界面
self.initWidget()

def initWidget(self):
""" 初始化界面 """
self.setFixedHeight(115)
self.setAttribute(Qt.WA_StyledBackground)
# 調整視窗寬度
self.adjustWindowWidth()
# 初始化定時器
self.timer.setInterval(self.timeStep)
self.timer.timeout.connect(self.updateIndex)
# 隻要有一個字元串寬度大于視窗寬度就開啟滾動:
if self.isSongerNameTooLong or self.isSongNameTooLong:
self.timer.start()

def getTextWidth(self):
""" 計算文本的總寬度 """
songFontMetrics = QFontMetrics(QFont('Microsoft YaHei', 14, 400))
self.songNameWidth = songFontMetrics.width(self.songName)
songerFontMetrics = QFontMetrics(QFont('Microsoft YaHei', 12, 500))
self.songerNameWidth = songerFontMetrics.width(self.songerName)

def adjustWindowWidth(self):
""" 根據字元串長度調整視窗寬度 """
self.getTextWidth()
maxWidth = max(self.songNameWidth, self.songerNameWidth)
# 判斷是否有字元串寬度超過視窗的最大寬度
self.isSongNameTooLong = self.songNameWidth > 250
self.isSongerNameTooLong = self.songerNameWidth > 250
# 設定視窗的寬度
self.setFixedWidth(min(maxWidth, 250))

def updateIndex(self):
""" 更新下标 """
self.update()
self.songCurrentIndex += 1
self.songerCurrentIndex += 1
# 設定下标重置條件
resetSongIndexCond = self.songCurrentIndex * \
self.moveStep >= self.songNameWidth + self.spacing * self.isSongNameAllOut
resetSongerIndexCond = self.songerCurrentIndex * \
self.moveStep >= self.songerNameWidth + self.spacing * self.isSongerNameAllOut
# 隻要條件滿足就要重置下标并将字元串溢出置位,保證在字元串溢出後不會因為留出的空白而發生跳變
if resetSongIndexCond:
self.songCurrentIndex = 0
self.isSongNameAllOut = True
if resetSongerIndexCond:
self.songerCurrentIndex = 0
self.isSongerNameAllOut = True

def paintEvent(self, e):
""" 繪制文本 """
# super().paintEvent(e)
painter = QPainter(self)
painter.setPen(Qt.white)
# 繪制歌名
painter.setFont(QFont('Microsoft YaHei', 14))
if self.isSongNameTooLong:
# 實際上繪制了兩段完整的字元串
# 從負的橫坐标開始繪制第一段字元串
painter.drawText(self.spacing * self.isSongNameAllOut - self.moveStep *
self.songCurrentIndex, 54, self.songName)
# 繪制第二段字元串
painter.drawText(self.songNameWidth - self.moveStep * self.songCurrentIndex +
self.spacing * (1 + self.isSongNameAllOut), 54, self.songName)
else:
painter.drawText(0, 54, self.songName)

# 繪制歌手名
painter.setFont(QFont('Microsoft YaHei', 12, 500))
if self.isSongerNameTooLong:
painter.drawText(self.spacing * self.isSongerNameAllOut - self.moveStep *
self.songerCurrentIndex, 82, self.songerName)
painter.drawText(self.songerNameWidth - self.moveStep * self.songerCurrentIndex +
self.spacing * (1 + self.isSongerNameAllOut), 82, self.songerName)
else:
painter.drawText(0, 82, self.songerName)
      

SongInfoCard 類

父級視窗 ​

​SongInfoCard​

​ 用來顯示專輯封面和滾動字幕,代碼如下:

複制class SongInfoCard(QWidget):
""" 播放欄左側歌曲資訊卡 """

def __init__(self, songInfo: dict, parent=None):
super().__init__(parent)
# 儲存資訊
self.songInfo = songInfo
self.songName = self.songInfo['songName']
self.songerName = self.songInfo['songer']
# 執行個體化小部件
self.albumPic = QLabel(self)
self.scrollTextWindow = ScrollTextWindow(
self.songName, self.songerName, self)
# 初始化界面
self.initWidget()

def initWidget(self):
""" 初始化小部件 """
self.setFixedHeight(115)
self.setFixedWidth(115 + 15 + self.scrollTextWindow.width() + 25)
self.setAttribute(Qt.WA_StyledBackground)
self.setWindowFlags(Qt.FramelessWindowHint)
self.scrollTextWindow.move(130, 0)
self.albumPic.setPixmap(QPixmap(self.songInfo['album'][-1]).scaled(
115, 115, Qt.KeepAspectRatio, Qt.SmoothTransformation))

if __name__ == "__main__":
app = QApplication(sys.argv)
songInfo = {
'songName': 'ハッピーでバッドな眠りは淺い', 'songer': '鎖那',
'album': [r'resource\Album Cover\ハッピーでバッドな眠りは淺い\ハッピーでバッドな眠りは淺い.png']}
demo = SongInfoCard(songInfo)
demo.setStyleSheet('background:rgb(129,133,137)')
demo.show()
sys.exit(app.exec_())

      

繼續閱讀