2010-10-19 11 views
5

W mojej aplikacji C# (.NET 2) chciałbym określić, która kontrola znajduje się w pobliżu myszy.Ustal, która kontrola znajduje się najbliżej wskaźnika myszy.

Mogę wymyślić kilka sposobów na zrobienie tego, co nie będzie działać poprawnie. Mógłbym użyć właściwości Control.Location, ale to tylko daje mi górę/lewo, a myszka może znajdować się po drugiej stronie kontrolki. Mógłbym obliczyć punkt środkowy kontroli, ale duże kontrole przekrzywiłyby to (bycie blisko krawędzi kontrolnej liczy się jako blisko kontroli).

Więc w zasadzie mam pęczku prostokąty na płótnie i punkt. Muszę znaleźć prostokąt najbliżej punktu.

(Idealnie chciałbym znać odległość między punktem a prostokątem).

Wszelkie pomysły?

+0

Czy jedna z tych odpowiedzi Ci pomogła? –

Odpowiedz

3

Trzeba znaleźć następujące:
- Odległość do najbliższego rogu
- Odległość do najbliższej krawędzi
- (opcjonalnie) Odległość do centrum

Zasadniczo, chcą mniejszej z tych trzech wartości. Minimum tego dla dwóch kontroli, aby ustalić, które jest bliżej.

Rozpocznij po załadowaniu formularza przez iterowanie wszystkich formantów w formularzu i utworzenie kolekcji klasy poniżej.

Aby znaleźć najbliższą kontrolę do punktu, należy powtórzyć kolekcję (patrz kod u dołu). Śledź kontrolę z minimalną odległością, jaką dotychczas znalazłeś. Możesz przetestować ContainsPoint(), jeśli chcesz ... Jeśli znajdziesz kontrolę, w której punkt mieści się w granicach kontrolnych, masz kontrolę (o ile nie masz nakładających się elementów sterujących). W przeciwnym razie, gdy dojdziesz do końca kolekcji, kontrola, którą znalazłeś przy najkrótszej odległości od centrum/krawędzi, jest twoją kontrolą.

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

Trzeba myśleć w kategoriach prostokątów :)

  1. Test: Czy mysz w ciągu kontroli?
  2. Jeśli nie: Jak daleko od pojedynczej krawędzi?

Następnie trzeba wiedzieć, które kontroluje jesteś zainteresowany, forma jest, na przykład, kontroli ..

0

Na początek stworzyć metodę, która będzie obliczyć odległość od krawędzi prostokąta w pewnym dowolnym punkcie . Podpis dla tej metody powinny być:

double DistanceFrom(Rect r, Point p); 

Następnie do najprostszych spróbować, iteracyjne wszystkie kontrolki, obliczyć odległości, zapamiętania minimalnej odległości i kontroli, które je dostarczyły.

Aby uzyskać odległość prostokąta, należy sprawdzić this na zewnątrz.

EDIT:

W rzeczywistości, można utrzymać posortowaną listę kontroli, dzięki czemu można zawsze mieć pierwszy, który jest bliżej na górze, i utrzymać tę listę jako ruchów myszką - może okazać się bardziej wydajne pod względem prędkości. Interesującą kwestią chociaż :)

1

Najpierw sprawdź punkt jest w każdym rectangle. Jeśli nie, możesz znaleźć odległość między punktem i każdym odcinkiem linii za pomocą algorytmu w this. Możesz również znaleźć 4 segmenty kontrolki, więc masz listę (zainicjowaną po raz pierwszy) czterech segmentów (określającą strony kontrolne), a teraz możesz znaleźć najbliższy segment, najbliższy prostokąt.

0

Zgadzam się z Danielem, że potrzebujemy: double DistanceFrom (Rect r, Point p);

Ale wcześniej potrzebujemy: double DistanceFrom (Line r, Point p); i podwójne punkty kątowe między punktami (punkt p1, punkt p2);

Powiązane problemy