Visual Basic Explorer
Visual Basic Explorer
 Navigation
 Home


 Coding
 Source Code

 FAQ Center

 VB Tips

 Downloads

 ToolBox

 Tutorials

 VB Games

 VB News

 VB Award

 VB Forums



 Affiliates
 Planet Source Code

 Rent a Coder

 DirectX4VB


 Misc
 Search

 Feedback

 Advertise

 About


Need to hire
a VB coder?

Please support our sponsor:

 Home 
 Site Map 
 Forums 
 News 
 Feedback 

Problem # 1 - Color Properties

DayColor and DayNameColor Properties

If you’ve played around with this control for a little while, you may have noticed something a bit peculiar regarding the DayColor and DayNameColor properties. Open the Test Project in Visual Basic’s IDE and, while looking at the properties for the calendar control, change the DayColor property. You’ll notice it will change for a brief moment, then changes to be the same as the DayNameColor property when the calendar gets refreshed. And if you change DayNameColor, the DayColor property also gets changed!

This problem is solved through changing the source code, as there’s a bug in the code for the Get DayNameColor property. Let’s have a look at this code:

'----------------------------------------------------------------------
' DayNameColor Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the color used for the day numbers
'----------------------------------------------------------------------
Public Property Get DayNameColor() As OLE_COLOR
DayColor = mclrDayNames

End Property 'Get DayNameColor()

A simple mistake: setting the DayColor variable to mclrDayNames, instead of setting the DayNameColor variable to mclrDayNames. Forgetting part of a variable name is easy to do when the names are so similar. A possibility is that this code was developed from a copy of the code for the DayColor property, and that this was missed. This is something to remember when reviewing your own code.

What’s Happening?

The Refresh property does exactly as its name suggests. One of the keys to its overall performance is that it carries out all of the Get properties in order to fully refresh a given control. When you set the DayColor Property, the code for Let DayColor calls the Refresh routine:

Public Property Let DayColor(NewVal As OLE_COLOR)

mclrDay = NewVal

UserControl.Refresh

End Property 'Let DayColor()

When this occurs, one of the routines called during the Refresh is Get DayColor:

'----------------------------------------------------------------------
' DayColor Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the color used for the day numbers
'----------------------------------------------------------------------
Public Property Get DayColor() As OLE_COLOR
DayColor = mclrDay
End Property 'Get DayColor()

This provides us with the grief glimpse of the correct color for the days. However, since the code for Get DayNameColor comes later in the list of routines than the Get DayNameColor property, the DayColor property ultimately gets set to the color for DayNameColor, while the DayNameColor Property doesn’t get refreshed at all.

Almost the same thing occurs when you set the DayNameColor property, with a couple of minor exceptions. The instant the color is changed, mclrDayNames gets properly set. When the Refresh occurs for this routine, the DayColor gets set to DayNameColor as well, again via the Get DayNameColor property. Since the DayNameColor property is not addressed correctly in its Get routine, the box on the OLE_COLOR control in the properties menu for DayNameColor never changes.

The "Fix"

Repair the Get DayNameColor code as follows:

'----------------------------------------------------------------------
' DayNameColor Get/Let
'----------------------------------------------------------------------
' Purpose: Gets and sets the color used for the day numbers
'----------------------------------------------------------------------
Public Property Get DayNameColor() As OLE_COLOR
' DayColor = mclrDayNames

DayNameColor = mclrDayNames
End Property 'Get DayNameColor()

If you now try to view the test form in design mode without going any further, you’ll see this:

The calendar control needs to be compiled once before we can check the results of our fix. Press the F5 key to run the sample, then shut it down. The test form will now show up as it did the first time we looked at it. Now, go ahead and toy with the DayColor and DayNameColor properties, and you’ll see that these properties now work correctly.

Once you’ve done this, select ‘Make MSVBCldr.ocx’ from the File menu of the IDE, making sure to select the c:\windows\system\ directory as its location.

 

Now What?

This problem was labeled #1, which means that, yes, there’s another one we’ll address a little later on. Does this indicate that we shouldn’t use this control in our applications? Of course not. It’s supplied as source code, so anything we find we should go ahead and repair. Problem #2 is a bit different, and we’ll see how to repair something outside of the source code.

The reason we receive samples from Microsoft with our development software is to see how to do things, not only how to accomplish a particular task, but also how to develop software in a manner consistent with certain software industry standards.

These unsupported controls and utilities are a bit different. Looking deeper at some of the code for this particular control reveals that we are looking at a work in-progress that we normally wouldn’t be allowed to see. For instance, the following code is from the Declarations section of the UserControl for the MSVBCalendar Control:

'----------------------------------------------------------------------
' Calendar.ctl
'----------------------------------------------------------------------
' Implementation file for the VB Calendar control sample.
' This control displays a month-at-a-time view calendar that the
' developer can use to let users view and adjust date values
'----------------------------------------------------------------------
' Copyright (c) 1996, Microsoft Corporation
' All Rights Reserved
'
' Information Contained Herin is Proprietary and Confidential

'----------------------------------------------------------------------

The bolded line is important, and indicates that this control may not have been intended as a sample. This may have actually been a control intended to be shipped with Visual Basic 5 that was turned into an unsupported sample due to time constraints.

The code for the UserControl’s Paint event is also interesting, as it reveals the uncompleted aspect of this sample:

'change the text color to dark gray to paint the previous month days

'daveste -- 7/31/96

'TODO: this should be replaced with day styles or at least with

'a property the control the font and color of these other dates

dcWork.TextColor = RGB(128, 128, 128)

Note the grammar on that one. Definitely incomplete!

There are other TODO lines throughout the code. You’ll find them if you look around a bit more.

What’s even more interesting is the following code, also from the UserControl portion of the code:

Private Sub CopyFont(fntSource As StdFont, fntDest As StdFont)
    'daveste -- 8/14/96
    'REVIEW:  Is there a better way to do this???!!!

    'if the destination is nothing, create a new font object
    If fntDest Is Nothing Then Set fntDest = New StdFont

    fntDest.Bold = fntSource.Bold
    fntDest.Charset = fntSource.Charset
    fntDest.Italic = fntSource.Italic
    fntDest.Name = fntSource.Name
    fntDest.Size = fntSource.Size
    fntDest.Strikethrough = fntSource.Strikethrough
    fntDest.Underline = fntSource.Underline
    fntDest.Weight = fntSource.Weight
End Sub 'CopyFont()

Good question from the anonymous ("daveste"?) code reviewer, and quite a challenge for those of us who now have the code. The challenge? Quite simply, this: Finish designing the control. Complete the TODO items, answer the reviewers questions, and test the final control for problems like the one we just repaired. Customize it as you’d like, since you’ve got the source code and the ability to do so. The end result in all of this will not just be a nifty little calendar control that works to our liking. Rather, this is a great way to become better developers than we already are.

 

Try It Out – Usage of the MSVBCalendar Control

In the chapter 6 directory of the CD is a sample application we’ll use to see how the calendar control can be used. Open the project chapter6.vbp and have a look at the form:

If an error occurs during the loading of this project, it’s likely due to the copy of MSVBCldr.ocx on your system being not quite what the IDE is looking for. If this happens, the place where the calendar would have been shown will only show an empty 3-D rectangle. Delete this rectangle, and ensure that the Microsoft Visual Basic Calendar is selected in the projects’ components. Then, add the calendar to the project, on this form, in the place the 3-D rectangle was previously. The default name for the calendar is Calendar1, which is what I used to develop this sample. None of the calendar’s properties need to be changed.

Right now there is no code on the form that performs any kind of tasks. The menus are empty, as are the events of the calendar control itself.

Place the following code in the form’s Load event to set the calendar’s date to the current date each time the form is opened:

Private Sub Form_Load()

  ' Set the calendar to today's date
  With Calendar1
    .Year = Format(Now, "yyyy")
    .Month = Format(Now, "m")
    .Day = Format(Now, "d")
    .Refresh
  End With

End Sub

Place the following code under the DblClick event of the calendar control Calendar1:

Private Sub Calendar1_DblClick()


  ' Declare the variables
  Dim SelDate As Variant, NowDate As Variant
  Dim SelYear As Integer, SelMonth As Integer, SelDay As Integer

  ' Assemble the date string from the calendar control
  With Calendar1
    SelYear = .Year
    SelMonth = .Month
    SelDay = .Day
  End With
  SelDate = DateSerial(SelYear, SelMonth, SelDay)

  ' Compute today's date
  NowDate = DateSerial((Format(Now, "yyyy")), (Format(Now, "m")), (Format(Now, "d")))

  ' Test to see if the selected date is earlier than today
  If SelDate < NowDate Then

    'If it is...
    Msg = "The  date you have selected is earlier than today." & Chr(10) & _
      "Please select today's date or later."
    Style = vbOKOnly + vbExclamation
    Title = "Date Selection Error"
    Response = MsgBox(Msg, Style, Title)

    ' Reset the calendar
    With Calendar1
      .Year = Format(Now, "yyyy")
      .Month = Format(Now, "m")
      .Day = Format(Now, "d")
      .Refresh
    End With

  Else
    ' Load the text box with the selected date
    If Option1.Value = True Then
      ' U.S.A.
      Text1.Text = SelMonth & "/" & SelDay & "/" & SelYear
    Else
      If Option2.Value = True Then
        ' Europe
        Text1.Text = SelDay & "/" & SelMonth & "/" & SelYear
        Else
          ' U.S.A.
          Option1.Value = True
          Text1.Text = SelMonth & "/" & SelDay & "/" & SelYear
      End If
    End If
  End If  
End Sub

Place the following code under the option button labeled U.S.A.:

Private Sub Option1_Click()

  ' Load the text box with the selected date
  If Text1.Text = "" Then
    ' Do nothing

  Else
    ' U.S.A.
    Text1.Text = Calendar1.Month & "/" & Calendar1.Day & "/" & Calendar1.Year
  End If

End Sub

This next bit of code goes under the option button labeled Europe:

Private Sub Option2_Click()

  ' Load the text box with the selected date
  If Text1.Text = "" Then
    ' Do nothing

  Else
    ' Europe
    Text1.Text = Calendar1.Day & "/" & Calendar1.Month & "/" & Calendar1.Year
  End If

End Sub

Press the F5 key to run the program. As long as there are no compilation errors, the form will appear in the center of the screen. If you double-click on a date later than today’s date, the date value will appear in the text box. However, if you double-click on a date earlier than today, a message will appear:

By default, the date is placed into the text box in the format used in the U.S.A. Click on the option button labeled Europe and watch the contents of the text box change appropriately.

How It Works

First we declare the variables we need to accomplish this task. The first two need to be of the type Variant since they are used with the DateSerial statement:

' Declare the variables
  Dim SelDate As Variant, NowDate As Variant
  Dim SelYear As Integer, SelMonth As Integer, SelDay As Integer

Instead of simply retrieving the value of the selected date from the calendar, we’ll retrieve it in pieces so we can correctly calculate the value for DateSerial:

  ' Retreive the date from the calendar control
  With Calendar1
    SelYear = .Year
    SelMonth = .Month
    SelDay = .Day
  End With

We then compute the serial value for the selected date.

‘ Compute the selected date
  SelDate = DateSerial(SelYear, SelMonth, SelDay)

Note that the DateSerial function will return an error if the value is -32,768 to 32,767 from the base date of January 1, 1904. This is important due to the range of years available from this control and the fact that they can be extended even further.

In a similar manner, we then compute today’s date:

' Compute today's date
  NowDate = DateSerial((Format(Now, "yyyy")), (Format(Now, "m")), (Format(Now, "d")))

Since this sample will be used later in the book for a scheduling wizard, we need to check if the selected date is earlier than today. If it is, we’ll generate an error to that effect. Once the message box is cleared, the calendar is refreshed with today’s date so the user can have another go at it:

' Test to see if the selected date is earlier than today
  If SelDate < NowDate Then

    'If it is...
    Msg = "The  date you have selected is earlier than today." & Chr(10) & _
      "Please select today's date or later."
    Style = vbOKOnly + vbExclamation
    Title = "Date Selection Error"
    Response = MsgBox(Msg, Style, Title)

    ' Reset the calendar
    With Calendar1
      .Year = Format(Now, "yyyy")
      .Month = Format(Now, "m")
      .Day = Format(Now, "d")
      .Refresh
    End With

If the selected date is, in fact, today or later, we place the selected date into the text box in the appropriate format for the locale:

  Else
    ' Load the text box with the selected date
    If Option1.Value = True Then
      ' U.S.A.
      Text1.Text = SelMonth & "/" & SelDay & "/" & SelYear
    Else
      If Option2.Value = True Then
        ' Europe
        Text1.Text = SelDay & "/" & SelMonth & "/" & SelYear
        Else
          ' U.S.A.
          Option1.Value = True
          Text1.Text = SelMonth & "/" & SelDay & "/" & SelYear
      End If
    End If
  End If

The internationalization applied by the option buttons is rather simple, as it places the date fields into the text box in the correct order for the locale.

Notice that the controls on this form are located on a picture box, which acts as a container for them. We’ll use this same sample to develop more concepts through the rest of this chapter. Later on, we’ll be building a scheduling wizard from this form, so remember to keep track of where it is. However, this is where the other problem comes in.


[Home Page] [Next Lesson] [Previous Lesson] [Dave Liske's Site] [Wrox Web-Developer]





Home | About | What's New | Source Code | FAQ | Tips & Tricks | Downloads | ToolBox | Tutorials | Game Programming | VB Award | Search | VB Forums | Feedback | VBNews | Copyright & Disclaimer | Advertise | Privacy Policy |

Quick searches: Site Search | Advanced Site Search 

Copyright 2002 by Exhedra Solutions, Inc.
By using this site you agree to its terms and conditions
VB Explorer and VBExplorer.com are trademarks of Exhedra Solutions, Inc.