Solved

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

Posted on 2008-10-07
19
506 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
  • 9
  • 9
19 Comments
 
LVL 14

Expert Comment

by:SteveBay
Comment Utility
0
 

Author Comment

by:HenryM2
Comment Utility
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
Comment Utility
actually, I've written a better bit of code that more closely matches what you want, I'll try to dig it up...
0
 

Author Comment

by:HenryM2
Comment Utility
Thanks, I am looking forward to that.  HenryM2
0
 
LVL 17

Expert Comment

by:TheRealLoki
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
yes, just so if you want to have more shapes than you can fit on the 1 screen, you can scroll to them
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:HenryM2
Comment Utility
OK Thanks I will continue so long.
0
 
LVL 17

Expert Comment

by:TheRealLoki
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Java Help 2 67
Using idhttp to login to instagram 2 63
Eclipse Neon start with Admin account only 6 44
creating threads in delphi 1 52
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
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…
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…
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

771 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now