dcsimg

Creating a Text Scroller Control

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


Introduction

Developing programs can be a drag sometimes, especially if you must do that for a living, and even more so when certain projects are just plain boring. Luckily, I've got my articles to provide some color and excitement to my life as developer.

Today, I will show you how to create a scrolling text user control. It is a lot of work, so let's jump right in.

Create a new VB.NET or C# Windows Forms application with Visual Studio.

Add a class library to your project. This will be used as the user control. Name it something funky; keep in mind that my names may differ from yours.

Open the code file for the class that you have just created, and ensure that you inherit from UserControl, as shown next:

C#

public class clsScroll_C : System.Windows.Forms.UserControl

VB.NET

Public Class clsScroll_VB
   Inherits System.Windows.Forms.UserControl

This adds the capabilities of a UserControl, which you can override or use whenever developing controls for your forms. Add the next few Namespaces.

C#

using System.Drawing;
using System.Windows.Forms;

VB.NET

Imports System.Drawing
Imports System.Windows.Forms

Now you have added Drawing capabilities to your UserControl, as well as added ordinary Windows Forms features.

Add the following fields to your class.

C#

   private int intWidth;
   private bool[,] blnDisplay = new bool[400, 200];
   private SolidBrush sbColor = new SolidBrush(Color.Aqua);
   private bool[,] blnText;
   private int intSpeed = 8;
   private string strText = "Example";
   private System.Timers.Timer T = new System.Timers.Timer();
   private Font fFont = new Font("Arial", 10);
   private Graphics grpGraphics;

   private Bitmap bmpGrp = new Bitmap(400, 300);
   private Graphics grpG;

VB.NET

   Private intWidth As Integer
   Private blnDisplay As Boolean(,) = New Boolean(399, 199) {}
   Private sbColor As SolidBrush = New SolidBrush(Color.Aqua)
   Private blnText As Boolean(,)
   Private intSpeed As Integer = 8
   Private strText As String = "Example"
   Private T As System.Timers.Timer = New System.Timers.Timer()
   Private fFont As Font = New Font("Arial", 10)
   Private grpGraphics As Graphics
   Private bmpGrp As Bitmap = New Bitmap(400, 300)
   Private grpG As Graphics

Most of the fields above are quite self-explanatory. A few highlights are the Display array for the grid window, the size of the Graphic bitmap, and then some settings such as speed, text, color, and font. These could be used later to create separate properties to be customized by the user. Perhaps in a Part 2 of this article, this could be covered.

Add the following Properties.

C#

   public new Font ScrollFont
   {
      get
      {
         return fFont;
      }
      set
      {
         fFont = value;
         CreateArray(strText);
      }
   }

   public int ScrollSpeed
   {
      get
      {
         return intSpeed;
      }
      set
      {
         if (value < 11)
         {
            intSpeed = value;
            switch (value)
            {
               case 1:
                  T.Interval = 1000;
                  break;
               case 2:
                  T.Interval = 900;
                  break;
               case 3:
                  T.Interval = 750;
                  break;
               case 4:
                  T.Interval = 600;
                  break;
               case 5:
                  T.Interval = 400;
                  break;
               case 6:
                  T.Interval = 200;
                  break;
               case 7:
                  T.Interval = 100;
                  break;
               case 8:
                  T.Interval = 50;
                  break;
               case 9:
                  T.Interval = 25;
                  break;
               case 10:
                  T.Interval = 1;
                  break;
            }
         }
      }
   }


   public string ScrollText
   {
      get
      {
         return strText;
      }
      set
      {
         strText = value;
         CreateArray(value);
      }
   }

   public override Color ForeColor
   {
      get
      {
         return sbColor.Color;
      }
      set
      {
         sbColor = new SolidBrush(value);
      }
   }

VB.NET

   Public Overloads Property ScrollFont As Font
      Get
         Return fFont
      End Get
      Set(ByVal value As Font)
         fFont = value
         CreateArray(strText)
      End Set
   End Property

   Public Property ScrollSpeed As Integer
      Get
         Return intSpeed
      End Get
      Set(ByVal value As Integer)

         If value < 11 Then
            intSpeed = value

            Select Case value
               Case 1
                  T.Interval = 1000
               Case 2
                  T.Interval = 900
               Case 3
                  T.Interval = 750
               Case 4
                  T.Interval = 600
               Case 5
                  T.Interval = 400
               Case 6
                  T.Interval = 200
               Case 7
                  T.Interval = 100
               Case 8
                  T.Interval = 50
               Case 9
                  T.Interval = 25
               Case 10
                  T.Interval = 1
            End Select
         End If
      End Set
   End Property

   Public Property ScrollText As String
      Get
         Return strText
      End Get
      Set(ByVal value As String)
         strText = value
         CreateArray(value)
      End Set
   End Property

   Public Overrides Property ForeColor As Color
      Get
         Return sbColor.Color
      End Get
      Set(ByVal value As Color)
         sbColor = New SolidBrush(value)
      End Set
   End Property

Add the methods to create the scrolling text and to create the display blocks.

C#

   private void CreateArray(string strTemp)
   {
      Graphics g;
      Bitmap bmpImage = new Bitmap(400, 200);

      g = Graphics.FromImage(bmpImage);

      intWidth = (int)g.MeasureString(strTemp, fFont).Width;

      intWidth += 20;

      if (intWidth < 400) intWidth = 400;

      bmpImage = new Bitmap(intWidth, 200);

      g = Graphics.FromImage(bmpImage);
      g.DrawString(strTemp, fFont, Brushes.Blue, 0, 0);

      blnText = new bool[intWidth, 200];

      for (int x = 0; x < intWidth; x++)
      {

         for (int y = 0; y < 200; y++)
         {

            if (bmpImage.GetPixel(x, y).ToArgb() != 0)
            {
               blnText[x, y] = true;
            }
            else
            {
               blnText[x, y] = false;
            }

         }

      }

      g.Dispose();
   }


   private void StepArray()
   {
      bool[] arrTemp = new bool[200];

      for (int x = 0; x < 200; x++)
      {
         arrTemp[x] = blnText[0, x];
      }

      for (int x = 1; x < intWidth; x++)
      {

         for (int y = 0; y < 200; y++)
         {
            blnText[x - 1, y] = blnText[x, y];
         }

      }

      for (int x = 0; x < 200; x++)
      {
         blnText[intWidth - 1, x] = arrTemp[x];
      }

      for (int x = 0; x < 400; x++)
      {

         for (int y = 0; y < 200; y++)
         {
            blnDisplay[x, y] = blnText[x, y];
         }

      }

      ScrollRefresh();
   }
   private void T_Tick(object sender,
      System.Timers.ElapsedEventArgs e)
   {

      if (DesignMode != true) StepArray();

   }


   private void ScrollRefresh()
   {
      grpG = Graphics.FromImage(bmpGrp);

      for (int x = 0; x < 400; x++)
      {

         for (int y = 0; y < 200; y++)
         {

            if (blnDisplay[x, y])
            {
               grpG.FillRectangle(sbColor, new Rectangle((5 * x)
                  + 1, (5 * y) + 1, 4, 4));
            }
            else
            {
               grpG.FillRectangle(Brushes.Wheat,
                  new Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4));
            }

         }

      }

      grpGraphics.DrawImage(bmpGrp, 0, 0);

   }

VB.NET

   Private Sub CreateArray(ByVal strTemp As String)
      Dim g As Graphics
      Dim bmpImage As Bitmap = New Bitmap(400, 200)
      g = Graphics.FromImage(bmpImage)
      intWidth = CInt(g.MeasureString(strTemp, fFont).Width)
      intWidth += 20
      If intWidth < 400 Then intWidth = 400
      bmpImage = New Bitmap(intWidth, 200)
      g = Graphics.FromImage(bmpImage)
      g.DrawString(strTemp, fFont, Brushes.Blue, 0, 0)
      blnText = New Boolean(intWidth - 1, 199) {}

      For x As Integer = 0 To intWidth - 1

         For y As Integer = 0 To 200 - 1

            If bmpImage.GetPixel(x, y).ToArgb() <> 0 Then
               blnText(x, y) = True
            Else
               blnText(x, y) = False
            End If
         Next
      Next

      g.Dispose()
   End Sub

   Private Sub StepArray()
      Dim arrTemp As Boolean() = New Boolean(199) {}

      For x As Integer = 0 To 200 - 1
         arrTemp(x) = blnText(0, x)
      Next

      For x As Integer = 1 To intWidth - 1

         For y As Integer = 0 To 200 - 1
            blnText(x - 1, y) = blnText(x, y)
         Next
      Next

      For x As Integer = 0 To 200 - 1
         blnText(intWidth - 1, x) = arrTemp(x)
      Next

      For x As Integer = 0 To 400 - 1

         For y As Integer = 0 To 200 - 1
            blnDisplay(x, y) = blnText(x, y)
         Next
      Next

      ScrollRefresh()
   End Sub

   Private Sub T_Tick(ByVal sender As Object, ByVal e As _
         System.Timers.ElapsedEventArgs)
      If DesignMode <> True Then StepArray()
   End Sub

   Private Sub ScrollRefresh()
      grpG = Graphics.FromImage(bmpGrp)

      For x As Integer = 0 To 400 - 1

         For y As Integer = 0 To 200 - 1

            If blnDisplay(x, y) Then
               grpG.FillRectangle(sbColor, New Rectangle((5 * x) _
                  + 1, (5 * y) + 1, 4, 4))
            Else
               grpG.FillRectangle(Brushes.Wheat, New _
                  Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4))
            End If
         Next
      Next

      grpGraphics.DrawImage(bmpGrp, 0, 0)
   End Sub

Add the last few methods to set up and create the control.

C#

   protected override void OnPaint(PaintEventArgs e)
   {
      e.Graphics.FillRectangle(Brushes.Black, new Rectangle(0, 0,
         base.Width - 1, base.Height - 1));

      if (DesignMode)
      {
         for (int x = 0; x < 400; x++)
         {

            for (int y = 0; y < 200; y++)
            {

               if (blnDisplay[x, y])
               {
                  e.Graphics.FillRectangle(sbColor, new
                     Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4));
               }
               else
               {
                  e.Graphics.FillRectangle(Brushes.Black, new
                     Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4));
               }

            }

         }
      }

      e.Graphics.DrawRectangle(Pens.White, 0, 0, 400, 200);
      e.Graphics.DrawRectangle(Pens.WhiteSmoke, 0, 0, 401, 201);

   }

   public clsScroll_C()
   {

      InitializeComponent();

      CreateArray(ScrollText);

      ScrollSpeed = 8;
      T.Elapsed += new System.Timers.ElapsedEventHandler(T_Tick);
      T.Start();

      base.SetStyle(ControlStyles.DoubleBuffer, true);
      base.SetStyle(ControlStyles.UserPaint, true);
      base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
      base.SetStyle(ControlStyles.ResizeRedraw, true);
      base.UpdateStyles();

      this.Size = new System.Drawing.Size(401, 201);

      grpGraphics = base.CreateGraphics();

   }

   private void InitializeComponent()
   {
      //
      // ScrollText
      //

      this.Name = "Example";
      this.ForeColor = ForeColor
      this.Size = new System.Drawing.Size(401, 201);
      this.ScrollSpeed = ScrollSpeed;
      this.Text = ScrollText;

   }

VB.NET

   Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
      e.Graphics.FillRectangle(Brushes.Black, New Rectangle(0, 0, _
         MyBase.Width - 1, MyBase.Height - 1))

      If DesignMode Then

         For x As Integer = 0 To 400 - 1

            For y As Integer = 0 To 200 - 1

               If blnDisplay(x, y) Then
                  e.Graphics.FillRectangle(sbColor, New +
                     Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4))
               Else
                  e.Graphics.FillRectangle(Brushes.Black, New _
                     Rectangle((5 * x) + 1, (5 * y) + 1, 4, 4))
               End If
            Next
         Next
      End If

      e.Graphics.DrawRectangle(Pens.White, 0, 0, 400, 200)
      e.Graphics.DrawRectangle(Pens.WhiteSmoke, 0, 0, 401, 201)
   End Sub

   Public Sub New()
      InitializeComponent()
      CreateArray(ScrollText)
      ScrollSpeed = 8
      AddHandler T.Elapsed, New System.Timers.ElapsedEvent _
         Handler(AddressOf T_Tick)
      T.Start()
      MyBase.SetStyle(ControlStyles.DoubleBuffer, True)
      MyBase.SetStyle(ControlStyles.UserPaint, True)
      MyBase.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
      MyBase.SetStyle(ControlStyles.ResizeRedraw, True)
      MyBase.UpdateStyles()
      Me.Size = New System.Drawing.Size(401, 201)
      grpGraphics = MyBase.CreateGraphics()
   End Sub

   Private Sub InitializeComponent()
      Me.Name = "Example"
      Me.ForeColor = ForeColor
      Me.Size = New System.Drawing.Size(401, 201)
      Me.ScrollSpeed = ScrollSpeed
      Me.Text = ScrollText
   End Sub

Build your Solution. If all went well, and there are no errors, open the Form in Design View and find the newly created control in the Toolbox.

Conclusion

In a future piece, I could perhaps take the properties for this control a bit further and extend them. Until then, happy coding!



About the Author

Hannes DuPreez

Hannes du Preez is a self-taught developer who started learning to program in the days of QBasic. He has written several articles over the years detailing his programming quests and adventures. .NET is his second love, just after his wife and kid. He has always been an avid supporter of .NET since the beginning and is an expert in VB and C#. He was given the Microsoft Most Valuable Professional Award for .NET (2008–2017). He has worked as a moderator and an article reviewer on online forums and currently works as a C# developer and writes articles for CodeGuru.com, Developer.com, DevX.com, and the Database journal.
His first book Visual Studio 2019 In Depth is currently on sale on Amazon and Bpb Publications.

You could reach him at: ojdupreez1978[at]gmail[dot]com

Related Articles

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date