• Log in or sign up for an account here: https://www.sythe.org/login

[VB.NET][TUT] Winforms Desktop Numerical Clock "Gadget"

Blupig

BEEF TOILET

$5 USD Donor
Joined
Nov 23, 2006
Sythe Gold
1,609
Messages
7,145
Age
33
Location
Canada
Valentine's Singing Competition Winner
Sythe Awards 2015 Winner
Sythe Awards 2016 Winner
Sythe Awards 2020 Winner
Member of the Month Winner
MushyMuncher
Gohan has AIDS
Extreme Homosex
World War 3
I'm LAAAAAAAME
Discord Verified
Off Topic Participant
Hey guys, this is a really old source of mine that I've decided to create a bit of a tutorial for, since it teaches the significance/use of the Paint event and uses the GDI+ DrawString function which are both fairly useful.

This is what you'll achieve with this tutorial:
oNhHW.jpg



1. Create a new Windows Forms Application project

2. Add a module to your project (in the Solution Explorer, right-click your project's name, then "Add" then "Module..."). Name it whatever you like.

3. The module will contain our function for parsing time properly into a more friendly, readable format, starting with this line which you will put at the top of the module:
Code:
Private secs, mins, hrs, TimeLabel As String
Private means that those variables will only be able to be accessed from the module. We don't want our main form or any other objects to be changing those values.

Next, is our function which will use our new variables:
Code:
    Public Function ParseTime(ShowSeconds As Boolean) As String

        secs = DateTime.Now.Second.ToString
        mins = DateTime.Now.Minute.ToString
        hrs = DateTime.Now.Hour.ToString

        If CInt(hrs) > 12 Then
            hrs = (CInt(hrs) - 12).ToString
            TimeLabel = "PM"
        Else
            TimeLabel = "AM"
        End If

        If CInt(secs) < 10 Then secs = "0" & secs
        If CInt(mins) < 10 Then mins = "0" & mins

        If ShowSeconds = True Then Return hrs & ":" & mins & ":" & secs & " " & TimeLabel
        If ShowSeconds = False Then Return hrs & ":" & mins & " " & TimeLabel

    End Function

If you set "ShowSeconds" to true in the function call, then the function will output the time with seconds like this: "5:50:13 PM". If it's false, it will exclude the seconds, like so: "5:50 PM".

Why do you set all the variables outside the function?
You can set them inside the function too, but it's good practice to put them outside. The reason is that if we want our clock to update (to change every minute or every second) then we want to only declare our variables once. Think about if our clock updates every second - You would be declaring 4 variables over and over each second, which can clog up the memory. Since this is a desktop gadget and should not be taking up many resources, we declare them once so that they don't have to be created again.

Function breakdown
Code:
        secs = DateTime.Now.Second.ToString
        mins = DateTime.Now.Minute.ToString
        hrs = DateTime.Now.Hour.ToString
This part here gives values to our seconds, minutes, and hours variables. We can grab the system's current time by using a few calls in the DateTime class. We add "ToString" at the end since our variables are strings and should be stored as such. The good thing about VB is that it does a lot of conversions on its own (so you don't actually have to do this) but it's good practice to get used to hard-coded conversions since other languages don't typically convert values for you.

Code:
        If CInt(hrs) > 12 Then
            hrs = (CInt(hrs) - 12).ToString
            TimeLabel = "PM"
        Else
            TimeLabel = "AM"
        End If
Here we check to see if the hours are bigger than 12. DateTime spits out values using military time (24 hour clock), so to get the more conventional 12 hour system, we do the check. If the hour is bigger than 12, we subtract 12 from the hour and we'll get the conventional hour value (by the way, CInt() simply converts whatever is between brackets to an integer so we can use it for calculations and numerical comparison). Since we know that any time between hour 13 and hour 23 are PM on the 12 hour system, we can change our "TimeLabel" value to "PM" since it's night. If the hour variable is 1-12 then we know it's AM.

Code:
        If CInt(secs) < 10 Then secs = "0" & secs
        If CInt(mins) < 10 Then mins = "0" & mins
Here we check to see if the seconds and the minutes variables are under 10. Since DateTime grabs values without formatting, we need to add a 0 in front to match standard digital clock formats. An example output without this check would be "5:9:1 PM". By doing the check and adding our zeros, we get "5:09:01 PM" instead.

Code:
        If ShowSeconds = True Then Return hrs & ":" & mins & ":" & secs & " " & TimeLabel
        If ShowSeconds = False Then Return hrs & ":" & mins & " " & TimeLabel
This is our final return. If you set ShowSeconds to true, it will return formatted time with seconds. If not, then time will be set to show without seconds.

4. Go to your form's designer, and set its "TransparencyKey" to "Fuchsia", its "FormBorderStyle" to "None" and its "BackColor" to "Fuchsia". You should also make the form wide, but not very high. For this example I used a width of 747px and a height of 134px. Doing all that should give you a bright-pink colored borderless form with nothing on it. If you don't have that, you fucked up. The TransparencyKey basically just sets a color on the form that will be transparent. It can be anything you want, but generally Fuchsia isn't used in anything which is why a lot of people use that for transparency. By setting your backcolor to the same color as the transparencykey, you'll have a completely transparent form.

5. Go to your form's code, and start put in the following:
Code:
    Dim g As Graphics
    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
    End Sub

This overrides the paint event for the form, so we can put stuff on it while its doing its normal drawing routine. We declare a Graphics object to use next in the paint event, so we can draw our text clock.

Under "MyBase.OnPaint(e)" put in the following:
Code:
        g = Me.CreateGraphics
        g.DrawString(ParseTime(True), New Font("Segoe UI", 72), New SolidBrush(Color.White), New Point(0, 0))

Here we give a value to our Graphics object by creating graphics on our form so we can draw. Without a graphics object pointing to our form, we cannot draw on it (unless you use a regular paint event and draw with the PaintEventArgs, but I personally prefer this way).

We then call the DrawString function from our graphics object and fill in all its values, the first being its text. DrawString simply draws text where-ever on the screen using a brush, a start point, a font, and some text. Since we made a function to format a digital clock display, we're going to put that in for our text. Next, we create a font. I like Segoe UI, but you can put in whatever you want as long as your computer has it. I made this point 72 as well, if that's too big or too small you can also change that. Next we create a solidbrush (a solid color) and make its color white. Then, finally, we tell our application where to start drawing the text, which should generally be at the point of origin (top left corner of the program), at 0,0.

Now, make a timer and call it whatever you want. Set its "Interval" property to 1000, and its "Enabled" property to "True". Then, double click it so we can see its event code. Put this in:
Code:
Me.Refresh()
That will refresh the form, making it paint itself again each time the timer cycles through. Without this, our clock won't update and will stay at the time that you started the program at.

You're done!

Here's the entire code for the module:
Code:
Module modFuncs

    Private secs, mins, hrs, TimeLabel As String

    Public Function ParseTime(ShowSeconds As Boolean) As String

        secs = DateTime.Now.Second.ToString
        mins = DateTime.Now.Minute.ToString
        hrs = DateTime.Now.Hour.ToString

        If CInt(hrs) > 12 Then
            hrs = (CInt(hrs) - 12).ToString
            TimeLabel = "PM"
        Else
            TimeLabel = "AM"
        End If

        If CInt(secs) < 10 Then secs = "0" & secs
        If CInt(mins) < 10 Then mins = "0" & mins

        If ShowSeconds = True Then Return hrs & ":" & mins & ":" & secs & " " & TimeLabel
        If ShowSeconds = False Then Return hrs & ":" & mins & " " & TimeLabel

    End Function

End Module

And here's the entire code for the form:
Code:
Public Class frmClock

    Dim g As Graphics
    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        g = Me.CreateGraphics
        g.DrawString(ParseTime(True), New Font("Segoe UI", 72), New SolidBrush(Color.White), New Point(0, 0))
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Me.Refresh()
    End Sub

End Class


Why can't I just use a label and update its text instead of doing all that complicated drawing?

You can if you want, but transparency with form controls is really tricky. You'll get an outline of your backcolor around the text if you use a label and it'll look awful. Since we want to achieve full and perfect transparency, we make our form invisible then draw text manually using GDI+ so we don't get that issue. If you were to make this same project in WPF instead of Winforms, you wouldn't have this label issue and could use labels if you want. The reason for that is Winforms is rendered through software, and WPF is rendered through hardware.
 
Runescape Gamblingrunescape gambling
Back
Top