web-dev-qa-db-fra.com

C # Obtenir la position d'un contrôle sur un formulaire

Existe-t-il un moyen de récupérer la position d'un contrôle dans un formulaire, lorsque le contrôle peut être à l'intérieur d'autres contrôles (comme les panneaux)?

Les propriétés Left et Top du contrôle ne me donnent que sa position dans son contrôle parent, mais que se passe-t-il si mon contrôle se trouve à l'intérieur de cinq panneaux imbriqués et que j'ai besoin de sa position sur le formulaire?

Exemple rapide:

Le bouton btnA est situé sur les coordonnées (10,10) à l'intérieur du panneau pnlB.
Le panneau pnlB est situé sur les coordonnées (15,15) à l'intérieur du formulaire frmC.

Je veux l'emplacement de btnA sur frmC, qui est (25,25).

Puis-je obtenir cet emplacement?

63
Erlend D.

Je combine généralement PointToScreen et PointToClient:

Point locationOnForm = control.FindForm().PointToClient(
    control.Parent.PointToScreen(control.Location));
88
Fredrik Mörk

Vous pouvez utiliser la méthode Controls PointToScreen pour obtenir la position absolue par rapport à l'écran.

Vous pouvez utiliser la méthode Forms PointToScreen et, avec les mathématiques de base, obtenir la position du contrôle.

11
Raj More

Je le fais habituellement comme ça .. Fonctionne à chaque fois ..

var loc = ctrl.PointToScreen(Point.Empty);
7
noisyass2

Vous pouvez remonter à travers les parents, en notant leur position au sein de leurs parents, jusqu'à ce que vous arriviez au formulaire.

Edit: Quelque chose comme (non testé):

public Point GetPositionInForm(Control ctrl)
{
   Point p = ctrl.Location;
   Control parent = ctrl.Parent;
   while (! (parent is Form))
   {
      p.Offset(parent.Location.X, parent.Location.Y);
      parent = parent.Parent;
   }
   return p;
}
6
Hans Kesting

Supergeek, votre fonction non récursive n'a pas produit le bon résultat, mais la mienne le fait. Je crois que le vôtre fait un trop grand nombre d'ajouts.

private Point LocationOnClient(Control c)
{
   Point retval = new Point(0, 0);
   for (; c.Parent != null; c = c.Parent)
   { retval.Offset(c.Location); }
   return retval;
}
5
Plater

Curieusement, PointToClient et PointToScreen n'étaient pas idéaux pour ma situation. En particulier parce que je travaille avec des contrôles hors écran qui ne sont associés à aucun formulaire. J'ai trouvé la solution de sahin la plus utile, mais j'ai supprimé la récursivité et éliminé la terminaison du formulaire. La solution ci-dessous fonctionne pour tous mes contrôles visibles ou non, contenus dans un formulaire ou non, IContainés ou non. Merci Sahim.

private static Point FindLocation(Control ctrl)
{
    Point p;
    for (p = ctrl.Location; ctrl.Parent != null; ctrl = ctrl.Parent)
        p.Offset(ctrl.Parent.Location);
    return p;
}
3
BoeroBoy
private Point FindLocation(Control ctrl)
{
    if (ctrl.Parent is Form)
        return ctrl.Location;
    else
    {
        Point p = FindLocation(ctrl.Parent);
        p.X += ctrl.Location.X;
        p.Y += ctrl.Location.Y;
        return p;
    }
}
1
sahin

Lors de mes tests, les solutions de Hans Kesting et de Fredrik Mörk ont ​​donné la même réponse. Mais:

J'ai trouvé une différence intéressante dans la réponse en utilisant les méthodes de Raj More et Hans Kesting, et j'ai pensé partager. Merci aux deux pour leur aide; Je ne peux pas croire qu'une telle méthode ne soit pas intégrée dans le cadre.

Veuillez noter que Raj n'a pas écrit de code et que mon implémentation peut donc être différente de ce qu'il voulait dire.

La différence que j'ai trouvée était que la méthode de Raj More était souvent deux pixels plus grande (en X et Y) que la méthode de Hans Kesting. Je n'ai pas encore déterminé pourquoi cela se produit. Je suis presque sûr que cela a quelque chose à voir avec le fait qu'il semble y avoir une bordure de deux pixels autour du contenu d'un formulaire Windows (comme dans, à l'intérieur des limites extérieures du formulaire). Lors de mes tests, qui n'étaient certainement pas exhaustifs, je ne l'ai rencontré que sur des contrôles imbriqués. Cependant, tous les contrôles imbriqués ne le présentent pas. Par exemple, j'ai un TextBox à l'intérieur d'un GroupBox qui présente la différence, mais pas un Button à l'intérieur du même GroupBox. Je ne peux pas expliquer pourquoi.

Notez que lorsque les réponses sont équivalentes, elles considèrent que le point (0, 0) est à l'intérieur de la bordure de contenu que j'ai mentionnée ci-dessus. Par conséquent, je pense que je considérerai les solutions de Hans Kesting et Fredrik Mörk comme correctes, mais je ne pense pas que je ferai confiance à la solution que j'ai mise en œuvre pour Raj More.

Je me suis également demandé exactement quel code Raj More aurait écrit, car il a donné une idée mais n'a pas fourni de code. Je n'ai pas entièrement compris la méthode PointToScreen () jusqu'à ce que j'ai lu ce post: http://social.msdn.Microsoft.com/Forums/en-US/netfxcompact/thread/aa91d4d8-e106-48d1-8e8a -59579e14f495

Voici ma méthode de test. Notez que la "méthode 1" mentionnée dans les commentaires est légèrement différente de celle de Hans Kesting.

private Point GetLocationRelativeToForm(Control c)
{
  // Method 1: walk up the control tree
  Point controlLocationRelativeToForm1 = new Point();
  Control currentControl = c;
  while (currentControl.Parent != null)
  {
    controlLocationRelativeToForm1.Offset(currentControl.Left, currentControl.Top);
    currentControl = currentControl.Parent;
  }

  // Method 2: determine absolute position on screen of control and form, and calculate difference
  Point controlScreenPoint = c.PointToScreen(Point.Empty);
  Point formScreenPoint = PointToScreen(Point.Empty);
  Point controlLocationRelativeToForm2 = controlScreenPoint - new Size(formScreenPoint);

  // Method 3: combine PointToScreen() and PointToClient()
  Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));

  // Theoretically they should be the same
  Debug.Assert(controlLocationRelativeToForm1 == controlLocationRelativeToForm2);
  Debug.Assert(locationOnForm == controlLocationRelativeToForm1);
  Debug.Assert(locationOnForm == controlLocationRelativeToForm2);

  return controlLocationRelativeToForm1;
}
1
Tyler Collier

C'est ce que j'ai fait fonctionne comme un charme

            private static int _x=0, _y=0;
        private static Point _point;
        public static Point LocationInForm(Control c)
        {
            if (c.Parent == null) 
            {
                _x += c.Location.X;
                _y += c.Location.Y;
                _point = new Point(_x, _y);
                _x = 0; _y = 0;
                return _point;
            }
            else if ((c.Parent is System.Windows.Forms.Form))
            {
                _point = new Point(_x, _y);
                _x = 0; _y = 0;
                return _point;
            }
            else 
            {
                _x += c.Location.X;
                _y += c.Location.Y;
                LocationInForm(c.Parent);
            }
            return new Point(1,1);
        }
0
shiroxx