TDateTimePicker 中的另一个错误?

Another bug in TDateTimePicker?

我发现将 TDateTimePicker 的 MaxDate 设置为非零值后,无法将其恢复为零(禁用它)。我的意思是,MaxDate 读数为零,但最大范围对于之前设置的值仍然有效。这可以通过下拉日历并检查最后可见日期来注意到。

这是另一个错误,还是我不明白如何禁用 MaxDate?

procedure TForm1.Button1Click(Sender: TObject);
begin
 DateTimePicker1.MaxDate:= Date + 10;
 DateTimePicker1.MaxDate:= 0;
 Caption:= IntToStr(Trunc(Test.MaxDate));
end;

P.S:我首先负责将时间设置为零(这是另一个错误)。

以下未被 MSDN 记录(并且是偶然发现的),但它似乎有效(至少在 Windows 7 上)。您可以尝试调用以下宏(或发送相应的消息)来取消日期时间选择器控件的时间范围限制:

DateTime_SetRange(DateTimePicker1.Handle, 0, nil);

我幸运的意外试验开始于在发送 DTM_SETRANGE 消息指向任何时间范围(因此我将 0nil 传递给宏)。

如果您将此作为一种可能的解决方法,VCL 剩下的就是重置内部字段值,例如制作小帮手可能会变成:

uses
  CommCtrl;

type
  TDateTimePickerHelper = class helper for TDateTimePicker
  public
    procedure ResetRange;
  end;

implementation

{ TDateTimePickerHelper }

procedure TDateTimePickerHelper.ResetRange;
var
  DateRange: array[0..1] of TDate;
begin
  DateRange[0] := MinDate; { ← store the current MinDate }
  DateRange[1] := MaxDate; { ← store the current MaxDate }

  MinDate := 0; { ← set the control's MinDate internal field to 0 }
  MaxDate := 0; { ← set the control's MaxDate internal field to 0 }

  if not DateTime_SetRange(Handle, 0, nil) then { ← if the macro fails, then... }
  begin
    MinDate := DateRange[0]; { ← restore the previous MinDate internal field value }
    MaxDate := DateRange[1]; { ← restore the previous MaxDate internal field value }
  end;
end;

然后使用它来重置范围:

procedure TForm1.Button1Click(Sender: TObject);
begin
  DateTimePicker1.ResetRange;
end;

Victoria accidentally that the Win32 Date and Time Picker control 可以通过使用未记录的技巧来重置其范围。

但是,Victoria 的答案在 Delphi 10.2 中不起作用,因为 VCL 包装器的内部最大和最小字段未正确重置为 0。将 MinDateMaxDate 属性更改为 0 没有用——这不会将 FMinDateFMaxDate 字段设置为 0 由于 属性 setter 的实施。

这将使该点之后的控制出现故障。

解决方法是直接设置字段(我还稍微调整了 Victoria 的逻辑以使代码更简洁):

type
  TCommonCalendarHelper = class helper for TCommonCalendar
    procedure ResetRangeFields;
  end;

  TDateTimePickerHelper = class helper for TDateTimePicker
  public
    procedure ResetRange;
  end;

{ TDateTimePickerHelper }

procedure TDateTimePickerHelper.ResetRange;
begin
  if DateTime_SetRange(Handle, 0, nil) then
    ResetRangeFields;
end;

{ TCommonCalendarHelper }

procedure TCommonCalendarHelper.ResetRangeFields;
begin
  with Self do
  begin
    FMinDate := 0;
    FMaxDate := 0;
  end;
end;

with 构造在这里非常必要,请参阅 。)

试试这个:

procedure TForm1.FormClick(Sender: TObject);
begin
  DateTimePicker1.MaxDate := IncDay(Now, 4);
  // DateTimePicker1.ResetRange; // uncomment to see resetting in action
end;

当然,此代码依赖于未记录的 Win32 功能和 VCL 实现细节。不过,危险可能相当小。有关此主题的更深入讨论,请参阅 Victoria post 上的评论。如果您知道 VCL 版本,那么(仅)使用此代码可能是合理的。 (您甚至可以让它在未来的 VCL 版本上不编译。)