wxPython 实现滚动字幕效果
过年在家刷视频号直播时发现弹幕互动游戏,挺有意思的,刚好诠释了“反射”(一种基于字符串的事件驱动)的用法。想要自己也做一个弹幕游戏,于是就有了这个基本的需求,先让弹幕滚动显示出来,直播时可以当作小挂件。
滚动文字功能
先查 API 文档和 demo 看有没相应的控件和例子,发现 wxPython 有滚动文字控件 wx.lib.ticker.Ticker (Ticker翻译:滚动条;收报机;心脏;跑马灯;断续器)。
类签名:
wx.lib.ticker.Ticker(parent, id=-1, text="", fgcolor = wx.BLACK, bgcolor = wx.WHITE, start=True, ppf=2, fps=20, direction="rtl", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.NO_BORDER, name="Ticker")
参数:
parent (wx.Window) – the parent
id (integer) – an identifier for the control: a value of -1 is taken to mean a default
text (string) – text in the ticker
fgcolor (wx.Colour) – text/foreground color
bgcolor (wx.Colour) – background color
start (boolean) – if True, the ticker starts immediately
ppf (int) – pixels per frame
fps (int) – frames per second
direction – direction of ticking, ‘rtl’ or ‘ltr’
pos (wx.Point) – the control position. A value of (-1, -1) indicates a default position, chosen by either the windowing system or wxPython, depending on platform
name – the control name
看看效果:

源码:
# -*- coding: utf-8 -*-
import wx
from wx.lib.ticker import Ticker
class MyFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MyFrame, self).__init__(*args, **kwargs)
self.Center()
self.ticker = Ticker(parent=self, id=-1, text="你好,世界!Hello World!😍 ",
fgcolor="#ff0000", bgcolor="#fff000", start=True,
ppf=2, fps=20, direction="rtl",
pos=wx.DefaultPosition, size=self.GetClientSize(), style=wx.NO_BORDER,
name="Ticker")
self.ticker.SetFont(wx.Font(18, family=wx.SWISS, style=wx.NORMAL, weight=wx.BOLD, faceName=u"宋体"))
self.ticker.Start()
self.ticker.Bind(wx.EVT_RIGHT_UP, self.OnClose)
self.ticker.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.ticker.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.ticker.Bind(wx.EVT_MOTION, self.OnMouseMove)
def OnClose(self, event):
self.Close()
def OnLeftDown(self, evt):
# CaptureMouse 把所有鼠标输入指向 self.ticker 控件窗口
self.ticker.CaptureMouse()
# ClientToScreen 把鼠标位置相对于程序窗口的坐标转换为相对于屏幕的坐标
x, y = self.ClientToScreen(evt.GetPosition())
originx, originy = self.GetPosition()
dx = x - originx
dy = y - originy
self.delta = ((dx, dy))
def OnLeftUp(self, evt):
if self.ticker.HasCapture():
self.ticker.ReleaseMouse()
def OnMouseMove(self, evt):
if evt.Dragging() and evt.LeftIsDown():
x, y = self.ClientToScreen(evt.GetPosition())
fp = (x - self.delta[0], y - self.delta[1])
# Move 将窗口移动到指定坐标
self.Move(fp)
class App(wx.App):
def OnInit(self):
frame = MyFrame(parent=None, size=(1075, 53), style=wx.NO_BORDER)
frame.Show()
return True
def OnExit(self):
return 0
if __name__ == "__main__":
app = App()
app.MainLoop()
滚动文字衔接问题
滚动循环,文字需要全部滚出才会重新滚入,有空白期。

原 Ticker 类中,滚动文字是用属性 self._text 来存储的,它是一个字符串。如果在字符串尾部附加其他新的字符串,并不能解决显示衔接问题,而且不便对指定字符串进行修改。那么直接继承 Ticker ,把 _text 改成 list,并修改相应方法。
本来是想像做动画一样,将 _text 复制一份,轮流滚动。但是因为后期还要动态添加字符串,并且不应该把所有文字都显示出来。
所以最后想到的解决办法是:另设一个列表 _show_text 用于存储要显示的字符串,_index 表示最后从 _text 添加到 _show_text 的字符串的_text 索引。 当 _show_text 头部节点滚出显示区时,从列表中去除,当尾节点尾部与显示区尾部相距超过设定间距时,则把 _text[_index+1] 附加到 _show_text。

效果,录像 GIF 帧率是 30 FPS:

源码:
# -*- coding: utf-8 -*-
# Author: SmileBasic
import wx
import wx.lib.ticker
class Ticker(wx.lib.ticker.Ticker):
def __init__(self, *args, **kwargs)

文章介绍了如何使用wxPython的Ticker控件创建滚动字幕效果,并讨论了在滚动文字衔接上遇到的问题。作者通过修改Ticker类,解决了文字空白期问题,实现了更平滑的滚动。此外,还探讨了使用双端队列优化显示性能的可能性,但考虑到特定场景下的效率和需求,最终选择了保留列表结构并优化处理方式。
最低0.47元/天 解锁文章
346

被折叠的 条评论
为什么被折叠?



