Someone on the board the other day had me thinking about graphical clock displays. Displaying something like the current time or maybe the time remaining of a song or even a general counter. Sure we can create these things using standard text, but what about nifty pictures? With this example we are going to show below, we could theoretically make counters that show wingdings, clocks displaying the time in binary pictures, show how long is left in a song using numbers that run together or even create captcha style sign in systems. So sit back, sip your tea and hack the planet on this entry of the Programming Underground!
Graphical clock displays… they are everywhere. Jack Bauer might have even seen one on a bomb he disarmed on the show “24”. It is easy to show the time or a counter using a standard string, but what if you want to make something a little more fancy with crazy numbers, fonts, colors, pictures, or heck a whole sentence generated based on the time? It can be done easily in the .NET framework using a little creativity and our friend the Graphics object and its sidekick the picturebox.
Our example has 4 main parts. First it involves one solid picture that contains all the numbers, symbols, and even the space used in a standard time display. Things like 0 – 9, space, and the colon. We could even add an AM, PM if we wanted. This graphic is going to be used to display everything shown in a graphic time display. It is organized in such a way that each number is in its own 50 x 90 pixel block. Now of course this makes a big display and you can certainly shrink it, but the key is to make sure that each symbol has its own individual rectangle and that all rectangles are the same width and height. That way you could place the number 1 or “:” in a spot and it would take up the same amount of space.
The second part is a picturebox which will hold all the digits for our time. The example we are going to show simply displays the current time on the system.
The third part is going to be an on paint event which will fire whenever the picturebox needs to repaint the time. Repainting happens when we invalidate the control, or it is invalidated by a window moving over the top of it, when the form is resized etc.
The last part is a timer that every second it invalidates the picturebox, causing it to repaint itself and display the current digits/pictures whatever.
The code may look like this…
Public Class Form1 ' Set a variable to hold our numbers image (the image that has all clock numbers/symbols) Private numbersImage As Image ' Array of Rectangles we will use to isolate each character in the image Private digits(11) As Rectangle ' Upon loading of the form, we will load in the numbers, then initialize ' our rectangle array to split the image into 50 x 90 rectangles, each number and ' symbol to its own rectangle. ' Think of it like little view windows on parts of the graphic. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load numbersImage = Image.FromFile("123.gif") Dim i As Integer = 0 For i = 0 To 11 digits(i) = New Rectangle((i * 50), 0, 50, 90) Next ' Start our timer to update the clock display timerUpdate.Start() End Sub ' When the picturebox control is invalidated, the paint method is fired Private Sub TimeBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles TimeBox1.Paint ' Get the graphics object of our TimeBox1 control Dim g As Graphics = e.Graphics() ' Get the short time string for right now (returns something like 12:34 AM) Dim strTime As String = DateTime.Now().ToShortTimeString() Dim i As Integer = 0 ' Loop through the time string, if it is a digit, draw it from our image file ' (using the appropriate window rectangle) onto the picturebox. ' This is why it was good to make one number every 50 pixels. For i = 0 To strTime.Length - 1 If Char.IsDigit(strTime.Chars(i)) Then Dim digit As Integer = Integer.Parse(strTime.Chars(i).ToString()) g.DrawImage(numbersImage, (i * 50), 0, digits(digit), GraphicsUnit.Pixel) ElseIf strTime.Chars(i) = ":" Then ' If the symbol was a colon, pull that from the graphic and show that. g.DrawImage(numbersImage, (i * 50), 0, digits(10), GraphicsUnit.Pixel) End If Next End Sub ' Every 1 second invalidate the picturebox control causing it to repaint. Private Sub timerUpdate_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerUpdate.Tick TimeBox1.Invalidate() End Sub End Class
First of all we create a variable to hold a reference to the main picture. In this case we call it 123.gif and it is 600 pixels wide (that is 12 symbols X 50 pixels each) by 90 pixels high. It looks like this…
After we load the image, we create an array of 12 rectangle objects which will be used as windows into the 123.gif graphic. Each rectangle is centered around a digit/symbol. So digit(0) is set to have coordinates around the picture “0” in 123.gif and digit(1) is centered around the picture “1” in 123.gif etc. We do this all the way through the graphic file. Later in the code we read the time, the digits in the time, and pull the appropriate rectangle to then paint into the picturebox.
When the application starts we load up the rectangles and set the variable for the main picture. We then start our timer which will fire every 1000 milliseconds. This is equal to 1 second and it simply calls the picturebox’s invalidate() method which causes the picturebox to fire its paint() method. The paint method starts parsing the time and drawing in the pictures. In case you were wondering we call our picturebox here TimeBox1.
In Timebox1’s paint method we get the current time and ask for it in short string time. Instead of giving us the entire date and time, it will return just the time in a format like 12:34 AM. This string we then loop through and check to see if each character is a digit or not. If it is a digit, we ask the paint method to look up the appropriate rectangle window and draw what it sees onto the picturebox at the given coordinates. So for instance if it sees “1” it goes to digits(1) and gets the rectangle which shows “1” from our graphic file and paints that at coordinate 0,0 of the picturebox with a width of 50 and a height of 90. It then moves onto the next character. If it runs into the “:” character, it looks that up individually and paints that in.
Lastly we have our timer tick event which fires every 1000 milliseconds of the timer and calls the TimeBox1.Invalidate() method to cause another repaint of the time. The result is a program similar to this…
It is a pretty simple project and like mentioned earlier, you could essentially use this for any kind of time for displaying clock time, maybe time left in a song, counters etc. Any number string that you want to show as graphical. With part of this project you could even setup animations where each rectangle is considered its own frame and you loop through the frames.
This project was just a quick little demo of how it is done and I will leave it up to you to expand on it and see what you can do with it. I hope you enjoyed it and thanks for reading.