Solved

How do I create a Graphic with moveable objects link by lines (wires) glued to the objects

Posted on 2008-10-07
19
509 Views
Last Modified: 2013-11-23
Using Delphi 7, I need to create an application that can be used to show wiring between objects, thus a graphic application to which one can add as many as required graphic objects represented in the attached diagram example as Objects A, B and C.  Each object, has a variable number of connection points, blocks shown as 1 to x as per the example.  Thus by changing a variable an object with the appropriate number of connector blocks is created.

Once the Object blocks with their connector blocks have been created on the graphic, the idea would be to click on, for example, Object As connector block 6 and drag a line to Object Bs connector block 2, and so connect the two points with a line.  This process is then repeated for each required connection.

The connector blocks should be attached to the Object blocks and should it be necessary to move an Object block to another place on the graphic, then it should be able to drag the Object block together with its connector blocks while the lines should remain glued to the connector blocks and be repainted to show the connections to the same connector blocks of the Object in its new position.
Graphic-object-link-example.JPG
0
Comment
Question by:HenryM2
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 9
19 Comments
 
LVL 14

Expert Comment

by:SteveBay
ID: 22658775
0
 

Author Comment

by:HenryM2
ID: 22666898
The solution offered only addresses part of the problem, namely dragging a line between lebels.  I need to have the lines glued to the labels / objects when they are dragged
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22666900
actually, I've written a better bit of code that more closely matches what you want, I'll try to dig it up...
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:HenryM2
ID: 22666946
Thanks, I am looking forward to that.  HenryM2
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22667373
Do the Object Blocks need to be resizable, or would swapping it for a bigger Object Block suffice?

When an Object Block is moved, how perfect does the line moving have to be? does it have to be completely smooth?

Do you just require "text" inside the Object Block, or is it going to be more complicated?

Do you need any special functionality, such as changing the block's colour dynamically, or flashing connectors, etc...

The reason I ask these questions, is that a near perfect way to implement this would be with OpenGL or DirectX. A less pretty, but workable solution is with canvas drawing, and another method is actually moving TPanels around...

I've done work in opengl, canvas, and tpanels, but each has its' own set of issues...
0
 

Author Comment

by:HenryM2
ID: 22667766
Thanks for getting back:
1 - The object blocks can be created a certain size and does not have to change thereafter.  Object blocks must have a different number of points to which the lines need to connect, but once created it does not have to change.  As per my illustration in the example, each main object block has a number of labeled blocks attached to it, each with onbe label/caption per line that need be connected to it.  This is required to identify the line connected to that specific point.

2 - While the object block is being moved, the line moving of the lines does not have to be perfect.  It will proably be good enough to even remove the lines when the object starts moving, and redraw them only once the object block is in its new position when the mouse button is released.

 3 - The object blocks and the label or line connection blocks will only contain text.

4 - Once the object block ha sbeen created in a certain color, the color does not have to change and no other special effects are required.  The only thing is that the block must be able to be dragged to a new location, and a double click event must be generated to run some other code when double click on the object which has no effect on the object itself.

5 - I trust that the above answers will help you to guide me to use the correct methods.  I know very little about canvas drawing and even less about opengl, but from the sounds of it, the canvas drawing method will probably be fine.

Thanks HenryM2

0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22684314
Wont be able to get this pasted until next week (but it is coming)
Hope you're not in a hurry.
Simply put, it's TShapes on a TScrollbox, and the lines are
canvas.moveto()    canvas.LineTo()  on a TPaintBox
clear the lines before painting them to simulate "moving them"
when the dragged object is stopped (i.e. MouseUp() event)
run through all the objects and do a refresh/draw of them to clean up any little paint ugly bits.

0
 

Author Comment

by:HenryM2
ID: 22685179
Thank you.  I am going to give it a try so long with the items you mention.  I will however pop out some short questions as I go along, if thats ok.  My first question being, what is the significance of putting the TShapes onto a TScrollbox.  Is it just to ensure that the graphic can scroll if it gets to big or is there another reason.
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22685315
yes, just so if you want to have more shapes than you can fit on the 1 screen, you can scroll to them
0
 

Author Comment

by:HenryM2
ID: 22685344
OK Thanks I will continue so long.
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22707145
Hi, I've got my source now, but it will need tweaking for your situation, mainly just adding a label to the shapes ("Object A", etc) but you could use an image instead (this is already catered for)
I will just create a quick screen layout sample for you, and upload it as a zip here today.
I'll explain more about it then
0
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 500 total points
ID: 22707728
I have uploaded the source demo for you. It should have everything you need
Take what you need from it, or use the whole thing
https://filedb.experts-exchange.com/incoming/ee-stuff/7331-movable-shapes-and-lines.zip
0
 

Author Closing Comment

by:HenryM2
ID: 31503737
Thanks, this solution is excellent, does exactly what I needed.  I am currently working through it and learnig as I am combinding it with the rest of my code.  I will probably have more questions later which I will then have to post as separate questions as the system appears to want me to make a conclusion on the question.  Regards HenryM2
0
 

Author Comment

by:HenryM2
ID: 22711005
I now need to put the scroll bar function onto a TScrollBox where I can preset the size of the scroll box area.  I tried this with just the TScrollBox and with a TPanel ontop of the scrollbox, then trying to make the TScrollBox or the panel the parent for World.
Below, is whaI did using a TPanel named FloorPlanPnl in the main form's On Create
World := TVCLTopography.Create(FloorPlanPnl);
World.Parent := FloorPlanPnl;
However, this crashes my whole application beyond repair with a Debugger Exception Notification, with an Exception Class EReadError, with message Error Reading MainForm.OnDestroy Invalid Property Value.  Changing back the On Create to what it was does not take the error away.  I obviously have to make more changes elsewhere, can you help please.
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22718121
I'm not sure I understand.

TVCLTopography already is a TScrollbox
you just put it on anything, such as a TPanel in your example
you can set its' width and height, or just set its' align to alClient

Then set the WorkAreaWidth and WorkAreaHeight properties (how big the "map" inside it can be)

The TVCLTopography will show the scrollbars and scroll as per a normal TScrollbar
0
 

Author Comment

by:HenryM2
ID: 22718500
OK solved.  my Form create is included below.
I then set the WorkAreaWidth and WorkAreaHeight properties to
  World.WorkAreaWidth := FloorPlanPnl.Width * 2;
  World.WorkAreaHeight := FloorPlanPnl.Height * 2;

I add objects (boxes). When I scroll so that the objects go off the screen and later return to them, upon moving the mouse onto them, they sometimes seem to separate from their vertexes.

One will also have to be able to select a line start at a vertex and then move to another vertex by scroling to it as it may be off the visible part of the screen.  So it will have to remeber that a start of a line has been made when dragging the scroll bar and then conclude the line when the end vertex is visible.

I am busy looking at this but if you have an idea to correct, it will be welcome.  Thanks.  
procedure TMainFrm.FormCreate(Sender: TObject);
begin
  World := TVCLTopography.Create(FloorPlanPnl);
  World.Align := alClient;
  World.Parent := FloorPlanPnl;
// temp for debugging
  World.fPaintBox.OnMouseMove := PaintBoxMouseMove;
end;

Open in new window

0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22718836
the issue with the objects moving happens with all the objects, shapes, vertex, or anchor. they all do the same if you hover over them.
It comes down to me not handling the control's ClientOrigin, which I forgot to put in (oops)

as for drawing a line. Currently, you right click the first "point" and then you can scroll wherever to the next point, and right click it to finish the line
I've made that code pretty basic, but it can be expanded on
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 22736670
Sorry for leaving you in the lurch there.
All you need to do is subtract the scrollbox's scrollbar position
Edit the VCLAnchor, VCLVertex and VCLPlanet's "RenderSelf' routines and change them like this

procedure TVCLVertex.RenderSelf;
begin
  if self.Highlighted then
  begin
    Shape.Shape := stRoundRect;
    Shape.Brush.Color := clBlue;
    Shape.SetBounds(self.Origin.X-10, self.Origin.Y-10, 21, 21);
    Shape.BringToFront;
  end
  else
  begin
    Shape.Shape := stCircle;
    Shape.Brush.Color := clBlack;
    Shape.SetBounds(self.Origin.X-2, self.Origin.Y-2, 5, 5);
    Shape.BringToFront;
  end;
  if not assigned(Shape.Parent) then Shape.Parent := fVCLTopography; // VCLTopography_ is derived from a TScrollbox
end;

becomes

procedure TVCLVertex.RenderSelf;
begin
  if self.Highlighted then
  begin
    Shape.Shape := stRoundRect;
    Shape.Brush.Color := clBlue;
    Shape.SetBounds(self.Origin.X-10-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-10-self.fVCLTopography.VertScrollBar.Position, 21, 21);
    Shape.BringToFront;
  end
  else
  begin
    Shape.Shape := stCircle;
    Shape.Brush.Color := clBlack;
    Shape.SetBounds(self.Origin.X-2-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-2-self.fVCLTopography.VertScrollBar.Position, 5, 5);
    Shape.BringToFront;
  end;
  if not assigned(Shape.Parent) then Shape.Parent := fVCLTopography; // VCLTopography_ is derived from a TScrollbox
end;

I will paste all 3 adjusted "RenderSelf" routines below

procedure TVCLAnchor.RenderSelf;
begin
  if self.Highlighted then
  begin
    Shape.Shape := stRoundRect;
    Shape.Brush.Color := clRed;
    Shape.SetBounds(self.Origin.X-10-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-10-self.fVCLTopography.VertScrollBar.Position, 21, 21);
    Shape.BringToFront;
  end
  else
  begin
    Shape.Shape := stCircle;
    Shape.Brush.Color := clBlue;
    Shape.SetBounds(self.Origin.X-3-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-3-self.fVCLTopography.VertScrollBar.Position, 7, 7);
    Shape.BringToFront;
  end;
  if not assigned(Shape.Parent) then Shape.Parent := fVCLTopography; // VCLTopography_ is derived from a TScrollbox
end;
 
 
procedure TVCLVertex.RenderSelf;
begin
  if self.Highlighted then
  begin
    Shape.Shape := stRoundRect;
    Shape.Brush.Color := clBlue;
    Shape.SetBounds(self.Origin.X-10-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-10-self.fVCLTopography.VertScrollBar.Position, 21, 21);
    Shape.BringToFront;
  end
  else
  begin
    Shape.Shape := stCircle;
    Shape.Brush.Color := clBlack;
    Shape.SetBounds(self.Origin.X-2-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-2-self.fVCLTopography.VertScrollBar.Position, 5, 5);
    Shape.BringToFront;
  end;
  if not assigned(Shape.Parent) then Shape.Parent := fVCLTopography; // VCLTopography_ is derived from a TScrollbox
end;
 
procedure TVCLPlanet.RenderSelf;
begin
  if self.Highlighted then
  begin
    Image.SetBounds(self.Origin.X-(self.Image.Width div 2)-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-(self.Image.Height div 2)-self.fVCLTopography.VertScrollBar.Position, self.Image.Width, self.Image.Height);
  end
  else
  begin
    Image.SetBounds(self.Origin.X-(self.Image.Width div 2)-self.fVCLTopography.HorzScrollBar.Position, self.Origin.Y-(self.Image.Height div 2)-self.fVCLTopography.VertScrollBar.Position, self.Image.Width, self.Image.Height);
  end;
  if not assigned(Image.Parent) then Image.Parent := fVCLTopography; // VCLTopography_ is derived from a TScrollbox
end;

Open in new window

0
 

Author Comment

by:HenryM2
ID: 22766456
Hi Sorry for only responding now, I was away since Friday.  Thanks for this, I will work this in and let you know.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…

756 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question