Link to home
Start Free TrialLog in
Avatar of blitz051697
blitz051697

asked on

Drawing Line with arrows to connect objects

I need a code, or component that I can use to draw lines between one or more controls on a form.  If I move the controls at runtime, the line should also move.  I would like the option of displaying an arrow at each, one, no ends. The arrow should correctly position itself upon move.  Very similar to a flowcharting package.  Drag a box, connected lines move with it.
Avatar of ZifNab
ZifNab

blitz,
 
 if you need it for flowcharting, then look at the excelent   component of TeeMach (TeeChart), namely TeeTree. It does all you need.  http://www.teemach.com/tee4/tree/TeeTree1.htm Isn't that expensive either.

Zif.
 


ok, I knew I once saw a freeware one. I found it very interesting then, but still haven't used it. Maybe looking at the code will help you something :

http://www.melander.dk/delphi/statemachine/index.html

Zif.

ps. I don't think you can make it with the standard components, you'll always need to make other components which have your specific feature.
To give you a way you could possibly do this:

Create a data structure for each component on your form.  This structure could contain whether or not it contains a line, which kind of arrow, which components it points to, etc..

Instead of making a new class with this structure, you could dynamically allocate memory for each one, and point to it using the component's "tag" property.  The tag would contain a pointer.  Note that you could use either an object, or simply a dynamically allocated data structure.  For example, you could do it like this:

Button1DataStructure := TComponentLineStructure.Create;

or

New(Button1DataStructure);

and then set the tag in Button1:

Button1.Tag := LongInt(Button1DataStructure);



Then, in your form's OnPaint method, go through all components on the page, and test what kind of component it is, and the structure attributed to each of them, to determine what kind of line to draw.

Here is something to get you started:  (note that I in this code I am referring to pointers rather than objects in the tag property)

procedure TForm1.FormPaint(Sender: TObject);
var x1,y1,x2,y2,i :integer;
    comp :TComponent;
    p :^TComponentLineStruct;
begin
  for i := 0 to ComponentCount-1 do begin
    comp := Components[i];
    if comp is TButton then begin
      p := Pointer(comp.Tag);
      if p^.DrawALine then begin
        x1 := comp.left;
        y1 := comp.top;
        x2 := p^.OtherComponent.Left;
        y2 := p^.OtherComponent.Top;
        if y2 > y1 then y1 := comp.top + comp.height;
        if x2 > x1 then x1 := comp.left + comp.width;
        with Canvas do begin
          MoveTo(x1,y1);
          LineTo(x2,y2);
        end;
    end
    else if comp is TListBox  {etc ...}
      ...
      ...

end;


The line drawing is done right in OnPaint.  You could have separate line drawing methods for each component, or have some that covers more than one component (such as "if (comp is TEdit) or (comp is TMaskEdit) then...").

Again, this is just to give you an idea where you could start.  Add any details as necessary.

scrapdog
ASKER CERTIFIED SOLUTION
Avatar of inter
inter
Flag of Türkiye image

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
To test just click on the button
Hello y'all

Hello Igor.

Looking at your code I just got a question... When do you use something = record and when do you use something = packed record  I've seen people use packed record pretty frequnetly, but I didn't know why???

btw- The rest of the code looks okay to me...

10x

Cheers,
Viktor
My friend,
Packed record tells delphi to pack the structure components into their original sizes. Lets explore it with an example,
 TRec = record
   x : byte;
   y : DWORD;
 end;
var
 T : TRec;
Normally this record should occupy 5 bytes in memory but due to 32 bit compiler it actually takes 8 bytes. Since system is tuned to 32 bit boundary delphi aligns each structure component to 4 byte boundaries -in 32 bit architecture such kind of memory access is native -> fast. However some routines expect that your data should appear as it declared. For example if you cast pointer to the above structure the following is illegal(points to wrong location)
  PDWord(PByteArray(@T)^[1])^ is not equal to T.y
when we declare it as PACKED the above expressions are equivalent. The PACKED stuff is necessary for most of the Win API calls and for dynamic record allocation. So as a rule of thumb I always use packed keyword for not to have trouble. These is also equivalent to {$A-} directive which means the ALIGNED RECORD FIELDS, I suppose I could make it clear, c.u. igor
10x man....That's a perfect explanation.... Tanks for your time :-)

Viktor
Avatar of blitz051697

ASKER

Thanks All.  I've checked out a couple of the recomendations--Very Interesting.  I like the TeeTree component.  It has many interesting properties.  I'm not sure its an exact fit because I don't neccessary need it to be a tree control.  But, I like the formatting it has.