Link to home
Start Free TrialLog in
Avatar of engdmorr
engdmorr

asked on

Faster Dynamic Creation of multiple TShape Components??

Hi,

I am writing an application that requires a 50x60 matrix of TShapes (i.e. 3000 TShapes!) to be displayed on the screen at the same time.  I am currently doing this dynamically, with the following code:

========================================================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Ar: Array[0..50, 0..60] of TShape;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j: integer;
begin

  for i:=0 to 50 do
    begin
      for j:=0 to 60 do
        begin
          Ar[i][j] := TShape.Create(form1);
          ar[i][j].Parent := form1;
          ar[i][j].Top := 20+(j+(j*10));
          Ar[i][j].Left :=20+( i+(i*10));
          Ar[i][j].Width := 10;
          Ar[i][j].Height := 10;
        end;
    end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FORM1.DoubleBuffered := TRUE;
end;

end.
=========================================================

The problem is it takes an awful long time to display them all.  I was just wondered wheather there is a quicker way to do this so they appear almost instantly??

Thanks.

Avatar of FeralCTO
FeralCTO

Here are a couple of ideas:

* Maybe you could multi-thread and create the TShapes at startup? Put them in a TObjectList. That way they'd be sitting in memory ready to use when the user clicked the button. If you're not too familiar with threads, Indy (www.indyproject.org) has a thread component which makes multi-threading really easy.

* DoubleBuffered uses a lot of memory. I'm assuming you have that enabled to reduce flicker during painting. I don't have a specific suggestion on this one, but you might want to play with WHEN you enable that property.

* I'm guessing there's a lot of painting going on the way your code is right now. I suspect that's where the performance hit is coming from. You could try setting the TShape's properties for top, left, height and width BEFORE you set the parent. In addition, you could place a panel on the form and have that be the parent for the shapes. Set the Panel to Invisible while you're getting the shapes onto it and positioned. Once they're all on it, then make the panel visible. FYI, TPanel has the DoubleBuffered property, too. So you could still achieve the flicker free repainting.

Good luck. If you solve this satisfactorily, it would be cool if you'd post your solution for the rest of us to see.


Alright, I couldn't help but play with your code! :-)  I tried some of my suggestions and it DEFINITELY helped. Here's the modified code:

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j: integer;
begin

  FORM1.DoubleBuffered := False;   // turn DoubleBuffered off while we get all the shapes in place
  for i:=0 to 50 do
    begin
      for j:=0 to 60 do
        begin
          Ar[i][j] := TShape.Create(form1);
//          ar[i][j].Parent := form1;    
          ar[i][j].Top := 20+(j+(j*10));
          Ar[i][j].Left :=20+( i+(i*10));
          Ar[i][j].Width := 10;
          Ar[i][j].Height := 10;
          ar[i][j].Parent := form1;    // I moved this to here from above
        end;
    end;
  FORM1.DoubleBuffered := TRUE;

end;
Avatar of engdmorr

ASKER

Thanks for the comments, havent tried any yet though!  I was thinking of maybe creating my own TShape component based on a simple rectangle.  I have just drawn 3000 rectangles to the screen in a fraction of the time a TShape takes, I'm assuming the object instantiation for a TShape takes a lot of resources.  Will get back to you all with the results.  Will try the suggestions 1st though, thanks once again :)
If you're willing to put a little (maybe a lot) of work into it, you can do all of the drawing yourself using TCanvas. You could draw on an offscreen graphic and then copy the image to something onscreen (form, canvas, TImage, etc). That would eliminate flicker similar to the way DoubleBuffered does.
I'd agree - draw them yourself in one master control if possible. 3000 components are likely to cause resource problems on a Win9x machine, if that's an issue...
Hi,

I think the problem here is not the code, but what you want to do, so I ask you:
what do you really want to do? <g>.

Please explain and I'm sure we'll get very far.

Cheers,

Andrew
Just to clarify why I need so many shapes, I am designing kind of a wierd packet analyser.. A cross between the GUI you get with Win9x Defrag and a network sniffer.

The packet sniffing is not a problem as I already designed my own NDIS drivers ages ago.  Basically, each of the squares represents the individual packet: The square will be coloured green if OK, red if collision occured, Brown border for TCP, Orange for UDP etc.. etc...  When you click on the square in question the data for the packet will be displayed, headers, data etc..

There is 50 frames of data per second being squirted out onto the network and I want to analyse a full minutes worth at once.. Hence the need for so many shapes!!

It would be nice to have this full minutes worth of data, but perhaps not essential.  I may end up just displaying a 50 x 20 array to display 20 seconds of data instead.

Hope this clarifies the need for so many shapes.

By the way, this is not a commercial product I am developing but my own nerdy idea so I will probably post it somewhere in the future if I manage to pull it off :)
ASKER CERTIFIED SOLUTION
Avatar of DeerBear
DeerBear

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial