Einzelnen Beitrag anzeigen

Hawkeye219

Registriert seit: 18. Feb 2006
Ort: Stolberg
2.227 Beiträge
 
Delphi 2010 Professional
 

Re: Suche Pfeile zur Visualisierung von Beziehungen

  Alt 15. Aug 2007, 20: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
  Mit Zitat antworten Zitat