具有布尔类型的可为空的数据集字段,如何在链接到此字段的NULL控件后代中以未检查状态显示其TDBCheckBox值。默认情况下,TDBCheckBox将字段的NULL值显示为灰色复选框:



但我需要在TDBCheckBox控件后代中将其显示为未选中状态:



修改原始TDBCheckBox源代码不是我的选择,也不能覆盖TDBCheckBox.GetFieldState,因为它是私有方法。

因此,如何在NULL后代中将TDBCheckBox值显示为未经检查的状态?

最佳答案

如果您的项目是封闭源代码,建议您复制一份DBCtrls,将其改为Result := cbGrayed,并将其明确添加到项目中。更改将在您的整个应用程序中进行,但不会更改原始代码。

然而,还有另一种方式-实际上是一个黑客,所以要当心,我建议放置一个编译器指令,以防止将此指令编译到其他Delphi版本中,从而要求再次查看该代码并确保其有效。

这是在Delphi XE中可用的代码-在Delphi 6中看起来可能有所不同,但是您会明白的。

type
  TDBCheckBoxHack = class(TCustomCheckBox)
  private
    FDataLink: TFieldDataLink;
    FValueCheck: string;
    FValueUncheck: string;
    procedure DataChange(Sender: TObject);
    function GetFieldState: TCheckBoxState;
    function ValueMatch(const ValueList, Value: string): Boolean;
  end;


我忽略了这些方法的实现,因为它们只是原始受版权保护的代码的副本。您必须在GetFieldState方法中更改一两行。

诀窍是创建与原始TDBCheckBox相同的内存布局,以便您可以访问私有字段-这就是为什么应谨慎使用此代码的原因!

然后,将固定的DataChange方法分配给数据链接:

TDBCheckBoxHack(DBCheckBox1).FDataLink.OnDataChange :=
  TDBCheckBoxHack(DBCheckBox1).DataChange;


为了使它更易于使用,您可以使用从原始TDBCheckBox继承的另一种技巧,并完全相同地调用您的类。然后,您可以将其放入某个单元中,并在使用时将其添加到DBCtrls之后。这将导致为您放置在窗体上的每个TDBCheckBox调用构造函数,而无需使用自己的构造函数并将其注册到IDE:

type
  TDBCheckBox = class(DBCtrls.TDBCheckBox)
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TDBCheckBox.Create(AOwner: TComponent);
begin
  inherited;
  TDBCheckBoxHack(Self).FDataLink.OnDataChange := TDBCheckBoxHack(Self).DataChange;
end;

07-27 14:53