2010-10-19 2 views
5

In meiner C# (. NET 2) -App möchte ich bestimmen, welches Steuerelement im Schrank der Maus ist.Bestimmen Sie, welches Steuerelement dem Mauszeiger am nächsten ist

Ich kann mir ein paar Möglichkeiten vorstellen, dies zu tun, die nicht ganz richtig funktionieren. Ich könnte die Control.Location Eigenschaft verwenden, aber das gibt mir nur oben/links, und die Maus könnte auf der anderen Seite des Steuerelements sein. Ich könnte den Mittelpunkt eines Steuerelements berechnen, aber große Steuerelemente würden dies verzerren (da es sich in der Nähe der Kante eines Steuerelements befindet, zählt es als in der Nähe des Steuerelements).

Also im Grunde habe ich eine Reihe von Rechtecken auf einer Leinwand und einem Punkt. Ich muss das Rechteck finden, das dem Punkt am nächsten ist.

(Idealerweise möchte ich auch den Abstand zwischen Punkt und Rechteck kennen).

Irgendwelche Ideen?

+0

Hat eine dieser Antworten Ihnen geholfen? –

Antwort

3

Sie müssen die folgenden finden:
- Distanz zur nächsten Ecke
- Distanz zur nächsten Kante
- (optional) zum Zentrum Entfernung

Grundsätzlich Sie möchte den kleineren dieser drei Werte. Nimm das Minimum davon für zwei Kontrollen, um zu bestimmen, welches näher ist.

Beginnen Sie, wenn Sie das Formular laden, indem Sie alle Steuerelemente auf dem Formular durchlaufen und eine Auflistung der Klasse unten erstellen.

Um die nächste Kontrolle zu einem Punkt zu finden, iterieren Sie die Sammlung (siehe Code unten). Verfolgen Sie die Kontrolle mit dem minimalen Abstand, den Sie bisher gefunden haben. Sie können für ContainsPoint() testen, wenn Sie möchten ... wenn Sie ein Steuerelement finden, bei dem der Punkt in die Kontrollgrenzen fällt, haben Sie Ihr Steuerelement (solange Sie keine überlappenden Steuerelemente haben). Andernfalls, wenn Sie das Ende der Sammlung erreicht haben, ist die Kontrolle, die Sie mit der kürzesten Entfernung zur Mitte/Kante gefunden haben, Ihre Kontrolle.

public class HitControl { 

    public Control ThisControl; 

    private Rectangle ControlBounds; 
    private Point Center; 

    public HitControl (Control FormControl) { 
     ControlBounds = FormControl.Bounds; 
     Center = new Point(ControlBounds.X + (ControlBounds.Width/2), ControlBounds.Y + (ControlBounds.Height/2)); 
    } 

    // Calculate the minimum distance from the left, right, and center 
    public double DistanceFrom(Point TestPoint) { 

     // Note: You don't need to consider control center points unless 
     // you plan to allow for controls placed over other controls... 
     // Then you need to test the distance to the centers, as well, 
     // and pick the shortest distance of to-edge, to-side, to-corner 

     bool withinWidth = TestPoint.X > ControlBounds.X && TestPoint.X < ControlBounds.X + ControlBounds.Width; 
     bool withinHeight = TestPoint.Y > ControlBounds.Y && TestPoint.Y < ControlBounds.Y + ControlBounds.Height; 

     int EdgeLeftXDistance = Math.Abs(ControlBounds.X - TestPoint.X); 
     int EdgeRightXDistance = Math.Abs(ControlBounds.X + ControlBounds.Width - TestPoint.X); 

     int EdgeTopYDistance = Math.Abs(ControlBounds.Y - TestPoint.Y); 
     int EdgeBottomYDistance = Math.Abs(ControlBounds.Y + ControlBounds.Height - TestPoint.Y); 

     int EdgeXDistance = Math.Min(EdgeLeftXDistance, EdgeRightXDistance); 
     int EdgeYDistance = Math.Min(EdgeTopYDistance, EdgeBottomYDistance); 


     // Some points to consider for rectangle (100, 100, 100, 100): 
     // - (140, 90): Distance to top edge 
     // - (105, 10): Distance to top edge 
     // - (50, 50): Distance to upper left corner 
     // - (250, 50): Distance to upper right corner 
     // - (10, 105): Distance to left edge 
     // - (140, 105): Distance to top edge 
     // - (105, 140): Distance to left edge 
     // - (290, 105): Distance to right edge 
     // - (205, 150): Distance to right edge 
     // ... and so forth 


     // You're within the control 
     if (withinWidth && withinHeight) { 
      return Math.Min(EdgeXDistance, EdgeYDistance); 
     } 

     // You're above or below the control 
     if (withinWidth) { 
      return EdgeYDistance; 
     } 

     // You're to the left or right of the control 
     if (withinHeight) { 
      return EdgeXDistance; 
     } 

     // You're in one of the four outside corners around the control. 
     // Find the distance to the closest corner 
     return Math.Sqrt(EdgeXDistance^2 + EdgeYDistance^2); 


    } 

    public bool ContainsPoint (Point TestPoint) { 
     return ControlBounds.Contains(TestPoint); 
    } 


} 



// Initialize and use this collection 
List<HitControl> hitControls = (from Control control in Controls 
           select new HitControl(control)).ToList(); 

Point testPoint = new Point(175, 619); 
double distance; 
double shortestDistance = 0; 
HitControl closestControl = null; 

foreach (HitControl hitControl in hitControls) { 

    // Optional... works so long as you don't have overlapping controls 
    // If you do, comment this block out 
    if (hitControl.ContainsPoint(testPoint)) { 
     closestControl = hitControl; 
     break; 
    } 

    distance = hitControl.DistanceFrom(testPoint); 
    if (shortestDistance == 0 || distance < shortestDistance) { 
     shortestDistance = distance; 
     closestControl = hitControl; 
    } 
} 

if (closestControl != null) { 
    Control foundControl = closestControl.ThisControl; 
} 
0

Sie haben in Bezug auf die Rechtecke zu denken :)

  1. Test: Ist die Maus im Griff?
  2. Wenn nicht: Wie weit entfernt von einer einzelnen Kante?

Dann müssen Sie wissen, welche Kontrollen Sie interessiert sind, die Form, beispielsweise eine Steuer ..

0

Für den Anfang Methode erstellen, die Abstand von dem Rechteck Rand bis zu einem gewissen beliebigen Punkt berechnen wird . Unterschrift für diese Methode sollte sein:

double DistanceFrom(Rect r, Point p); 

Dann wird für die einfachste versuchen, laufen alle Steuerelemente, berechnen Abstand, remeber den Mindestabstand und Kontrolle, die sie zur Verfügung gestellt.

Für die Rechteckentfernung überprüfen Sie this aus.

EDIT:

In der Tat können Sie eine sortierte Liste von Kontrollen beibehalten, so dass Sie immer zuerst die man haben kann, die näher an der Spitze ist, und halten Sie diese Liste, wie die Maus bewegt - es kann sich als effizienter sein in Bezug auf die Geschwindigkeit. Interessante Frage aber :)

1

Zuerst prüfen, ob der Punkt in einem rectangle ist. Wenn nicht, können Sie den Abstand zwischen Ihrem Punkt und jedem Liniensegment mit dem Algorithmus in this finden. Sie können auch die 4 Segmente Ihres Controls finden, so dass Sie eine Liste von vier Segmenten haben (das erste Mal initiiert) (bestimmen Sie die Kontrollseiten) und jetzt können Sie das nächste Segment, das nächste Rechteck, finden.

0

Ich stimme mit Daniel überein, dass wir brauchen: double DistanceFrom (Rect r, Point p);

Aber zuvor brauchen wir: double DistanceFrom (Linie r, Punkt p); und doppelte AngleBetweenPoints (Punkt p1, Punkt p2);