最近在工作中使用 TStringGrid 时遇到个比较特殊的需求:要求 Grid 中某些 Cell 只能用鼠标点击来控制其内容(开关切换),而其它的 Cell 则允许用户编辑内容。查看 D7 下的 TStringGrid,没有发现能直接实现该需求的办法,于是分析一下 VCL 源码,并通过以下简单的方法实现了该需求。现帖上来与大家交流。
具体的实现是在使用该 Grid 的窗体单元中,增加以下代码:
TEditShowEvent = procedure (var CanShow: Boolean) of object;
// 增加了控制编辑框是否允许事件的 StringGrid
TStringGrid = class(Grids.TStringGrid)
private
FOnEditShow: TEditShowEvent;
protected
function CanEditShow: Boolean; override;
public
property OnEditShow: TEditShowEvent read FOnEditShow write FOnEditShow;
end;
implementation
{ TStringGrid }
function TStringGrid.CanEditShow: Boolean;
begin
Result := inherited CanEditShow;
if Assigned(FOnEditShow) then
FOnEditShow(Result);
if not Result then
EditorMode := False;
end;
基本思路如下:
因为不希望注册新的 IDE 控件,所以在窗体中使用了同名类覆盖的小技巧,通过声明 TStringGrid = class(Grids.TStringGrid) 在窗体中为 VCL 的 TStringGrid 派生出一个同名的类,但是增加了一个 OnEditShow 事件。新的控件通过 override CanEditShow 方法来产生事件供用户使用。使用时,通过代码的方式手动为该 Grid 关联 OnEditShow 事件并在其中对 Cell 位置进行判断以解决原始需求。
补充:
这个新的 TStringGrid 类是跟 Form 的定义在同一个单元的,针对窗体上已经放置的 TStringGrid 控件有效。之所以使用这种方式,一是不想注册新的 IDE 控件,二是不想手工动态创建新定义的控件。