2012-06-10 136 views
12

我創建了一個組件,TGridPaintBox,基於TPaintBox。它基本上是一個添加了「網格功能」的繪圖箱。這不是數據網格。更像是一個棋盤組件。當我更改屬性時,爲什麼不更新我的自定義組件?

在對象資源管理我可以設置某些性能。最重要的是,我可以設置網格的尺寸(多少個單元格跨/下),還有與繪圖有關的選項。無論是細胞應該是正方形,奇/偶細胞等

我這個組件的第一個版本的顏色直接對類的屬性,當我更改的屬性,在設計時繪製立即更新。隨着組件的不斷增長,我希望能夠更好地組織我的屬性,並引入一些「選項屬性」,如繪圖選項,行爲選項等。介紹完這些之後,設計時繪圖不再像以前那樣更新。更改屬性後,我必須點擊組件才能更新。誰能告訴我爲什麼會發生這種情況?

下面的代碼的精簡版。我希望它能解釋這種行爲:

(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,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,gdoCenterCells,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. 

回答

13

它發生,因爲你沒有setter的選項設置,這將使您的控制屬於。然而,表單設計器中的點擊會調用控件來使其無效,但是您應該在自己的選項設置器中自行處理。因此,我將存儲的選項所有者的直接所有者類實例,並在選項設定裝置強制此車主更好的訪問,控制重繪:

type 
    TGridPaintBox = class; 
    TGridDrawOption = (gdoSquareCells, gdoCenterCells, gdoDrawCellEdges, 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, gdoCenterCells, 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; 

其它注意事項:

如果您沒有明確需要有漆箱」公佈屬性和事件例如像ColorFontOnPaint事件,從TGraphicControl而不是從TPaintBox派生您控制。你可以選擇你自己發佈的屬性和事件。

+1

呀,錯字。它實際上是在TGridPaintBox類中,但是在編輯這篇文章時我搞砸了。我會更新我的問題。 –

+1

另外,感謝關​​於派生自TGraphicControl而不是TPaintBox的提示。當然,謝謝你的答案。它解決了我的問題:-) –

相關問題