Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Nächstes Control zu einem Punkt finden (https://www.delphipraxis.net/140727-naechstes-control-zu-einem-punkt-finden.html)

argonix 24. Sep 2009 19:30


Nächstes Control zu einem Punkt finden
 
Hallo!
Wie kann ich, wenn ich einen Punkt vorgebe das Control finden, welches am nächsten zu diesem Punkt liegt?
(Möglichst nah an diesem Punkt ist)
Ich habe es mit FindControlAtPosition() probiert, diese Lösung ist aber unglaublich langsam und ineffizient. Geht das eleganter als in einem Bereich jeden Punkt einzeln abzufragen?

Mithrandir 24. Sep 2009 19:32

Re: Nächstes Control zu einem Punkt finden
 
Idee:

Leg dir eine Liste an. In dieser speicherst du zu jedem Control die Koordinaten links oben und die rechts unten. Und dann musst du nur noch durch die Liste iterieren, und gucken, ob sich dieser Punkt in dem Rechteck befindet.

Funktioniert mit jeder IDE... :)

argonix 24. Sep 2009 19:39

Re: Nächstes Control zu einem Punkt finden
 
Hmm... Ich will nicht schauen, ob das Control da ist, sondern ob es nah ist. (Am besten ohne extra-Liste)
Das heist, das Control welches die kleinste XY-Differenz zu den Koordinaten des Punktes hat soll zurückgegeben werden.

Medium 24. Sep 2009 19:57

Re: Nächstes Control zu einem Punkt finden
 
Dann must du immer und immer wieder den Abstand vom Punkt zu allen Controls ausrechnen, und den kleinsten davon nehmen. Das erschwert sich hierbei ggf, je nach dem wie genau du es haben magst.
Das einfachste wäre es den Abstand zum Mittelpunkt eines Controls zu berechnen, der ist ja schnell gefunden (zumindest bei rechteckigen). Aufwendiger wird es, wenn du die Kanten haben willst, dann musst du nämlich Abstände von Punkt zu Strecken berechnen, bzw. genauer: Punkt zu Gerade und dann noch bestimmen ob der Fußpunkt auch im Segment der Geraden ist, dass die Strecke darstellt. Zudem bekommst du dann Abstände >0 wenn du innerhalb des Controls bist, d.h. das müsste ggf. gesondert behandelt werden.

argonix 24. Sep 2009 20:07

Re: Nächstes Control zu einem Punkt finden
 
Sie sind alle rechtecking oder rund, das ist kein Problem. Schade, dann geht es wohl nicht ohne listen und Sortierfunktion.
Aber ich glaube, die kriege ich noch etwas intelligenter hin.
Vielen Dank für die Hilfe!

Medium 24. Sep 2009 22:36

Re: Nächstes Control zu einem Punkt finden
 
Wenn du recht viele Elemente hast, bzw. das ganze wirklich flott sein muss, schau dir mal Bei Google suchenQuadtrees (2D-Variante von Octrees) an. Wobei auch schon eine einfache Segmentierung der Fläche + Zuordnung der Komponenten zu den Segmenten hier ausreichen sollte, du wirst vermutlich eher weniger als tausende von Controls haben :)

Aphton 24. Sep 2009 22:45

Re: Nächstes Control zu einem Punkt finden
 
Probier mal Folgendes

Delphi-Quellcode:
//**
//** Gibt den am naheliegendsten Control zurück
//** - wobei die Distanz ausgehend vom Mittelpunkt
//** - der einzelnen Controls berechnet wird
//**
function NearestControl(const Position: TPoint; const MainControl: TControl): TControl;
var
  i, j: Integer;
  lDis, cDis: Single; // last distance, current distance
  function DistanceTo( Control: TControl ): Single;
  var
    x, y: Single;
  begin
    with Control do
    begin
      x := Left + ( Width div 2 ) - Position.X;
      y := Top + ( Height div 2 ) - Position.Y
    end;
    Result := SQRT( x*x + y*y );
  end;
begin
  Result := NIL;
  if MainControl.ComponentCount = 0 then
    Exit;
  j := -1;
  Result := TControl( MainControl.Components[0] );
  lDis := DistanceTo( Result );
  if MainControl.ComponentCount < 2 then
    Exit;
  for i := 1 to MainControl.ComponentCount - 1 do
  begin
    cDis := DistanceTo( TControl( MainControl.Components[i] ) );
    if cDis < lDis then
    begin
      lDis := cDis;
      j := i;
    end;
  end;
  if j > 0 then
    Result := TControl( MainControl.Components[j] );
end;

//**
//** Beispiel: Klatsch ein paar Controls auf die Form, und füge diesen Code in OnMouseDown() ein!
//**
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  c: TControl;
begin
  c := NearestControl( Point( X, Y ), Form1 );
  if Assigned( c ) then
    c.Enabled := not c.Enabled;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:56 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz