Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8056719
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 5, 20262026-06-05T08:48:10+00:00 2026-06-05T08:48:10+00:00

I have created a component, TGridPaintBox, based on TPaintBox. It is basically a paintbox

  • 0

I have created a component, TGridPaintBox, based on TPaintBox. It is basically a paintbox with added “grid functionality”. It’s not a data grid. More like a chess board component.

In the object explorer I can set certain properties. Most importantly I can set the grid dimensions (how many cells across/down), but also options relating to drawing. Whether the cells should be square, the color of odd/even cells etc.

My first version of this component had properties directly on the class, and when I changed a property, the designtime drawing was updated immediately. As the component grew, I wanted to organize my properties a little better, and introduced some “options properties”, like drawing options, behaviour options etc. After introducing this, the designtime drawing no longer updates like before. After changing a property, I have to click on the component for it to update. Can anyone tell me why this happens?

Here’s a stripped down version of the code. I hope it will explain the behaviour:

(PS: This is my first component, even though I’ve been using Delphi since 1997, so if anyone can spot anything stupid in the way I’ve done it, please feel free to tell me)

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.
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-05T08:48:12+00:00Added an answer on June 5, 2026 at 8:48 am

    It happens because you don’t have a setter for the options set which would invalidate your control which belongs to. The click in the form designer invokes the control to invalidate though, but you should handle this by your own in such options setter. So I would store the options owner for better access to the direct owner class instance and in the options setter force this owner, the control to redraw:

    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;
    

    Further notes:

    If you don’t explicitly need to have paint box’ published properties and events like for instance Color, Font or OnPaint event, derive your control from TGraphicControl instead of from TPaintBox. You can choose what properties and events will you publish by your own.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have created a transformation component, and basically it accepts data from a source,
I have created a reddot cms component, in which I added this line Also,
I have created a custom component based on spark.components.HGroup and it works mostly as
I'm using Joomla 1.5. I have created a custom component that pulls data out
I have created a component for table row and added in to another activity.it's
I have created a composite component in JSF2. I works great. I would like
I have created a custom component that I am using, more conveniently, as a
I have created a Box component and inside it I have more then 2-3
I have created a component to fetch data from a web service. The web
I have created a stateless component in Wicket 1.5, by extending the component and

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.