VCL Controls: The Month Calendar

 

The Month Calendar Control

 

Introduction

The Win32 API provides a control used to select dates on a colorful calendar. The dates used and the way they display are based on the Regional Settings of the Control Panel. It may also depend on the operating system:

This convenient control is called Month Calendar. The title bar of the control displays two buttons and two labels. The left button allows the user to select the previous month by clicking the button. The left label displays the currently selected month. The right label displays the year of the displayed date. The right button is used to get to the next month.

The calendar can be configured to display more than one month. Here is an example that displays two months:

If the control is displaying more than one month, the buttons would increment or decrement by the previous or next month in the list. For example, if the control is displaying April and May, if the user clicks the left button, the control would display March and April. If the control is displaying April and May and the user clicks the right button, the control would display May and June. Also, to select any month of the current year, the user can click the name of the month, which displays the list of months and this allows the user to click the desired month:

To select a year, the user clicks the year number. This changes the year label into a spin button:

To change the year, the user can click the up or down arrows of the spin button. As the spin button is displaying, the user can also use the arrow keys of the keyboard to increase or decrease the value.

Under the title bar, the short names of week days display, using the format set in Control Panel. In US English, the first day is usually Sunday. The first day can be changed by the programmer.

On the control, the currently selected date has a circle around. To select a date on the control, the user clicks the desired date, which changes from the previous selection.

In the main area, the numeric days of the month display on a white background (this color and any color on the control can be changed as we will see in the next section). To select a date, the user clicks it in the list. By default, the calendar opens with today's day circled with a hand-drawn-look-alike ellipse. Using the buttons of the title bar, the month label, and/or the year, the user can change the date. If at one time the calendar is displaying a date other than today, and if the user wants to return to today's date, he can click the bottom label that displays Today (you as the programmer can hide the Today label if you want).

Practical Learning: Creating a Month Calendar-Based Application

  1. Start Borland Delphi and create a new VCL Forms Application - Delphi for Win32
  2. Save the project in a new folder called Payroll1
  3. Save the unit as Main and the project as Payroll
  4. Design the form as follows:
     
    Control Name Caption Other Properties
    TForm frmMain Employee Payroll BorderStyle: dsDialog
    ShowHint: True
    TPanel     Height: 128
    Width: 578
    TLabel   Start Period:  
    TEdit edtStartPeriod    
    TSpeedButton btnStartPeriod   AllowAllUp: true
    GroupIndex: 18
    TLabel   Ending Period:  
    TEdit edtEndPeriod    
    TSpeedButton btnEndPeriod   AllowAllUp: True GroupIndex: 20
  5. Set the Glyph of the btnStartPeriod speed button to: C:\Programs Files\Common Files\Borland Shared\Images\Buttons\calendar.bmp
  6. Set the Glyph of the btnStartPeriod speed button to: C:\Programs Files\Common Files\Borland Shared\Images\Buttons\calendar.bmp
  7. Double-click an empty area on the form to access its OnCreate event and implement it as follows:
     
    procedure TfrmMain.FormCreate(Sender: TObject);
    begin
         edtStartPeriod.Text := DateToStr(Date);
         edtEndPeriod.Text   := DateToStr(Date + 13);
    end;
  8. Save All

Calendar Properties

To provide a month calendar control to your application, add a TMonthCalendar button to a form or container. The TMonthCalendar object is created from the TMonthCalendar class which is indirectly derived from TWinControl. The MonthCalendar control is a rectangular object without a border. After placing it on the form, it displays the current month and only one month. This is because, by default, its width and height are set enough to accommodate a month. To display more than one month, change the width of the control to provide enough space:

In the same way, you can increase the height to display many months.

To make it a highly visual object, a month calendar uses different colors to represent the background, week days, the background of the title bar, the text of the title bar, the text of the days of the previous month, and the text of the days of the next month. These colors are controlled by the CalColors property of the control. At design time, you can set these colors to the values of your choice:

Of course, you can programmatically change these colors. Although any color is allowed in any category, you should make sure that the calendar is still reasonably appealing and usable.

Under the title bar, the short names of week days display, using the format set in Control Panel. In US English, the first day is usually Sunday. If you want to start with a different day, set the value using the FirstDayOfWeek property. Under the names of the week and their line separator, the numeric days of the month are listed.

The month calendar control is used to let the user know today's date in two ways. On the calendar, today's date is circled by a hand-drawn ellipse. In the bottom section of the calendar, today's date is also displayed as a sentence. If you want to display or hide the bottom label, set the ShowToday Boolean property accordingly. For example, to hide it, set this property to false.

At any time, a particular date is selected and has an ellipse with the same color as the background of the title bar. By default, the selected date is today's date. On the Object Inspector, it is represented by the Date property. When the user clicks the calendar, a date is selected. To find out what date the user selected, you can access the TMonthCalendar.Date value. The Date value of the MonthCalendar is a TDateTime type. Here is an example:

procedure TfrmMain.MonthCalendar1Click(Sender: TObject);
begin
     Label1.Caption := DateToStr(MonthCalendar1.Date)
end;

When the user clicks the MonthCalendar control, one date is selected. To control whether the user can select one or more dates, set the value of the MultiSelect property accordingly. For example, if you want the user to select a range of dates on the control, set the MultiSelect property to true.

Practical Learning: Adding a Calendar Control

  1. Click an empty area on the form, under the panel
  2. In the Tool Palette, scroll to the Win32 section. Double-click the MonthCalendar button
  3. Click an empty area on the form again and, once more, from the Win32 section of the Tool Palette, double-click the Calendar button
  4. Position both calendars as follows:
     
  5. Change the Name of the left month calendar control to calStartPeriod and change the Name of the right month calendar to calEndPeriod
  6. Change the FirstDayOfWeek of both controls to dowMonday
  7. Set the Visible property of both calendars to False
  8. On the form, double-click the left SpeedButton and implement its OnClick event as follows:
     
    procedure TfrmMain.btnStartPeriodClick(Sender: TObject);
    begin
         if btnStartPeriod.Down = True then
            calStartPeriod.Visible := True
         else
             calStartPeriod.Visible := False;
    end;
  9. On the form, double-click the right SpeedButton and implement its OnClick event as follows:
     
    procedure TfrmMain.btnEndPeriodClick(Sender: TObject);
    begin
         if btnEndPeriod.Down = True then
             calEndPeriod.Visible := True
         else
             calEndPeriod.Visible := False;
    end;
  10. Test the application and return to Delphi
  11. Save All

Month Calendar Methods and Events

The TMonthCalendar class provides a constructor that can be used to programmatically create a calendar and place it on a form or container. To do this, declare a TMonthCalendar variable and, using the new operator, specify the container and the parent of the control. Here is an example:

procedure TfrmMain.Button1Click(Sender: TObject);
var
   cal: TMonthCalendar;
begin
    cal := TMonthCalendar.Create(Self);
    cal.Parent := Self;
end;

After creating the control, all of the properties we have seen above can be accessed.

To accentuate the importance of one or more days of a month, you can call the BoldDays() method. Its syntax is:

procedure BoldDays(Days: array of LongWord; var MonthBoldInfo: LongWord);

This method can be used to format some days in bold and it is mostly used in conjunction with the OnGetMonthInfo() event. The only event the MonthCalendar control handles on its own is the OnGetMonthInfo() event. Its syntax is:

property OnGetMonthInfo: TOnGetMonthInfoEvent;

This means that the OnGetMonthInfo() event is of type TOnGetMonthInfoEvent. This event fires as soon as the month of the calendar has been changed. As a descendant of TWinControl, the MonthCalendar control fires the same regular events of a Windows control.

Practical Learning: Using a Month Calendar Control

  1. On the top section of the source file of the form, in the uses section, add DateUtils:
    #include <DateUtils.hpp>
  2. On the form, double-click the left Calendar and implement its OnClick event as follows:
     
    procedure TfrmMain.calStartPeriodClick(Sender: TObject);
    var
       DateSelected : TDateTime;
       DOTW         : Word;
    begin
         // Get the date that the user has just selected
         DateSelected := calStartPeriod.Date;
         // Find out the numeric "name" of the weekday
         DOTW := DayOfWeek(DateSelected);
    
         // Make sure the user selected a Monday
         if DOTW = 1 then
         begin
              // Since the user selected a Monday date,
              // display it in the Ending Period edit box
              edtStartPeriod.Text := DateToStr(calStartPeriod.Date)
         end
         // Make sure the user can select only a Monday date
         else if DOTW <> 1 then
              ShowMessage('The selected date is invalid' +
                          'A time sheet period starts on Monday');
    end;
  3. On the form, double-click the right Calendar and implement its OnClick event as follows:
     
    procedure TfrmMain.calEndPeriodClick(Sender: TObject);
    var
       DateSelected : TDateTime;
       DOTW         : Word;
       StartPeriod  : TDateTime;
    begin
         // Get the current date selected on the End Period Calendar
         DateSelected := calEndPeriod.Date;
         // Find the numeric "name" of the weekday
         DOTW := DayOfWeek(DateSelected);
         // Get the date of the left calendar
         StartPeriod := calStartPeriod.Date;
    
         // Find out if the user selected a Sunday date
         if DOTW = 7 then
         begin
              // Since the user selected a date on Sunday,
              // display it in the Ending Period edit box
              if DateSelected = StartPeriod + 13 then
                  edtEndPeriod.Text := DateToStr(calEndPeriod.Date)
              // Make sure the date the user selected is the week following
              // the previous
              else
                  ShowMessage('Invalid date selection' +
                              'The time sheet period spans 14 days');
         end
         // Make sure the user selects a Sunday date.
         // Otherwise, dismiss it
         else if DOTW <> 7 then
              ShowMessage('The selected date is invalid' +
                          'A time sheet period ends on Sunday');
    end;
  4. Test the application
     
  5. Return to Delphi and Save All 
Home Copyright © 2005 FunctionX, Inc.