1

I am currently creating a program with Delphi (Professional, Version 7.0; Build 4.453).

Originally, I wanted to bold some dates in the TDateTimePicker dropdown calendar; but I quickly found out that I couldn't - so I'm trying to overlap a TMonthCalendar (with which you can do bold dates) on top of the TDateTimePicker dropdown calendar (simple, right?)

But not so fast: somehow, the TDateTimePicker dropdown calendar always shows up ON TOP of my TMonthCalendar. I would like to have the TMonthCalendar show up on top instead.

Here is what I figured I could do:

  1. Position TMonthCalendar under the TDateTimePicker (where its dropdown would usually show)
  2. Make visible the TMonthCalendar on the TDateTimePicker's OnDropDown event
  3. Hide the TMonthCalendar on the TDateTimePicker's OnCloseUp event

Here is what is happening:

  1. When I click on the dropdown triangle on the TDateTimePicker, the TMonthCalendar becomes visible (yay!)
  2. But the TDateTimePicker dropdown calendar always takes precedent (TMonthCalendar is always underneath the dropdown)
  3. Therefore I can't do anything with the TMonthCalendar until I've picked a date on the TDateTimePicker dropdown (I can't even see the bolded dates because TMonthCalendar is underneath).

Here is what I've tried:

  • TMonthCalendar.Show on the OnDropDown event of the TDateTimePicker (this is supposed to bring whatever is Show-ed to the top). But this does nothing.
  • Do DateMode: dmDropDown -> DateMode: dmUpDown on TDateTimePicker's OnDropDown (thus disabling the dropdown calendar). But this has problems since clicking anywhere on the MonthCalendar (including the change Month buttons on either side of the top) will render the MonthCalendar to become invisible (I'm doing "if MonthCalendar.Visible then visible := false" in MonthCalendarOnClick)

I know the solution is probably simple, but I can't think of a way to do this. So far the few ideas that I've come up with aren't working :( So if you can think of of a way to do what I want, please help me out.

Thank you in advance! :)

jsp
  • 11
  • 1
  • 2
  • Don't go down this road. `TMonthCalendar` is a thin wrapper around the Win32 month calendar control. `TDateTimePicker` is a thin wrapper around the Win32 date time picker control, which internally creates a month calendar control when needed. It's possible (and not all that hard) to get access to that internal month calendar control and do whatever you want with it, including everything you can do with a `TMonthCalendar`. Just look at how `TMonthCalendar` does it, and then do the same thing for your own control. (I'd post an example, but I'm not on a system where I could test it right now.) –  Feb 09 '14 at 13:50
  • This approach is never going to yield good results – David Heffernan Feb 09 '14 at 13:54
  • Possible duplicate, [`How do you programmatically mark a date in Delphi's TDateTimePicker's calendar?`](http://stackoverflow.com/q/7210565/576719). – LU RD Feb 09 '14 at 14:15

1 Answers1

2

The entire premise of your question is wrong. It is perfectly possible to modify the formatting of the month calendar attached to the date time picker.

The solution is to respond to the MCN_GETDAYSTATE notification. Only controls that have the MCS_DAYSTATE style are sent this notification. To make sure that this style is applied, even in the face of window re-creation, you need to apply it in an overridden CreateWnd method.

For example, here I do it with an interposer:

type
  TDateTimePicker = class(Vcl.ComCtrls.TDateTimePicker)
  protected
    procedure CreateWnd; override;
    procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
  end;

procedure TDateTimePicker.CreateWnd;
begin
  inherited;
  DateTime_SetMonthCalStyle(WindowHandle, DateTime_GetMonthCalStyle(WindowHandle) or MCS_DAYSTATE);
end;

procedure TDateTimePicker.WMNotify(var Message: TWMNotify);
var
  i: integer;
  NMDayState: PNMDayState;
begin
  inherited;
  case Message.NMHdr.code of
  MCN_GETDAYSTATE:
    begin
      NMDayState := PNMDayState(Message.NMHdr);
      for i := 0 to NMDayState.cDayState-1 do begin
        NMDayState.prgDayState[i] := $FFFFFFFF; // every day is bold
      end;
    end;
  end;
end;

enter image description here

Or with a bit mask of $AAAAAAAA to have only even numbered days bold:

enter image description here

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • As noted on the comments on the answer to the other question (the question that this one should be closed as a duplicate of), this won't work on XP. It is possible to make it work on XP by getting the window handle for the contained month calendar, and changing its style directly, in addition to (not instead of) using `DateTime_SetMonthCalStyle`. –  Feb 09 '14 at 15:24
  • @hvd OK. I think we can start forgetting about XP very soon. Thankfully. – David Heffernan Feb 09 '14 at 15:30
  • 2
    I wouldn't count on XP dying the moment MS stops supporting it. That's just when some users will even *consider* upgrading. It may still take months for them to actually do so, and I do wish it wouldn't. –  Feb 09 '14 at 15:35
  • @hvd In this case you could probably not bother with XP and give those users a less capable UI – David Heffernan Feb 09 '14 at 15:40
  • @hvd FWIW I don't see XP at all these days with my users and in fact I very rarely see 32 bit systems. – David Heffernan Feb 09 '14 at 21:22
  • @David, that your users doesn't have XP doesn't mean that about 11% of users do. Btw. Windows XP had a 64-bit version so the note about bitness is a bit unrelated here. – TLama Feb 09 '14 at 21:39
  • @TLama I'm just surprised that XP has gone away so quickly for my users. Was dominant only two years ago. Windows 7 killed it. The 64 bit XP doesn't count for much. It was a rather lame server 2003 version with a quaint WOW64 and no driver support. Nobody uses it. – David Heffernan Feb 09 '14 at 21:43
  • @David, but you are (or at least were) working for industrial area (as far as I remember) where equipment usually follows the trends, so I wouldn't be much surprised. If you were developing an application for public use, you would certainly want to support XP. – TLama Feb 09 '14 at 21:48
  • @tlama Depends. Home users tend to be quicker to migrate and upgrade. Perhaps government are a bit slower. Industry tends to be slower than home users. I'm confident that XP can be ignored 12 months from now. It cannot come soon enough!!! – David Heffernan Feb 09 '14 at 21:50
  • Thank you everybody for your insight! I realized that it was very similar to the one you marked this a duplicate of, so I'm sorry if I frustrated any of you. The other answer was the one that I spent the most time reading (and trying to figure out), so maybe there was something I missed there. The reason, though, I decided to ask this one anyways was because I am using XP. I noticed a lot of discussion on XP here, but that's what I'm using, and possibly older - that's out of my control. I just couldn't figure out how to do it pre-XP in the other answer. Am I missing something? – jsp Feb 11 '14 at 16:05
  • It's easy enough to do it in XP. Too bad you didn't mention that up front. – David Heffernan Feb 11 '14 at 16:09