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 消息指向任何时间范围(因此我将 0 和 nil 传递给宏)。
如果您将此作为一种可能的解决方法,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
。将 MinDate
和 MaxDate
属性更改为 0
没有用——这不会将 FMinDate
和 FMaxDate
字段设置为 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 版本上不编译。)
我发现将 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 消息指向任何时间范围(因此我将 0 和 nil 传递给宏)。
如果您将此作为一种可能的解决方法,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
但是,Victoria 的答案在 Delphi 10.2 中不起作用,因为 VCL 包装器的内部最大和最小字段未正确重置为 0
。将 MinDate
和 MaxDate
属性更改为 0
没有用——这不会将 FMinDate
和 FMaxDate
字段设置为 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 版本上不编译。)