AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Überprüfen ob Mausklick in bestimmten bereich war
Thema durchsuchen
Ansicht
Themen-Optionen

Überprüfen ob Mausklick in bestimmten bereich war

Ein Thema von xZise · begonnen am 30. Jul 2006 · letzter Beitrag vom 26. Mär 2012
Antwort Antwort
Seite 2 von 3     12 3      
Nicolai1234

Registriert seit: 21. Feb 2004
1.008 Beiträge
 
Turbo Delphi für Win32
 
#11

Re: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 30. Jul 2006, 12:37
Zitat von xZise:
[roter Kasten]
o.O
Öhm ja, so könnte man es machen

Problem ist nur, dass sie nach unten hin versetzt sind... Also könnte ich die Reihe bestimmen und müsste an noch ein bisschen mehr rand dazuaddieren.

(PS: richtig geschlussfolgert )[/roter Kasten]
Na ja, der Rand verhält sich proportional zur Reihe. In der ersten ist er sagen wir mal nur 10, in der zweiten dann 35, dann 60. Es kommt immer ein halber Koffer hinzu.
Also 10 + 25*(Spaltennummer - 1) oder so in der Art. Je nachdem, wie groß die Zahlen wirklich sind.

Probier das mal aus, ich finde, dass dieser Weg der schönste wäre. Vor allem, weil du kein Array[1..26] of Trect brauchst, die du manuell füllen musst.
  Mit Zitat antworten Zitat
Benutzerbild von xZise
xZise

Registriert seit: 3. Mär 2006
Ort: Waldbronn
4.303 Beiträge
 
Delphi 2009 Professional
 
#12

Re: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 30. Jul 2006, 12:58
(Das TRect könnte ich in der Zeichenrutine unterbringen )

Aber hier ist jetzt die Lösung des Problems!
Es funktioniert eigentlich genz gut!
Was noch fehlt, ist, dass man nicht rechts neben den Koffern klicken kann!

Delphi-Quellcode:
procedure TForm1.SpielfeldMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var row, side, col, KofferNum,prefrows : Integer;
begin
  // Zeile heruasfinden (0-3)
  row := Floor(Y / 70);
  // Rand herausfinden (5 mindestens und pro Zeile (row = 1 oder 3) sind es 32 px mehr ansonsten sind es 65 px)
  side := Floor(5 + row * 32.5);
  // Spalte herausfinden
  col := Floor((x - side) / 70);
  // dareingehen, wenn man mindestens über den linksten Koffer ist
  if col > 0 then begin
    // Vorhergende Koffer dazuaddieren
    prefrows := 0;
    if row >= 1 then
      inc(prefrows, 8); // 1. sind 8 K. +
    if row >= 2 then
      inc(prefrows, 7); // 2. sind 7 K. +
    if row >= 3 then
      inc(prefrows, 6); // 3. sind nochmal 6 K. +
    // Koffernummer (plus eins, weil der erste ohne dem plus eins 0 ist)
    KofferNum := col + prefrows + 1;
    // zu testzwecken einfach mal anzeigen !
    Label2.Caption := IntToStr(row) + ' :: ' + IntToStr(col) + ' == ' + IntToStr(KofferNum);
  end else
    Label2.Caption := IntToStr(row) + ' :: ' + IntToStr(col) + ' == ';
end;
Fabian
Eigentlich hat MS Windows ab Vista den Hang zur Selbstzerstörung abgewöhnt – mkinzler
  Mit Zitat antworten Zitat
30. Jul 2006, 13:08
Dieses Thema wurde von "Phoenix" von "Object-Pascal / Delphi-Language" nach "VCL / WinForms / Controls" verschoben.
Hat eher was mit den Klassen der VLC zu tun
Root2k

Registriert seit: 7. Jun 2011
Ort: Ulm
49 Beiträge
 
Delphi XE Enterprise
 
#14

AW: Re: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 12:31
Hi.

Ich weiß, dass dieser thread schon ein "bisschen" veraltet ist, aber vom Thema her passt das hier ganz gut zu meinem Problem.

Zunächst zu dem Eintrag von Igel:

Delphi-Quellcode:
function InRect(x,y:integer;rect:TRect):boolean;
begin
  result := (x >= rect.Left) and (y >= rect.Top) and (y <= rect.Bottom) and (y >= rect.Top);
end;
Da hat sich ein kleiner Fehler eingeschlichen. Korrekt sollte die Funktion so aussehen:
Delphi-Quellcode:
function InRect(x,y:integer;rect:TRect):boolean;
begin
  result := (x >= rect.Left) and (y >= rect.Top) and (y <= rect.Bottom) and (x <= rect.Right);
end;

Mein Problem bezieht sich auch auf diese Funktion:
Funktioniert das Ganze vielleicht auch irgendwie mit einem Polygon, bzw. einer beliebigen Form die durch ein Punkte-Array definiert ist?
Kann ich z.B. ermitteln wenn sich die Maus in einem Kreis befindet? Derzeit lege ich ein Rechteck außen herum, aber das ist je nach Form sehr ungenau.

Über hilfreiche Beiträge würde ich mich freuen.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#15

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 13:04
Auf die Schnelle fällt mir MSDN-Library durchsuchenPtInRegion ein (für das ursprüngliche Problem hätte man BTW auch MSDN-Library durchsuchenPtInRect verwenden können, sofern ich den Thread korrekt überflogen habe). Der einzige Nachteil ist, dass Du zuerst eine entsprechende Region erzeugen (und später wieder freigeben) musst.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#16

AW: Re: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 13:14
Funktioniert das Ganze vielleicht auch irgendwie mit einem Polygon, bzw. einer beliebigen Form die durch ein Punkte-Array definiert ist?
Kann ich z.B. ermitteln wenn sich die Maus in einem Kreis befindet? Derzeit lege ich ein Rechteck außen herum, aber das ist je nach Form sehr ungenau.
Kreis ist einfach, da musst du nur prüfen, ob die Distanz zum Mittelpunkt kleiner dem Radius ist:
PtInCirle := sqr(X-P.X)+sqr(Y-P.Y) < sqr(R) , wobei X und Y die Koordinaten z.B. des Cursors sind, P.X und P.Y der Mittelpunkt des Kreises und R der Radius. Die Gleichung wurde hier quadriert um die Wurzel zu sparen.

Für Polygone gibt es auch Verfahren (engl.), aber wenn es wirklich nur um einen Kreis geht, macht es absolut keinen Sinn, das zu implementieren. Ansonsten gibt es natürlich noch die von DeddyH verwendete API-Funktion, aber manchmal will man nicht mit Windows-Regions arbeiten...

[edit]

Hab mal meinen Port für den verlinten Algorithmus ausgegraben:
Delphi-Quellcode:
function TMapRegion.PointInRegion(APoint: TPoint): boolean;
var
  Pt1, Pt2: TPoint;
  PtOld, PtNew: TPoint;
  i: integer;
begin
  if (APoint.X >= FVertexList.BoundingBox.Left) and
     (APoint.X <= FVertexList.BoundingBox.Right) and
     (APoint.Y >= FVertexList.BoundingBox.Top) and
     (APoint.Y <= FVertexList.BoundingBox.Bottom) and
     (FVertexList.Count >= 3) then
  begin
    ///
    /// Ported from http://www.visibone.com/inpoly/
    ///
    Result := False;
    PtOld := FVertexList.Last;
    for i := 0 to FVertexList.Count - 1 do
    begin
      PtNew := FVertexList[i];
      if PtNew.X > PtOld.X then
      begin
        Pt1 := PtOld;
        Pt2 := PtNew;
      end
      else
      begin
        Pt1 := PtNew;
        Pt2 := PtOld;
      end;
      if ((PtNew.X < APoint.X) = (APoint.X <= PtOld.X)) and
         ((APoint.Y-Pt1.Y)*(Pt2.X-Pt1.X) < (Pt2.Y-Pt1.Y)*(APoint.X-Pt1.X)) then
      begin
        Result := not Result;
      end;
      PtOld := PtNew;
    end;
  end
  else
    Result := False;
end;
Bin jetzt zu Faul, den Code für normale Arrays zu verallgemeinern, aber es sollte nicht schwierig sein, ihn entsprechend abzuändern. Relevant ist übrigens nur der Teil innerhalb des if-Konstrukts. In der Abfrage davor wird nur erst mal gegen eine Bounding Box verglichen, was aber lediglich aus Performancegründen geschieht und somit weglassen werden kann.

[/edit]

Geändert von Namenloser (23. Mär 2012 um 13:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.625 Beiträge
 
Delphi 12 Athens
 
#17

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 13:25
Klar, Regions sind manchmal etwas eklig, aber damit entfallen halt eine Menge eigener Berechnungen. Einfaches Beispiel:
Delphi-Quellcode:
procedure TForm1.FormClick(Sender: TObject);
var
  Rgn: hRGN;
  Pt: TPoint;
begin
  Rgn := CreateEllipticRgnIndirect(ClientRect);
  if Rgn <> 0 then
    try
      Pt := ScreenToClient(Mouse.CursorPos);
      if PtInRegion(Rgn, Pt.X, Pt.Y) then
        ShowMessage('Innerhalb')
      else
        ShowMessage('Außerhalb');
    finally
      DeleteObject(Rgn);
    end;
end;

procedure TForm1.FormPaint(Sender: TObject);
begin
  Canvas.Brush.Color := clRed;
  Canvas.Pen.Color := Canvas.Brush.Color;
  Canvas.Ellipse(ClientRect);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  Invalidate;
end;
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#18

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 14:30
Ab XE2 geht auch sowoas, welches man, für D2006/TD bis XE über einen Record-Helper, selber nachrüsten kann.
Delphi-Quellcode:
var
  R: TRect;
  P: TPoint;
begin
  if R.Contains(P) then
    ...
Aber bisher sind dort nur Methoden für rechteckige Dinge integriert.
$2B or not $2B

Geändert von himitsu (23. Mär 2012 um 14:32 Uhr)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#19

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 15:07
Es gäbe noch die möglichkeit über WindowfromPoint diese methode verwende ich bei PictureBoxen bei meinem Mediaplayer
um zu verhindern das eine function wenn meine Maus sich nicht innerhalb der x,y position befindet nach dem klick
auf einer als Button ausgelegten picBox ausgeführt wird.

Code:
GetCursorPos pos
If WindowFromPoint(pos.X, pos.Y) = PicButton(Index).hWnd Then
Habe jetzt nicht nachgeschaut wie sich das in Delphi verwirklichen läßt.

ups.. hab mich da wohl verlesen

gruss

Geändert von EWeiss (23. Mär 2012 um 15:17 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#20

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 17:03
Hier, eine etwas allgemeinere Lösung SAT (Separating Axis Theorem)

Kurze Erläuterung der Funktionsweise (soweit ich das richtig in Erinnerung habe):
Man berechnet zu allen Seiten beider Polygone schrittweise die Normalen, und projeziert alle Punkte auf diese Achse (Normale). Dann berechnet man sich die Min-Max Werte auf der Achse für Polygon 1 & 2. Schneiden sich nun diese beiden Bereiche nicht, so gibt es keine Kollision -> die Überprüfung kann vorzeitig beendet werden. Ansonsten kommt es höchstwahrscheinlich (nicht sicher!) zu einer Kollision.

Bild 1
Bild 2
(bei Bild 2 sieht man, dass der grüne und rote Bereich sich nicht schneiden -> keine Kollision)

Delphi-Quellcode:
type
  TVector = record
    X, Y: Single;
    procedure Assign(const AX, AY: Single);
  end;
  TVectorArray = Array of TVector;
  PPolygon = ^TPolygon;
  TPolygon = TVectorArray;

procedure TVector.Assign(const AX, AY: Single);
begin
  X := AX;
  Y := AY;
end;

function vector(const AX, AY: Single): TVector;
begin
  Result.Assign(AX, AY);
end;

function scalarProduct(const A, B: TVector): Single;
begin
  Result := A.X*B.X + A.Y*B.Y;
end;

procedure normalize(var V: TVector);
var
  size: Single;
begin
  size := SQRT(scalarProduct(V, V));
  if size <> 0 then V.Assign(V.X/size, V.Y/size);
end;

function normal(const V: TVector): TVector;
begin
  Result.Assign(V.Y, -V.X);
end;

function BoundingBoxCollisionCheck(const A1, A2, B1, B2: TVector): Boolean; overload;
{  1
    +---------+
    |        |
    |        |
    +---------+ 2
}

begin
  Result := not((A1.X > B2.X) or (A2.X < B1.X) or
    (A1.Y > B2.Y) or (A2.Y < B1.Y));
end;

function BoundingBoxCollisionCheck(const PolyA, PolyB: TPolygon): Boolean; overload;
var
  boxA1, boxA2,
  boxB1, boxB2: TVector;
  procedure createBoundingBox(const P: TPolygon; var bbox1, bbox2: TVector);
  var
    i: Integer;
  begin
    for i := 0 to High(P) do
    begin
      if P[i].X < bbox1.X then
        bbox1.X := P[i].X
      else
      if P[i].X > bbox2.X then
        bbox2.X := P[i].X;
      if P[i].Y < bbox1.Y then
        bbox1.Y := P[i].Y
      else
      if P[i].Y > bbox2.Y then
        bbox2.Y := P[i].Y
    end;
  end;
begin
  with PolyA[0] do
  begin
    boxA1.Assign(X, Y);
    boxA2.Assign(X, Y);
  end;
  with PolyB[0] do
  begin
    boxB1.Assign(X, Y);
    boxB2.Assign(X, Y);
  end;
  createBoundingBox(PolyA, boxA1, boxA2);
  createBoundingBox(PolyB, boxB1, boxB2);
  Result := BoundingBoxCollisionCheck(boxA1, boxA2, boxB1, boxB2);
end;

function SATCollisionCheck(const PolyA, PolyB: TPolygon): Boolean;
var
  P1, P2: PPolygon;
  function collisionCheck: boolean;
  var
    len: Integer;
    i: Integer;
    n: TVector;
    minMaxA, minMaxB: TVector;
    procedure getMinMaxAxisMappedValues(const Polygon: PPolygon; var min, max: Single);
    // axis = n
    var
      j: Integer;
      scalar: Single;
    begin
      min := scalarProduct(Polygon^[0], n);
      max := min;
      for j := 1 to high(Polygon^) do
      begin
        scalar := scalarProduct(Polygon^[j], n);
        if (scalar < min) then
          min := scalar
        else
        if scalar > max then
          max := scalar;
      end;
    end;
    function collision1DCheck(const A, B: TVector): Boolean;
    begin
      Result := not((A.X > B.Y) or (A.Y < B.X));
    end;
  begin
    Result := False;
    // gehe alle Punkte des Polygons 1 durch, bilde die Gerade und berechne darauf die Normale
    len := Length(P1^);
    for i := 0 to len do
    begin
      with P1^[(i+1) mod len] do
        n := normal(vector(X - P1^[i].X, Y - P1^[i].Y)); // n = normal(AB)
      normalize(n);
      // mappe nun alle punkte beider Polygone auf die Achse (punkt * n) und merke dir
      // min max Werte
      getMinMaxAxisMappedValues(P1, minMaxA.X, minMaxA.Y);
      getMinMaxAxisMappedValues(P2, minMaxB.X, minMaxB.Y);
      // wenn beide Bereiche sich NICHT schneiden, so kommts zu keienr Kollision und es kann beendet werden
      if not collision1DCheck(minMaxA, minMaxB) then Exit;
    end;
    Result := True;
  end;
begin
  Result := False;
  if (Length(PolyA) < 2) or (Length(PolyB) < 2) then Exit;
  if not BoundingBoxCollisionCheck(PolyA, PolyB) then Exit;
  P1 := @PolyA;
  P2 := @PolyB;
  if collisionCheck then
  begin
    P1 := @PolyB;
    P2 := @PolyA;
    Result := collisionCheck;
  end;
end;
Das ganze ist noch mit Bounding Boxes optimiert.
Hf
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG

Geändert von Aphton (23. Mär 2012 um 17:12 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:39 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