By , 8 Jan 2014
Introduction
When looking around the internet for a clue to implementing a simple
scrolling news ticker style panel for an application I have in production, the
samples I found all pointed to the use of Graphics.Drawstring
,
which when turned into a control flickered annoyingly no matter what I tried.
The code I will present below in my first ever submission (please be gentle!)
provides two ways that I found to overcome this. Please feel free to add/amend
and otherwise improve on my examples!
Also, I should add that there are a lot of omissions in the class, like extra properties that could be implemented and there is virtually no error trapping... I will leave that up to your individual requirements.
Implementation 1 - Text Rendering
Having started to code a control against the sample ideas I found and having
already implemented double buffering to little effect, I took a look at an
alternative way to actually draw the text to the control‘s surface and came
across theTextRenderer
class
The key area of the first implementation is to use
a TextRenderer
object instead of the
aforementionedGraphics.Drawstring
call. In the snippet
below, Gr
is a graphics object defined for the
UserControl itself, _news
is the actual string to present
in the control and the
variables X
and Y
are the starting
width and height offset of the string.
Gr.Clear(Me.BackColor) TextRenderer.DrawText(Gr, _news, Me.Font, New Point(CInt(X), CInt(Y)), Me.ForeColor)
The text is moved across the panel by manipulating the value
of X
in response to a
timer Tick
event until it is found to be less than zero
minus the length of the string itself (ie: it has disappeared off the left side
of the control) when it is reset to the starting point, the right side of the
control.
Altering the values of the timer‘s interval and a step
value _speed
allows the user to fine-tune the control for
least flicker.
The two central methods in the control respond to the initial setup
during MyBase.Load
and the timer tick response
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
Implementation 2 - Repositioning a Label
While I was looking at ways to reduce the flicker in the above code, I
considered the possibility of not redrawing the text directly at all but just
moving it, so I added a label to my UserControl, set Autosize =
True
and set its text property to the string to be shown
(_news
). By manipulating the
same X
and Y
variables as above,
having first set them to the label‘s width and height offset it was possible to
implement the same effect of a scrolling text with (to my mind) even less
flickering evident than that noticeable in the first implementation
lbl.Location = New Point(CInt(X), CInt(Y))
The full listing for implementation two is reproduced here (Note: I am
omitting the label insertion in the designer partial class, although this should
be placed on the UserControl and
named lbl
for this code to operate
correctly)
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
I will upload the full project source as a .ZIP when I can work out why I keep getting an ‘Unexpected error‘ during the upload procedure? - .ZIP now uploaded thanks to the guys at CP!
History
- v1.0 - Initial release: 27 December 2013.
- v1.01 - .ZIP upload issue resolved.
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
http://www.codeproject.com/Articles/702858/A-simple-NewsTicker-Two-implementations