我已经创建了一个基于TPaintBox的组件,TGridPaintBox.它基本上是一个添加了“网格功能”的paintBox.它不是数据网格.更像棋盘组件.
在对象资源管理器中,我可以设置某些属性.最重要的是我可以设置网格尺寸(跨/下两个单元格),还可以设置与图形有关的选项.细胞是否应该是正方形,奇/偶细胞的颜色等
我的这个组件的第一个版本的属性直接在类上,当我更改了一个属性时,设计时间图被立即更新.随着组件的增长,我想组织我的属性一点更好,并介绍了一些“选项属性”,如绘图选项,行为选项等.介绍后,设计时间图不再像以前一样更新.更改属性后,我必须单击要更新的组件.谁能告诉我为什么会发生这种情况?
(PS:这是我的第一个组件,即使我自1997年以来一直在使用Delphi,所以如果任何人可以按照我的方式发现任何愚蠢的事情,请随时告诉我)
unit GridPaintBox; interface type TGridDrawOption = (gdoSquareCells,gdoCenterCells,gdoDrawCellEdges,gdoDrawFocus); TGridDrawOptions = set of TGridDrawOption; TGridOptions = class(TPersistent) private FCellsX : integer; FCellsY : integer; FDrawOptions : TGridDrawOptions; public constructor Create(aGridPaintBox : TGridPaintBox); procedure Assign(Source : TPersistent); override; published property CellsX : integer read FCellsX write FCellsX; property CellsY : integer read FCellsY write FCellsY; property DrawOptions : TGridDrawOptions read FDrawOptions write FDrawOptions; end; TGridPaintBox = class(TPaintBox) private FGridOptions : TGridOptions; FFocusedX,FFocusedY : integer; FOnFocusChanged: TNotifyEvent; procedure CalculateSizeAndPosition; procedure DrawCell(X,Y : integer); procedure DrawCells; procedure SetGridOptions(const Value: TGridOptions); protected procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override; public constructor Create(aOwner : TComponent); override; destructor Destroy; override; procedure Paint; override; procedure SetFocus(X,Y : integer); published property OnFocusChanged : TNotifyEvent read FOnFocusChanged write FOnFocusChanged; property Options : TGridOptions read FGridOptions write SetGridOptions; end; procedure Register; implementation procedure Register; begin RegisterComponents('Samples',[TGridPaintBox]); end; procedure TGridPaintBox.CalculateSizeAndPosition; begin <...> end; constructor TGridPaintBox.Create(aOwner: TComponent); begin inherited; FGridOptions := TGridOptions.Create(self); end; procedure TGridPaintBox.DrawCell(X,Y: integer); begin <...> end; procedure TGridPaintBox.DrawCells; var X,Y : integer; begin CalculateSizeAndPosition; for Y := 0 to FGridOptions.CellsY-1 do for X := 0 to FGridOptions.CellsX-1 do DrawCell(X,Y); end; procedure TGridPaintBox.Paint; begin Canvas.Font := Font; Canvas.Brush.Color := Color; Canvas.Brush.Style := bsSolid; Canvas.FillRect(Rect(0,Width,Height)); DrawCells; if Assigned(OnPaint) then OnPaint(Self); end; procedure TGridPaintBox.SetGridOptions(const Value: TGridOptions); begin FGridOptions.Assign(Value); invalidate; end; procedure TGridPaintBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); begin SetFocus(PixelToCellX(X),PixelToCellY(Y)); inherited; end; procedure TGridPaintBox.SetFocus(X,Y: integer); begin if (FocusedX=X) and (FocusedY=Y) then exit; FFocusedX := X; FFocusedY := Y; if assigned(OnFocusChanged) then OnFocusChanged(self); invalidate; end; constructor TGridOptions.Create(aGridPaintBox : TGridPaintBox); begin FCellsX := 20; FCellsY := 8; FDrawOptions := [gdoSquareCells,gdoDrawCellEdges]; end; procedure TGridOptions.Assign(Source : TPersistent); begin if Source is TGridOptions then begin FCellsX := TGridOptions(Source).CellsX; FCellsY := TGridOptions(Source).CellsY; FDrawOptions := TGridOptions(Source).DrawOptions; end else inherited; end; end.
解决方法
这是因为您没有一个选项集的setter,这将使您的控件属于无效.表单设计器中的点击调用控件无效,但是您应该在这样的选项设置器中由您自己处理.所以我会存储选项所有者更好地访问直接的所有者类实例,并在选项设置器强制这个所有者,控件重绘:
type TGridPaintBox = class; TGridDrawOption = (gdoSquareCells,gdoDrawFocus); TGridDrawOptions = set of TGridDrawOption; TGridOptions = class(TPersistent) private FOwner: TGridPaintBox; FCellsX: Integer; FCellsY: Integer; FDrawOptions: TGridDrawOptions; procedure SetCellsX(AValue: Integer); procedure SetCellsY(AValue: Integer); procedure SetDrawOptions(const AValue: TGridDrawOptions); public constructor Create(AOwner: TGridPaintBox); procedure Assign(ASource: TPersistent); override; published property CellsX: Integer read FCellsX write SetCellsX; property CellsY: Integer read FCellsY write SetCellsY; property DrawOptions: TGridDrawOptions read FDrawOptions write SetDrawOptions; end; implementation constructor TGridOptions.Create(AOwner: TGridPaintBox); begin FOwner := AOwner; FCellsX := 20; FCellsY := 8; FDrawOptions := [gdoSquareCells,gdoDrawCellEdges]; end; procedure TGridOptions.SetCellsX(AValue: Integer); begin if FCellsX <> AValue then begin FCellsX := AValue; FOwner.Invalidate; end; end; procedure TGridOptions.SetCellsY(AValue: Integer); begin if FCellsY <> AValue then begin FCellsY := AValue; FOwner.Invalidate; end; end; procedure TGridOptions.SetDrawOptions(const AValue: TGridDrawOptions); begin if FDrawOptions <> AValue then begin FDrawOptions := AValue; FOwner.Invalidate; end; end;
进一步说明:
如果您不明确需要绘制框的发布属性和事件,例如Color,Font或OnPaint事件,则从TGraphicControl而不是TPaintBox导出控件.您可以选择自己发布的属性和事件.