Solved

Clickable line

Posted on 2001-06-27
7
195 Views
Last Modified: 2010-05-18
Hi,

Is there anyone out there who know if it's possible to draw a line on the "canvas" and have it reacting on mouseclick.

Example of the setup is I have five buttons on the form and connect them with lines.
I then want to be able to click on the line and get information on for instance the X and Y points of the endpoints.

If it's possible i also want to assign a "name" to this line to be able to sort wich line is selected if I have for instance 15 lines in a star pattern.

Hoping for this as I have tried myself and failed..
0
Comment
Question by:samone
7 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6230866
? maybe
use tshape(s)
0
 
LVL 9

Accepted Solution

by:
ITugay earned 200 total points
ID: 6230925
Hi samone,

here is sample unit. It generates 10 random lines. All lines drawn in OnPaint method.
Moving the mouse (OnMouseMove) over the one of line you can see how cursor changed to crHandPoint.
Clickin on line (OnMouseDown) you can change it's "Selected" property.

Be sure you include "Contnrs" unit in your uses clause.

Enjoy :-)

------
Igor.


unit Unit1;

interface

uses
  Windows, Classes, Graphics, Controls, Forms,
  Contnrs;

type

  TLine = class(TObject)
    A: TPoint;
    B: TPoint;
    Selected: Boolean;
  end;

  TForm1 = class(TForm)
    procedure FormPaint(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
  public
    Lines: TObjectList;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

// check that point P lie on line with coordinates X1.Y1 - X2.Y2
// Delta - possible distance from the line's point
function PointOnLine(X1,Y1, X2,Y2: Integer; P: TPoint; Delta: Integer): Boolean;
var
  Step: Real;
  R: TRect;
  N: Integer;
  Z: Real;
begin
  Result := False;
  if (Abs(X2-X1) > Abs(Y2-Y1)) and (X2-X1 <> 0) then
  begin
    Step := (Y2- Y1)/abs((X2 - X1));
    if X2 > X1 then N := 1 else N := -1;
    Z := Y1;

    while X1 <> X2 do
    begin
      SetRect(R, X1, Round(Z), X1, Round(Z));
      InflateRect(R, Delta, Delta);
      if PtInRect(R, P) then
      begin
        Result := True;
        Break;
      end;
      Z := Z + Step;
      X1 := X1 + N;
    end;
  end
  else
  if Y2 - Y1 <> 0 then
  begin
    Step := (X2 - X1)/abs((Y2 - Y1));
    if Y2 > Y1 then N := 1 else N := -1;
    Z := X1;

    while Y1 <> Y2 do
    begin
      SetRect(R, Round(Z), Y1, Round(Z), Y1);
      InflateRect(R, Delta, Delta);
      if PtInRect(R, P) then
      begin
        Result := True;
        Break;
      end;
      Z := Z + Step;
      Y1 := Y1 + N;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
  L: TLine;
begin
  Randomize;
  Lines := TObjectList.Create(true);
  // create 10 random lines
  for I := 1 to 10 do
  begin
    L := TLine.Create;
    L.A.X := Random(Width);
    L.B.X := Random(Width);
    L.A.Y := Random(Height);
    L.B.Y := Random(Height);
    Lines.Add(L);
  end;
end;

procedure TForm1.FormPaint(Sender: TObject);
var
  I: Integer;
  L: TLine;
begin
  // draw generated lines
  with Form1.Canvas do
  for I := 0 to Lines.Count - 1 do
  begin
    L := TLine(Lines[I]);
    if L.Selected then
      Pen.Color := clRed
    else
      Pen.Color := clBlack;

    MoveTo(L.A.X, L.A.Y);
    LineTo(L.B.X, L.B.Y);
  end;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  P: TPoint;
  I: Integer;
  L: TLine;
begin
  P.X := X;
  P.Y := Y;
  Cursor := crDefault;
  // detect when mouse over the one of line
  for I := 0 to Lines.Count - 1 do
  begin
    L := TLine(Lines[I]);
    if PointOnLine(L.A.X, L.A.Y, L.B.X, L.B.Y, P, 3) then
      Cursor := crHandPoint;
  end;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  P: TPoint;
  I: Integer;
  L: TLine;
begin
  P.X := X;
  P.Y := Y;
  // select deselect line when mouse clicked on it
  for I := 0 to Lines.Count - 1 do
  begin
    L := TLine(Lines[I]);
    if PointOnLine(L.A.X, L.A.Y, L.B.X, L.B.Y, P, 3) then
    begin
      L.Selected := not L.Selected;
      Invalidate;
    end;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Lines.Free;
end;

end.
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6230950
nice igor ;-)
0
Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

 
LVL 9

Expert Comment

by:ITugay
ID: 6230953
just compilation from another samples :-)
0
 
LVL 17

Expert Comment

by:geobul
ID: 6231349
Hi,
Just another way:

DrawLine adds a line to a StringList with coordinates and name. Label1 shows current line name and coordinates(OnMouseMove).

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormPaint(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  LineList : TStringList;

implementation

{$R *.DFM}

const
  Sensitivity = 50;

function Min(X1,X2: integer): integer;
begin
 if X1 <= X2 then result := X1
             else result := X2;
end;

function Max(X1,X2: integer): integer;
begin
 if X1 >= X2 then result := X1
             else result := X2;
end;

procedure DrawLine(X1,Y1,X2,Y2: integer; Name: string);
begin
  with Form1.Canvas do begin
    MoveTo(X1,Y1);
    LineTo(X2,Y2);
  end;
  LineList.Add(Format('%.4d',[X1])+Format('%.4d',[Y1])+Format('%.4d',[X2])+Format('%.4d',[Y2])+Name);
end;

function OverLine(X,Y: integer): integer;
var
  X1,Y1,X2,Y2: integer;
  i: integer;
begin
 result := -1;
 for i := 0 to LineList.Count - 1 do begin
  X1 := StrToInt(Copy(LineList[i],1,4));
  Y1 := StrToInt(Copy(LineList[i],5,4));
  X2 := StrToInt(Copy(LineList[i],9,4));
  Y2 := StrToInt(Copy(LineList[i],13,4));
  if (Y-Y1 <> 0) and (Y-Y1 <> 0) and (X-X2 <> 0) and (X1-X2 <> 0) then begin
   if (X >= Min(X1,X2)) and (X <= Max(X1,X2)) and (Y >= Min(Y1,Y2)) and (Y <= Max(Y1,Y2)) then begin
    if (Round(((X - X1)/(Y - Y1))*Sensitivity) = Round(((X2 - X1)/(Y2 - Y1))*Sensitivity)) or
       (Round(((Y - Y2)/(X - X2))*Sensitivity) = Round(((Y1 - Y2)/(X1 - X2))*Sensitivity)) then begin
      result := i;
      exit;
    end;
   end;
  end;
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  LineList := TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  LineList.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  DrawLine(5,200,100,5,'Line1');
  DrawLine(5,5,100,200,'Line2');
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
 i: integer;
 s: string;
begin
 i := OverLine(X,Y);
 if i > -1 then begin
  s := LineList[i];
  Label1.Caption := Copy(s,17,Length(s) - 16) + ' ' +
    Copy(s,1,4) + ',' + Copy(s,5,4) + ',' +
    Copy(s,9,4) + ',' + Copy(s,13,4);
  end else Label1.Caption := '';
end;
end.

Regards, Geo
0
 

Expert Comment

by:manata
ID: 6232484
Hi Samone

By now you know how to draw a line on a canvas.

A method to get where you are going would be to use the MoveTo and LineTo methods of the TCanvas Class.

But prior to using this make up coordinates that you may store in an array( ICoordinates : Array[0..10] of Integer;)
this will help you keep track of the starting and ending points of the line.

On your mouse down method you may track the mouse coordinates and compare them to the points in the array.

Facts:
You draw the lines so you know ICoordinates[0] = x Mouse coordinate of the first line, etc

So knowing the order of the lines and the order of the coordinates, the index of the array can work as a tag value of any control.

Good Luck Manata
0
 

Author Comment

by:samone
ID: 6243884
Hi,

I have been sick for a few days and haven't been able too check the answers yet.

I will try to see if and how to use what you have written and I come back with more questions if I don't understand something.

//Ulf
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

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…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

757 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

17 Experts available now in Live!

Get 1:1 Help Now