【问题标题】:Another bug in TDateTimePicker?TDateTimePicker 中的另一个错误?
【发布时间】:2018-08-15 11:56:01
【问题描述】:

我发现在我将 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:我先把时间设置为零(这是另一个错误)。

【问题讨论】:

  • 是的,这似乎是一个错误,至少在我目前正在使用的 Delphi 10.2 中。
  • 但即使是底层 Win32 控件的 MSDN 文档也无济于事......
  • 这就是我所害怕的......所以,我认为,唯一的解决方案是将 MaxDate 设置为我永远不会在我的应用程序中使用的更高值......
  • 实际上,我对 MSDN 文档的质量差感到有点惊讶。尽管如此,控件的最大值似乎是9999-12-31(同时使用控件和使用DateTime_SetRange)。
  • 您可以调用DateTime_SetRange(DateTimePicker1.Handle, 0, nil) 删除范围。另一件事是重置保存范围的内部字段。

标签: delphi datetimepicker delphi-2009


【解决方案1】:

Victoriadiscovered 偶然发现 Win32 Date and Time Picker control 可以通过使用未记录的技巧重置其范围。

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

这将使控制在该点之后发生故障。

一种解决方法是直接设置字段(我还稍微调整了 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 结构在这里非常必要,请参阅https://stackoverflow.com/a/42936824/282848。)

试试这个:

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

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

【讨论】:

  • 我很难选择答案,因为两者都在我的 Delphi 版本中工作。我会接受 Victoria 的回答,因为她发现了这个技巧,并为您 +1 重置内部字段的方法。
【解决方案2】:

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

DateTime_SetRange(DateTimePicker1.Handle, 0, nil);

我的幸运意外试验开始时没有使用 GDTR_MINGDTR_MAX 标志发送 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;

【讨论】:

  • 您确定将MaxDate 设置为0 实际上会将FMaxDate 字段设置为0
  • 仍然,+1 用于发现重置本机 Win32 控件范围设置的方法,并尽可能负责任地使用未记录的 hack。
  • @AndreasRejbrand,这在您的 Delphi 10.2 中有效吗?起初,当我尝试维多利亚的DateTime_SetRange(Handle, 0, nil) 时,我也很失望,因为内部字段仍然设置。但在那之后,我看到给他们分配零就可以了。那么,除此之外,您的 Delphi 版本中是否还有其他错误?
  • @Marus Nebunu:维多利亚的回答在 Delphi 10.2 中不起作用。当MaxValue 属性设置为0 时,FMaxValue 字段设置为0.99999 或类似的值,因此VCL 仍会认为设置了最大值,即使Win32 控件没有设置。当我尝试DateTimePicker1.MaxDate := IncDay(Now, 4); DateTimePicker1.ResetRange; 时,我很快就收到了一条错误消息。
  • 但是由于 Win32 技巧未记录在案,并且 Victoria 和我的班级助手依赖 VCL 实现细节,因此您无法保证这些变通办法在 Delphi 和 Windows 的未来版本中继续有效,即使它们将在所有当前版本中完美运行。但好消息是 Victoria 和我都检查了 DateTime_SetRange 的返回值,所以如果 Microsoft 改变它的实现,我们将合理地优雅地失败(虽然不太可能,因为可能有太多的应用程序依赖它,而 Win32 桌面是反正不是最热门的东西)。
猜你喜欢
  • 2016-10-15
  • 2023-03-22
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 2012-11-06
  • 1970-01-01
  • 2014-08-27
相关资源
最近更新 更多