一个简单的 NewsTicker - 两种实现方式





4.00/5 (8投票s)
为 Winforms .NET 实现一个简单的自定义新闻滚动条控件,以最大限度地减少闪烁。
引言
在网上寻找实现一个简单的滚动式新闻滚动条面板的线索时,我发现的示例都指向使用`Graphics.Drawstring`,无论我尝试什么,将其转换为控件后都会令人讨厌地闪烁。我在我的第一次提交(请温柔!)中将要展示的代码提供了两种我发现可以克服这个问题的方法。请随意添加/修改并改进我的示例!
另外,我应该补充一点,这个类有很多遗漏,例如可以实现的额外属性,而且几乎没有错误处理……我将把它留给你们的个人需求。
实现 1 - 文本渲染
在开始根据我找到的示例想法编写控件代码,并且已经实现了双缓冲但效果不佳之后,我查看了另一种实际将文本绘制到控件表面的方法,并发现了`TextRenderer`类。
第一个实现的关键部分是使用`TextRenderer`对象而不是前面提到的`Graphics.Drawstring`调用。在下面的代码片段中,`Gr`是为 UserControl 本身定义的图形对象,`_news`是要在控件中呈现的实际字符串,变量`X`和`Y`是字符串的起始宽度和高度偏移量。
Gr.Clear(Me.BackColor)
TextRenderer.DrawText(Gr, _news, Me.Font, New Point(CInt(X), CInt(Y)), Me.ForeColor)
通过响应计时器`Tick`事件来操作`X`的值来移动面板上的文本,直到发现它小于零减去字符串本身的长度(即:它已消失在控件的左侧)时,将其重置为起始点,即控件的右侧。
更改计时器间隔和步长值`_speed`的值,允许用户微调控件以获得最少的闪烁。
控件中的两个核心方法响应`MyBase.Load`期间的初始设置和计时器滴答响应。
Private Sub SetupWindow()
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Gr = Me.CreateGraphics()
X = Me.Width
Me.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
Me.Dock = DockStyle.Bottom
_strSize = Gr.MeasureString(_news, Me.Font)
If (Me.Height < _strSize.Height + 4) Then Me.Height = CInt(_strSize.Height) + 4
Timer.Interval = 25
Timer.Start()
End Sub
Private Sub UpdateDisplay()
Dim tHeight As Double = _strSize.Height
Select Case Me.TextPosition
Case TextPlacement.Top : Y = 0
Case TextPlacement.Middle : Y = CSng((Me.Height / 2) - (tHeight / 2))
Case TextPlacement.Bottom : Y = CSng(Me.Height - tHeight)
End Select
Gr.Clear(Me.BackColor)
TextRenderer.DrawText(Gr, _news, Me.Font, New Point(CInt(X), CInt(Y)), Me.ForeColor)
If X <= (0 - _strSize.Width) Then
X = Me.Width
Else
X = CSng(X - _speed)
End If
End Sub
实现 2 - 重新定位标签
在我寻找减少上述代码中闪烁的方法时,我考虑了根本不直接重绘文本,而只是移动它的可能性,所以我向我的 UserControl 添加了一个标签,设置`Autosize = True`并将它的文本属性设置为要显示的字符串(`_news`)。通过操作与上面相同的`X`和`Y`变量,首先将它们设置为标签的宽度和高度偏移量,可以实现相同的滚动文本效果,在我看来,闪烁比第一个实现中明显的闪烁还要少。
lbl.Location = New Point(CInt(X), CInt(Y))
这里复制了第二个实现的完整列表(注意:我省略了设计器局部类中的标签插入,尽管这应该放在 UserControl 上并命名为`lbl`才能使此代码正常运行)。
Public Class NewsTicker
Inherits System.Windows.Forms.UserControl
Enum TextPlacement
Top
Middle
Bottom
End Enum
Dim X As Single
Dim Y As Single
Dim Gr As Graphics
Dim _news As String = "There is no news to display at this time"
Dim _strSize As SizeF
Private _tpos As TextPlacement = TextPlacement.Top
Private _speed As Double = 1.0
Private Sub NewsTicker_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
SetupWindow()
End Sub
Private Sub NewsTicker_Resize(sender As Object, e As System.EventArgs) Handles Me.Resize
SetupWindow()
End Sub
Private Sub Timer_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer.Tick
UpdateDisplay()
End Sub
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
lbl.Height = Me.Height - 4
lbl.Text = _news
lbl.AutoSize = True
lbl.Location = New Point(Me.Width, 0)
Me.Dock = DockStyle.Bottom
Me.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
X = Me.Width
If (Me.Height < lbl.Height + 4) Then Me.Height = CInt(lbl.Height) + 4
Timer.Interval = 25
Timer.Start()
End Sub
Private Sub UpdateDisplay()
Dim tHeight As Double = lbl.Height
Select Case Me.TextPosition
Case TextPlacement.Top : Y = 0
Case TextPlacement.Middle : Y = CSng((Me.Height / 2) - (tHeight / 2))
Case TextPlacement.Bottom : Y = CSng(Me.Height - tHeight)
End Select
lbl.Location = New Point(CInt(X), CInt(Y))
If X <= (0 - lbl.Width) Then
X = Me.Width
Else
X = CSng(X - _speed)
End If
End Sub
Public Property News As String
Get
Return _news
End Get
Set(value As String)
_news = value
SetupWindow()
End Set
End Property
Public Property TextPosition As TextPlacement
Get
Return _tpos
End Get
Set(value As TextPlacement)
_tpos = value
End Set
End Property
Public Property Speed As Double
Get
Return _speed
End Get
Set(value As Double)
If value < 0.01 Or value > 100 Then
Throw New ArgumentOutOfRangeException("Speed", _
"Cannot be less than 0.01 or greater than 100")
Else
_speed = value
SetupWindow()
End If
End Set
End Property
End Class
我将在弄清楚为什么我在上传过程中一直收到“意外错误”时上传完整的项目源代码作为 .ZIP 文件?——感谢 CP 的各位,.ZIP 文件现已上传!
历史
- v1.0 - 初始发布:2013 年 12 月 27 日。
- v1.01 - 已解决 .ZIP 上传问题。