2012-06-10 24 views
12

Tôi đã tạo một thành phần, TGridPaintBox, dựa trên TPaintBox. Về cơ bản nó là một hộp sơn có thêm "chức năng lưới". Nó không phải là một lưới dữ liệu. Giống như một thành phần của bàn cờ.Tại sao bản cập nhật thành phần tùy chỉnh của tôi không thay đổi khi tôi thay đổi các thuộc tính?

Trong trình khám phá đối tượng, tôi có thể đặt các thuộc tính nhất định. Quan trọng nhất là tôi có thể thiết lập kích thước lưới (bao nhiêu ô trên/xuống), nhưng cũng có các tùy chọn liên quan đến bản vẽ. Cho dù các ô phải là hình vuông, màu của các ô lẻ/chẵn, vv

Phiên bản đầu tiên của thành phần này có thuộc tính trực tiếp trên lớp và khi tôi thay đổi thuộc tính, bản vẽ designtime được cập nhật ngay lập tức. Khi thành phần phát triển, tôi muốn tổ chức các thuộc tính của mình tốt hơn một chút và giới thiệu một số "thuộc tính tùy chọn", như các tùy chọn vẽ, tùy chọn hành vi, v.v. Sau khi giới thiệu, bản vẽ designtime không còn cập nhật như trước nữa. Sau khi thay đổi thuộc tính, tôi phải bấm vào thành phần để nó cập nhật. Bất cứ ai có thể cho tôi biết lý do tại sao điều này xảy ra?

Đây là phiên bản rút gọn của mã. Tôi hy vọng nó sẽ giải thích hành vi:

(PS: Đây là thành phần đầu tiên của tôi, mặc dù tôi đã sử dụng Delphi từ năm 1997, vì vậy nếu ai đó có thể phát hiện bất cứ điều gì ngu ngốc theo cách tôi đã làm miễn phí cho tôi biết)

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. 

Trả lời

13

Điều này xảy ra vì bạn không có setter cho bộ tùy chọn sẽ làm mất hiệu lực quyền kiểm soát của bạn. Tuy nhiên, cú nhấp chuột trong trình thiết kế biểu mẫu yêu cầu điều khiển làm mất hiệu lực, nhưng bạn nên xử lý điều này theo cách riêng của bạn trong trình thiết lập tùy chọn như vậy. Vì vậy, tôi sẽ lưu trữ các chủ sở hữu lựa chọn để tiếp cận tốt hơn với các trường hợp chủ sở hữu lớp trực tiếp và trong các tùy chọn setter buộc chủ sở hữu này, sự kiểm soát để vẽ lại:

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; 

Tiếp tục ghi chú:

Nếu bạn không rõ ràng cần có các thuộc tính và sự kiện được xuất bản của hộp sơn như ví dụ: Color, Font hoặc OnPaint sự kiện, lấy được sự kiểm soát của bạn từ TGraphicControl thay vì từ TPaintBox. Bạn có thể chọn những thuộc tính và sự kiện nào bạn sẽ tự xuất bản.

+1

Vâng, lỗi chính tả. Đó là thực sự trong lớp TGridPaintBox, nhưng tôi sai lầm khi chỉnh sửa cho bài đăng này. Tôi sẽ cập nhật câu hỏi của mình. –

+1

Ngoài ra, cảm ơn cho tip về bắt nguồn từ TGraphicControl hơn là TPaintBox. Và tất nhiên, cảm ơn phần còn lại của câu trả lời. Nó giải quyết vấn đề của tôi :-) –

Các vấn đề liên quan