![]() |
Überprüfen ob Mausklick in bestimmten bereich war
Ich habe ein großes Image und möchte überprüfen ob der Mausklick in bestimmten Rechtecken war.
Welche Prozeduren etc würden da gehen? |
Re: Überprüfen ob Mausklick in bestimmten bereich war
machs doch so:
Delphi-Quellcode:
x,y: Mauskoordinate; top, left, width, height: ein Zielbereich:
if (x>left) and (x<(left+width)) and (y>top) and (y<(top+height)) then showmessage('drin'); |
Re: Überprüfen ob Mausklick in bestimmten bereich war
So... Und jetzt 26 mal???
ich dachte da vielleicht an einen Vergleich:
Delphi-Quellcode:
for i := 0 to 25 do
if inRect(myRect[i], X, Y) then begin {...} end; |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Wo ist denn das Problem?
// Bei rectangle waren doch die ersten Koordinaten die ecke links oben und die zweiten rechts unten, oder?
Delphi-Quellcode:
Function inRect(Rect[i], X, Y): boolean;
begin result:= false; if (x>Rect[i].x1) and (x<(Rect[i].x2-Rect[i].x1)) and (das gleiche für y ) then result:= true; |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Was ist denn jetzt dein Problem?
Packe doch den Boolschen ausdruck von oben in eine Funktion "inRect" und rufe diese 26 Mal auf. EDIT: Wo war dieser Rote Kasten...
Delphi-Quellcode:
Wäre einfacher...
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; |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Und noch ein Ansatz:
Delphi-Quellcode:
Grüße vom marabu
type
TRects = array of TRect; var rects: TRects; function InRect(rects: TRects; pt: TPoint): Boolean; var i: Integer; begin Result := True; for i := Low(rects) to High(rects) do if PtInRect(rects[i], pt) then Exit; Result := False; end; |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Igels Version dürfte die schnellste sein, da sie keine Branches enthält...
Allerdings dürften die Unterschiede minimal sein, kann sogar sein, dass der Compiler sowieso das so stark optimiert, dass es gar nicht mehr auffällt. |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Ich denke mal, das ganze bezieht sich auf
![]() Wäre es nicht besser, bei einem Klick die Koordinaten zu nehmen und berechnen zu lassen, auf welchen Koffer man gedrückt hat? Die Koffer sind ja immer gleich groß. Sagen wir mal 50 Pixel breit. Wenn du dann als X-Wert sowas wie 384 bekommst weißt du, dass 384 / 50 = 7 (Rest 34) ist, also der 7. Koffer in der Reihe gedrückt wurde. Jetzt musst du nur noch den Rand "ausmessen", bei dem links jeweils der erste Koffer beginnt. grrr... ich bin gerade erst aufgestanden und kann noch keine Texte schreiben, ich hoffe es ist klar, was ich meine. Ich denke, diese Art wäre schneller, als alle 26 mal inRect auszuführen. |
Re: Überprüfen ob Mausklick in bestimmten bereich war
Okay die Funktion könnte ich mir selber schreiebn (:D), was mich am ersten asnatz gestört hat ist die "komplexibilität"...
Da bilckt man nicht so einfach durch... Da ist die "InRect" Methode besser. Okay... Dann mache ich's so ;) [roter Kasten] o.O Öhm ja, so könnte man es machen :D 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 :mrgreen: )[/roter Kasten] |
Re: Überprüfen ob Mausklick in bestimmten bereich war
bei seinem Dond sind die Koffer aber nicht schön wie auf einem Schachbrett angeordnet, sondern die zweite Reihe beginnt eine halbe Kofferbreite weiter rechts als die erste. Um das auch noch zu berücksichtigen müsste man auch noch ein paar Abfragen schreiben.
Da die Koffersuche aber nur alle paar minuten mal ausgeführt werden muss, ist es hier wichtiger einen gut verständlichen Code zu schreiben, als einen schnellen. |
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 |
AW: Überprüfen ob Mausklick in bestimmten bereich war
Das Separating Axis Theorem gilt aber afair nur für konvexe Polygone.
|
AW: Überprüfen ob Mausklick in bestimmten bereich war
Liste der Anhänge anzeigen (Anzahl: 1)
Ist ja logisch, denn alle Punkte werden ohne weiteres projeziert. Allein von der Logik her ist das ersichtlich.
Daher schrieb ich Zitat:
|
AW: Überprüfen ob Mausklick in bestimmten bereich war
Hab das nur überflogen, aber ich glaube das Thema hatten wir hier schon mal:
![]() |
AW: Überprüfen ob Mausklick in bestimmten bereich war
Danke für die vielen hilfreichen Beiträge.
Damit habt Ihr mir schon mal sehr weitergeholfen! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:50 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