Skip to main content
Table of Contents

Date Selection

TTMSFNCCalendar supports single and multi-date selection, keyboard navigation, and programmatic range selection. The same API applies to TTMSFNCDatePicker, which displays the calendar in a dropdown.


Selecting dates

Select dates, set limits and navigatePascalC++
procedure TForm1.CalendarDateExamples;
var
  d: TDate;
begin
  // --- Single date selection ---
  TMSFNCCalendar1.SelectADate(Now + 2);   // select one date, deselects all others

  // --- Multi-date selection (requires MultiSelect) ---
  TMSFNCCalendar1.Interaction.MultiSelect := True;
  TMSFNCCalendar1.SelectDate(Now - 3);                 // add a date to the selection
  TMSFNCCalendar1.SelectDate(EncodeDate(2025, 12, 25));

  // Range selection: select all dates from AStartDate to AEndDate (clears prior selection)
  TMSFNCCalendar1.SelectMultiDates(Now - 10, Now + 5);

  // --- Reading selected dates ---
  d := TMSFNCCalendar1.SelectedDate;  // last / only selected date
  if TMSFNCCalendar1.SelectedDates.Count > 0 then
    d := TMSFNCCalendar1.SelectedDates.Items[0].Date;

  // --- Deselecting ---
  TMSFNCCalendar1.SelectedDates.UnselectAll;
  TMSFNCCalendar1.SelectedDates.UnselectDate(Now);

  // --- Date limits ---
  TMSFNCCalendar1.MinDate := EncodeDate(2024, 1, 1);
  TMSFNCCalendar1.MaxDate := EncodeDate(2026, 12, 31);

  // --- Navigate the calendar view ---
  TMSFNCCalendar1.Date  := EncodeDate(2025, 6, 1);  // jump to June 2025
  TMSFNCCalendar1.Month := 12;
  TMSFNCCalendar1.Year  := 2025;
end;

// React to selection
procedure TForm1.TMSFNCCalendar1SelectDate(Sender: TObject; ADate: TDate);
begin
  ShowMessage(DateToStr(ADate) + ' selected');
end;
// --- Single date selection ---
void __fastcall TForm1::CalendarDateExamples()
{
  TMSFNCCalendar1->SelectADate(Now() + 2);   // select one date, deselects all others

  // --- Multi-date selection (requires MultiSelect) ---
  TMSFNCCalendar1->Interaction->MultiSelect = true;
  TMSFNCCalendar1->SelectDate(Now() - 3);                 // add a date to the selection
  TMSFNCCalendar1->SelectDate(EncodeDate(2025, 12, 25));

  // Range selection: select all dates from AStartDate to AEndDate (clears prior selection)
  TMSFNCCalendar1->SelectMultiDates(Now() - 10, Now() + 5);

  // --- Reading selected dates ---
  TDate d = TMSFNCCalendar1->SelectedDate();  // last / only selected date
  if (TMSFNCCalendar1->SelectedDates->Count > 0)
    d = TMSFNCCalendar1->SelectedDates->Items[0]->Date;

  // --- Deselecting ---
  TMSFNCCalendar1->SelectedDates->UnselectAll();
  TMSFNCCalendar1->SelectedDates->UnselectDate(Now());

  // --- Date limits ---
  TMSFNCCalendar1->MinDate = EncodeDate(2024, 1, 1);
  TMSFNCCalendar1->MaxDate = EncodeDate(2026, 12, 31);

  // --- Navigate the calendar view ---
  TMSFNCCalendar1->Date  = EncodeDate(2025, 6, 1);  // jump to June 2025
  TMSFNCCalendar1->Month = 12;
  TMSFNCCalendar1->Year  = 2025;
}

// React to selection
void __fastcall TForm1::TMSFNCCalendar1SelectDate(TObject *Sender, TDate ADate)
{
  ShowMessage(DateToStr(ADate) + " selected");
}
Multiple individual dates selected

SelectADate — replace selection

Inline example 1PascalC++
TMSFNCCalendar1.SelectADate(Now + 2);
TMSFNCCalendar1->SelectADate(Now + 2);

Selects one date and deselects everything else. Also moves the focused date to the selected date.

SelectDate — add to selection

Inline example 2PascalC++
TMSFNCCalendar1.Interaction.MultiSelect := True;
TMSFNCCalendar1.SelectDate(Now - 3);
TMSFNCCalendar1.SelectDate(EncodeDate(2025, 12, 25));
TMSFNCCalendar1->Interaction->MultiSelect = True;
TMSFNCCalendar1->SelectDate(Now - 3);
TMSFNCCalendar1->SelectDate(EncodeDate(2025, 12, 25));

Keeps existing selected dates and adds the new one. Requires MultiSelect = True for more than one date.

SelectMultiDates — range selection

Inline example 3PascalC++
TMSFNCCalendar1.SelectMultiDates(Now - 10, Now + 5);
TMSFNCCalendar1->SelectMultiDates(Now - 10, Now + 5);

Selects all dates from AStartDate to AEndDate and clears any previous selection.

Range of dates selected

Reading selected dates

Inline example 4PascalC++
var d: TDate;
begin
  d := TMSFNCCalendar1.SelectedDate;  // last/only selected date
  if TMSFNCCalendar1.SelectedDates.Count > 0 then
    d := TMSFNCCalendar1.SelectedDates.Items[0].Date;
end;
TDate d = TMSFNCCalendar1->SelectedDate;
if (TMSFNCCalendar1->SelectedDates->Count > 0)
  d = TMSFNCCalendar1->SelectedDates->Items[0]->Date;

Deselecting dates

Inline example 5PascalC++
TMSFNCCalendar1.SelectedDates.UnselectAll;         // clear all
TMSFNCCalendar1.SelectedDates.UnselectDate(Now);   // clear one date
TMSFNCCalendar1->SelectedDates->UnselectAll;         // clear all
TMSFNCCalendar1->SelectedDates->UnselectDate(Now);   // clear one date
All dates deselected

Date limits

Inline example 6PascalC++
TMSFNCCalendar1.MinDate := EncodeDate(2024, 1, 1);
TMSFNCCalendar1.MaxDate := EncodeDate(2026, 12, 31);
TMSFNCCalendar1->MinDate = EncodeDate(2024, 1, 1);
TMSFNCCalendar1->MaxDate = EncodeDate(2026, 12, 31);

Dates outside the min/max range are disabled and cannot be selected.


Interaction options

Set on TTMSFNCCalendar.Interaction:

Property Description
MultiSelect Enable selecting more than one date.
KeyboardSupport Allow keyboard navigation of the focused date.
ReadOnlyMode Disable all user date selection.

Events

Reach for the selection events whenever something outside the calendar has to follow the selection — a detail panel, an agenda list, a Save command, or a persisted user preference. Read the selection from the after event (OnSelectDate / OnSelectMultiDate), where SelectedDates already reflects the change; OnBeforeSelectDate still sees the previous state.

Event Signature Fires
OnBeforeSelectDate (Sender: TObject; ADate: TDate) Once per date, before it is added to SelectedDates.
OnSelectDate (Sender: TObject; ADate: TDate) Once per date, after it has been added.
OnSelectMultiDate (Sender: TObject; AStartDate, AEndDate: TDate) Once for a whole range instead of once per day.
Track the selection through the calendar eventsPascalC++
procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCCalendar1.Interaction.MultiSelect := True;

  TMSFNCCalendar1.OnBeforeSelectDate := DoBeforeSelectDate;
  TMSFNCCalendar1.OnSelectDate       := DoSelectDate;
  TMSFNCCalendar1.OnSelectMultiDate  := DoSelectMultiDate;
end;

{ Fires once per date, just before it is added to SelectedDates. The handler has
  no cancel parameter, so use it to observe or prefetch only - block a date with
  MinDate / MaxDate or Interaction.ReadOnlyMode instead. }
procedure TForm1.DoBeforeSelectDate(Sender: TObject; ADate: TDate);
begin
  StatusLabel.Text := 'Loading agenda for ' + DateToStr(ADate);
end;

{ Fires after the date has been added. SelectedDates is already up to date here,
  so this is the right place to read the full selection. }
procedure TForm1.DoSelectDate(Sender: TObject; ADate: TDate);
begin
  StatusLabel.Text := Format('%s selected (%d day(s) in total)',
    [DateToStr(ADate), TMSFNCCalendar1.SelectedDates.Count]);
end;

{ Fires once for a range selection - either SelectMultiDates or a shift-click
  drag - instead of once per day. AStartDate and AEndDate are the range bounds. }
procedure TForm1.DoSelectMultiDate(Sender: TObject; AStartDate, AEndDate: TDate);
begin
  StatusLabel.Text := Format('Range %s - %s',
    [DateToStr(AStartDate), DateToStr(AEndDate)]);
  SaveDateRange(AStartDate, AEndDate);
end;
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  TMSFNCCalendar1->Interaction->MultiSelect = true;

  TMSFNCCalendar1->OnBeforeSelectDate = DoBeforeSelectDate;
  TMSFNCCalendar1->OnSelectDate       = DoSelectDate;
  TMSFNCCalendar1->OnSelectMultiDate  = DoSelectMultiDate;
}

// Fires once per date, just before it is added to SelectedDates. The handler has
// no cancel parameter, so use it to observe or prefetch only - block a date with
// MinDate / MaxDate or Interaction.ReadOnlyMode instead.
void __fastcall TForm1::DoBeforeSelectDate(TObject *Sender, TDate ADate)
{
  StatusLabel->Text = "Loading agenda for " + DateToStr(ADate);
}

// Fires after the date has been added. SelectedDates is already up to date here,
// so this is the right place to read the full selection.
void __fastcall TForm1::DoSelectDate(TObject *Sender, TDate ADate)
{
  StatusLabel->Text = Format("%s selected (%d day(s) in total)",
    ARRAYOFCONST((DateToStr(ADate), TMSFNCCalendar1->SelectedDates->Count)));
}

// Fires once for a range selection - either SelectMultiDates or a shift-click
// drag - instead of once per day. AStartDate and AEndDate are the range bounds.
void __fastcall TForm1::DoSelectMultiDate(TObject *Sender, TDate AStartDate, TDate AEndDate)
{
  StatusLabel->Text = Format("Range %s - %s",
    ARRAYOFCONST((DateToStr(AStartDate), DateToStr(AEndDate))));
  SaveDateRange(AStartDate, AEndDate);
}

Note

OnBeforeSelectDate carries no cancel parameter, so it cannot veto a selection. Prevent a date from being selected with MinDate / MaxDate, or block selection entirely with Interaction.ReadOnlyMode.


Combining limits, range selection and events

Date limits, multi-select and the selection events are designed to work together. Limits decide which dates can ever be chosen, MultiSelect and SelectMultiDates decide how many, and the events let the rest of the form follow along. Use the combination for booking and planning screens, where a range such as a holiday or a stay must stay inside an allowed window and a summary label has to show what was picked. The sample enables multi-select, restricts the calendar to 2024-2026, pre-selects a range and updates a status label when the user selects a new range.

Combine date limits, range selection and selection eventsPascalC++
procedure TForm1.SetupSelectionCombined;
begin
  // Interaction options and limits
  TMSFNCCalendar1.Interaction.MultiSelect := True;
  TMSFNCCalendar1.Interaction.KeyboardSupport := True;
  TMSFNCCalendar1.MinDate := EncodeDate(2024, 1, 1);
  TMSFNCCalendar1.MaxDate := EncodeDate(2026, 12, 31);

  // Pre-select a range inside the limits and react to later range selections
  TMSFNCCalendar1.Date := EncodeDate(2025, 6, 1);
  TMSFNCCalendar1.SelectMultiDates(EncodeDate(2025, 6, 2), EncodeDate(2025, 6, 6));
  TMSFNCCalendar1.OnSelectMultiDate := DoSelectRangeCombined;
end;

procedure TForm1.DoSelectRangeCombined(Sender: TObject; AStartDate, AEndDate: TDate);
begin
  StatusLabel.Text := Format('%s - %s (%d day(s) selected)',
    [DateToStr(AStartDate), DateToStr(AEndDate),
     TMSFNCCalendar1.SelectedDates.Count]);
end;
void __fastcall TForm1::SetupSelectionCombined()
{
  // Interaction options and limits
  TMSFNCCalendar1->Interaction->MultiSelect = true;
  TMSFNCCalendar1->Interaction->KeyboardSupport = true;
  TMSFNCCalendar1->MinDate = EncodeDate(2024, 1, 1);
  TMSFNCCalendar1->MaxDate = EncodeDate(2026, 12, 31);

  // Pre-select a range inside the limits and react to later range selections
  TMSFNCCalendar1->Date = EncodeDate(2025, 6, 1);
  TMSFNCCalendar1->SelectMultiDates(EncodeDate(2025, 6, 2), EncodeDate(2025, 6, 6));
  TMSFNCCalendar1->OnSelectMultiDate = DoSelectRangeCombined;
}

void __fastcall TForm1::DoSelectRangeCombined(TObject *Sender, TDate AStartDate, TDate AEndDate)
{
  StatusLabel->Text = Format("%s - %s (%d day(s) selected)",
    ARRAYOFCONST((DateToStr(AStartDate), DateToStr(AEndDate),
      TMSFNCCalendar1->SelectedDates->Count)));
}

See also