Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
Delphi 2010 Professional
|
Re: Suche Pfeile zur Visualisierung von Beziehungen
15. Aug 2007, 21:17
Hallo Tom,
ich habe hier eine kleine Demo zusammengebaut, die dir zeigen soll, wie du möglicherweise auf eine Pfeil-Komponente verzichten kannst. Zum Testen benötigst du lediglich ein leeres Formular, auf das du zwei Panels (Panel1 und Panel2) legst. Die Ereignisse OnMouseDown, OnMouseMove und OnMouseUp der Panels verbindest du über den Objektinspektor mit den zugehörigen Methoden des folgenden Codes. Das Ereignis OnPaint des Formulars verbindest du mit der Methode FormPaint. Wenn du nun die Anwendung startest, solltest du beide Panels mit der Maus verschieben können. Ein Pfeil verbindet Panel1 mit Panel2.
Delphi-Quellcode:
// uses Math;
type
TForm1 = class (TForm)
Panel1: TPanel;
Panel2: TPanel;
procedure FormPaint (Sender: TObject);
procedure PanelMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure PanelMouseMove (Sender: TObject; Shift: TShiftState; X,Y: Integer);
procedure PanelMouseUp (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
private
FAnchor : TPoint; // Mausposition zu Beginn des Verschiebens
FOrgPos : TPoint; // Position des Controls vor dem Verschieben
FPanning : Boolean; // True während des Verschiebens
end;
CONST
GRIDINTERVAL = 16;
type
TPin = (pinBody, pinLeft, pinTop, pinRight, pinBottom);
// zeichnet einen Vektor mit einer Pfeilspitze
procedure DrawVector (aCanvas: TCanvas;
x1, y1, x2, y2: Integer;
aHeadSize: Integer = 5;
aFillHead: Boolean = False);
const
ApexAngle = 30 * Pi / 180;
var
dx, dy : Integer;
angle : Double;
s1, c1 : Extended;
s2, c2 : Extended;
P1, P2 : TPoint;
begin
aCanvas.MoveTo (x1, y1);
aCanvas.LineTo (x2, y2);
if (x1 <> x2) then
angle := {Math.}ArcTan2(y2 - y1, x2 - x1)
else
if (y1 < y2) then
angle := Pi / 2
else
angle := 3 * Pi / 2;
{Math.}SinCos (angle - ApexAngle, s1, c1);
{Math.}SinCos (angle + ApexAngle, s2, c2);
P1.x := x2 - Round(c1 * aHeadSize);
P1.y := y2 - Round(s1 * aHeadSize);
P2.x := x2 - Round(c2 * aHeadSize);
P2.y := y2 - Round(s2 * aHeadSize);
if aFillHead then
aCanvas.Polygon ([P1, Point(x2, y2), P2])
else
begin
aCanvas.MoveTo (P1.x, P1.y);
aCanvas.LineTo (x2, y2);
aCanvas.MoveTo (P2.x, P2.y);
aCanvas.LineTo (x2, y2);
end;
end;
// Liefert die Position eines Anschlußpunktes für ein Control
function PinPosition (aControl: TControl; aPin: TPin): TPoint;
var
w2, h2 : Integer;
begin
w2 := aControl.Left + aControl.Width div 2;
h2 := aControl.Top + aControl.Height div 2;
case aPin of
pinLeft: Result := Point(aControl.Left, h2);
pinTop: Result := Point(w2, aControl.Top);
pinRight: Result := Point(aControl.Left + aControl.Width, h2);
pinBottom: Result := Point(w2, aControl.Top + aControl.Height);
else
Result := Point(w2, h2);
end;
end;
procedure TForm1.PanelMouseDown (Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FAnchor := Mouse.CursorPos;
FOrgPos := TControl(Sender).BoundsRect.TopLeft;
FPanning := True;
end;
procedure TForm1.PanelMouseMove (Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
xPos, yPos : Integer;
begin
if FPanning then
begin
xPos := FOrgPos.X + (Mouse.CursorPos.X - FAnchor.X);
yPos := FOrgPos.Y + (Mouse.CursorPos.Y - FAnchor.Y);
TControl(Sender).Left := xPos - (xPos mod GRIDINTERVAL);
TControl(Sender).Top := yPos - (yPos mod GRIDINTERVAL);
Invalidate;
end;
end;
procedure TForm1.PanelMouseUp (Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FPanning := False;
end;
procedure TForm1.FormPaint (Sender: TObject);
var
P1, P2 : TPoint;
begin
inherited;
// zeichne eine Verbindung von Panel1 (rechter Anschlußpunkt) zu Panel2 (linker Anschlußpunkt)
P1 := PinPosition(Panel1, pinRight);
P2 := PinPosition(Panel2, pinLeft);
Canvas.Pen.Color := clBlue;
Canvas.Brush.Color := clBlue;
{
Canvas.Pen.Width := 2;
Canvas.MoveTo (P1.X, P1.Y);
Canvas.LineTo (P2.X, P2.Y);
}
DrawVector (Canvas, P1.X, P1.Y, P2.X, P2.Y, 10, True);
end;
end.
Im Beispiel wird eine feste Verbindung eingezeichnet, in deiner Anwendung wirst du diese Verbindung variabel gestalten wollen. Du mußt dir dazu überlegen, wie du die beiden beteiligten Controls zusammen mit den benutzten Anschlußpunkten verwalten kannst.
Der Code wird sicher nicht genau dem entsprechen, was du dir vorstellst, er soll lediglich das Prinzip zeigen. Um die Treppen bei den Linien zu entfernen, könntest du das Graphics32-Paket einsetzen. Es unterstützt auch die Kantenglättung ( antialiasing) bei Linien.
Gruß Hawkeye
|