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

Discussion in 'Programming General' started by Blupig, May 21, 2012.

[VB.NET][TUT] Winforms Desktop Numerical Clock "Gadget"
  1. Unread #1 - May 21, 2012 at 6:19 PM
  2. Blupig
    Joined:
    Nov 23, 2006
    Posts:
    7,145
    Referrals:
    16
    Sythe Gold:
    1,609
    Discord Unique ID:
    178533992981594112
    Valentine's Singing Competition Winner Member of the Month Winner MushyMuncher Gohan has AIDS Extreme Homosex World War 3 I'm LAAAAAAAME
    Off Topic Participant

    Blupig BEEF TOILET
    $5 USD Donor

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

    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:
    [​IMG]


    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.
     
< Image Recognition? VB 2010 | Grand Exchange Parser >

Users viewing this thread
1 guest


 
 
Adblock breaks this site