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?
Je combine généralement PointToScreen
et PointToClient
:
Point locationOnForm = control.FindForm().PointToClient(
control.Parent.PointToScreen(control.Location));
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.
Je le fais habituellement comme ça .. Fonctionne à chaque fois ..
var loc = ctrl.PointToScreen(Point.Empty);
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;
}
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;
}
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;
}
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;
}
}
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;
}
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);
}