type
TDBCalendar = class(TCalendar)
private
FReadOnly: Boolean;
published
property ReadOnly: Boolean read FReadOnly write FReadOnly default True;
end;
constructor TDBCalendar.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FReadOnly := True;
end;
function TDBCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if FReadOnly then Result := False // 封鎖使用者選擇
else Result := inherited SelectCell(ACol, ARow);
end;
設計期預設 ReadOnly = True,SelectCell 回傳 False 直接取消儲存格進入,滑鼠/鍵盤操作完全無效。
問題:UpdateCalendar 內部設定 Row/Col 同步日期顯示,但被 SelectCell 封鎖。
解決:引入 FUpdating 旗標區分使用者操作與程式更新:
type
TDBCalendar = class(TCalendar)
private
FUpdating: Boolean;
protected
function SelectCell(ACol, ARow: Longint): Boolean; override;
public
procedure UpdateCalendar; override;
end;
function TDBCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if (not FUpdating) and FReadOnly then Result := False
else Result := inherited SelectCell(ACol, ARow);
end;
procedure TDBCalendar.UpdateCalendar;
begin
FUpdating := True;
try
inherited UpdateCalendar; // 正常同步 Row/Col
finally
FUpdating := False; // 保證旗標重置
end;
end;
try...finally 確保異常情況下旗標必歸零,避免永久解除唯讀保護。
type
TDBCalendar = class(TCalendar)
private
FDataLink: TFieldDataLink;
function GetDataField: string;
function GetDataSource: TDataSource;
procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);
published
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write SetDataSource;
end;
function TDBCalendar.GetDataField: string;
begin Result := FDataLink.FieldName; end;
function TDBCalendar.GetDataSource: TDataSource;
begin Result := FDataLink.DataSource; end;
procedure TDBCalendar.SetDataField(const Value: string);
begin FDataLink.FieldName := Value; end;
procedure TDBCalendar.SetDataSource(Value: TDataSource);
begin FDataLink.DataSource := Value; end;
委派給 FDataLink 同名屬性,零邏輯薄封裝,符合 VCL 資料感知元件標準契約。