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.
blitz, look at this too http://www.hamburg.netsurf.de/~michael.urban/main.htm
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.
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.Cr eate;
or
New(Button1DataStructure);
and then set the tag in Button1:
Button1.Tag := LongInt(Button1DataStructu re);
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
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.Cr
or
New(Button1DataStructure);
and then set the tag in Button1:
Button1.Tag := LongInt(Button1DataStructu
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
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])
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
Viktor
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.
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.