![]() |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Zitat:
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. |
Re: Überprüfen ob Mausklick in bestimmten bereich war
(Das TRect könnte ich in der Zeichenrutine unterbringen :D)
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; |
DP-Maintenance
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 |
AW: Re: Überprüfen ob Mausklick in bestimmten bereich war
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: Zitat:
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. |
AW: Überprüfen ob Mausklick in bestimmten bereich war
Auf die Schnelle fällt mir
![]() ![]() |
AW: Re: Überprüfen ob Mausklick in bestimmten bereich war
Zitat:
Delphi-Quellcode:
, 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.
PtInCirle := sqr(X-P.X)+sqr(Y-P.Y) < sqr(R)
Für Polygone gibt es auch ![]() [edit] Hab mal meinen Port für den verlinten Algorithmus ausgegraben:
Delphi-Quellcode:
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.
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; [/edit] |
AW: Überprüfen ob Mausklick in bestimmten bereich war
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; |
AW: Überprüfen ob Mausklick in bestimmten bereich war
Ab XE2 geht auch sowoas, welches man, für D2006/TD bis XE über einen Record-Helper, selber nachrüsten kann.
Delphi-Quellcode:
Aber bisher sind dort nur Methoden für rechteckige Dinge integriert.
var
R: TRect; P: TPoint; begin if R.Contains(P) then ... |
AW: Überprüfen ob Mausklick in bestimmten bereich war
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:
Habe jetzt nicht nachgeschaut wie sich das in Delphi verwirklichen läßt.
GetCursorPos pos
If WindowFromPoint(pos.X, pos.Y) = PicButton(Index).hWnd Then ups.. hab mich da wohl verlesen ;) gruss |
AW: Überprüfen ob Mausklick in bestimmten bereich war
Hier, eine etwas allgemeinere Lösung
![]() 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. ![]() ![]() (bei Bild 2 sieht man, dass der grüne und rote Bereich sich nicht schneiden -> keine Kollision)
Delphi-Quellcode:
Das ganze ist noch mit Bounding Boxes optimiert.
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; Hf |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz