[C#][Winforms] [Resolu] Centrer automatiquement un panel dans une Form

Centrer automatiquement un panel dans une Form [C#][Winforms] [Resolu] - C#/.NET managed - Programmation

Marsh Posté le 08-12-2005 à 14:56:20    

Bonjour.
 
Alors voila, je fais une application Winforms en C# pour Windows et j'utilise Visual Studio .NET 2003.
J'ai donc une form principale (Form1) dans laquelle j'ai ajoute un panel (panel1) possedant une image de fond.
Le panel peut avoir 2 tailles principalement (depends en fait de 2 images differentes), mais j'aimerai que ce soit relativement adaptable (ie quelle que soit la taille de l'image).
Maintenant, j'aimerai que le panel reste au centre de la form quelle que soit sa taille (La fenetre peut donc etre resizee), avec apparition d'ascenceurs de scroll si la taille du panel est plus grande que celle de la form, comme pour le "Windows Picture Viewer" sous XP par exemple.
Ce que j'ai fait pour l'instant, c'est mettre l'attribut "autoscroll" a "true" pour la form, et calculer la position du panel en fonction des tailles respectives du panel et de la form.
Un peu de code pour que ca soit plus clair:
 
Dans la methode InitializeComponent de la Form (genere automatiquement donc):

Code :
  1. this.AutoScaleBaseSize = ((System.Drawing.Size)(resources.GetObject("$this.AutoScaleBaseSize" ))); // Valeur a true
  2. this.AutoScroll = ((bool)(resources.GetObject("$this.AutoScroll" ))); // Valeur a true
  3. this.AutoScrollMargin = ((System.Drawing.Size)(resources.GetObject("$this.AutoScrollMargin" ))); // Valeurs a 0 et 0
  4. this.AutoScrollMinSize = ((System.Drawing.Size)(resources.GetObject("$this.AutoScrollMinSize" ))); // Valeurs a 0 et 0


 
Puis pour que la position soit calculee a l'instanciation et a chaque fois que la fenetre change de taille, voici la methode CenterSoccerGround dans Form1, appelee par le constructeur puis a chaque fois que la fenetre change de taille (grace a l'event Resize):

Code :
  1. private void CenterSoccerGround()
  2.  {
  3.   if (this.panel1 != null)
  4.   {
  5.    this.panel1.Location = new System.Drawing.Point((this.ClientSize.Width - this.panel1.Width) / 2, (this.ClientSize.Height - this.panel1.Height) / 2);
  6.   }
  7.  }


 
Ca marche pas mal (a part que c'est un peu lent mais ca ne vient peut-etre pas de la), sauf que quand la taille de la fenetre est plus petite que celle du panel, la position de ce dernier devient donc negative et le scroll commencant a la position 0, on ne peut pas acceder aux parties extremes gauche et/ou haut.
 
Ma question est donc (on y arrive  ;) ), comment faire pour que ca marche, y compris pour les cotes extremes (gauche et haut)?
Peut-etre faut-il faire autrement, mais apres de longs jours de recherche grace a Google et sur les forums de programmation, je n'ai pas trouve de methode pour faire ca...
 
Je precise que c'est mon premier programme en C#, mais que j'ai quelques annees d'experience de programmation en C (surtout) et C++ sous Unix, ainsi qu'un peu sous Visual Studio (un peu de Java aussi a mon actif). En gros, je suis etudiant...
 
Voila, merci d'avance.
 
Mooga
 
PS: Desole pour le manque d'accents, mais je suis en Irlande avec des claviers "qwerty", donc c'est pas facile...
Je les rajouterai si c'est genant...


Message édité par Mooga le 12-12-2005 à 14:26:03
Reply

Marsh Posté le 08-12-2005 à 14:56:20   

Reply

Marsh Posté le 08-12-2005 à 17:38:05    

Tu veux faire quoi comme type d'application ?
Un Viewer d'image ?
Un panel c'est fait pour contenir des contrôles. Si c'est juste l'image qui t'intéresse, pourquoi n'utilises-tu pas une PictureBox ?
Et encore... y'a plus rapide.
 
Qu'est ce que tu appelles 'lent' au fait ? Comme VS.Net avec une solution chargées quand tu le resize ? Ou bien pire ?
Si c'est comme VS.Net, alors c'est normal : un panel c'est pas rapide au resize.
 
Sinon une question de plus : le but c'est de centrer l'image et de pouvoir scroller pour voir les parties cachées, mais quid des autres controls ? Si tu scrolles ils doivent rester fixes ou bouger aussi ?

Message cité 1 fois
Message édité par _Mose_ le 08-12-2005 à 17:47:06
Reply

Marsh Posté le 08-12-2005 à 18:06:29    

_Mose_ a écrit :

Tu veux faire quoi comme type d'application ?
Un Viewer d'image ?
Un panel c'est fait pour contenir des contrôles. Si c'est juste l'image qui t'intéresse, pourquoi n'utilises-tu pas une PictureBox ?
Et encore... y'a plus rapide.


En fait, je mets des choses dans le panel bien sur...
Pour plus de precisions, c'est un logiciel qui permet de placer des elements (maillot de joueurs, ballon, fleches) sur un terrain de foot (le panel), pour ensuite pouvoir l'exporter en image. Donc je ne crois pas que c'etait possible avec une PictureBox, panel me paraissait pas mal...
 

_Mose_ a écrit :

Qu'est ce que tu appelles 'lent' au fait ? Comme VS.Net avec une solution chargées quand tu le resize ? Ou bien pire ?
Si c'est comme VS.Net, alors c'est normal : un panel c'est pas rapide au resize.


C'est lent pour l'affichage de l'image du panel seulement (c'est a dire que quand le panel est plus petit que la form, ca ne rame pas). Un peu plus que pour un VS.NET charge. Mais bon, je suis sur que j'ai fait des trucs pas tres beau pour l'affichage et le refresh de certains composants dans le panel... C'est une autre histoire....
 

_Mose_ a écrit :

Sinon une question de plus : le but c'est de centrer l'image et de pouvoir scroller pour voir les parties cachées, mais quid des autres controls ? Si tu scrolles ils doivent rester fixes ou bouger aussi ?


Il n'y a pas d'autres controls dans la form, juste dans le panel. Mais s'il y en avait, il faudrait qu'ils bougent aussi.

Reply

Marsh Posté le 08-12-2005 à 19:14:04    

 Je pense que ça répond à ton besoin. Et c'est assez rapide avec un panel vide.
Tu peux même enlever les valeurs que tu as mises à AutoScrollMargin et AutoScrollMinSize, tu as juste besoin d'avoir AutoScroll à true.
 

Code :
  1. /// <summary>
  2. /// Change l'image de fond
  3. /// </summary>
  4. private void ChangerImage(Image image)
  5. {
  6. // changer l'autoscrollminsize (elle doit faire la taille de l'image)
  7. this.AutoScrollMinSize = image.Size;
  8. // centrer le scrolling sur le centre de l'image
  9. this.AutoScrollPosition = new Point((image.Width >> 1), (image.Height >> 1));
  10. // suspendre les évènement du panel pour éviter un scintillement au chgt d'image
  11. this.panel.SuspendLayout();
  12. // changer la taille du panel
  13. this.panel.Size = image.Size;
  14. // changer l'image de fond du panel
  15. this.panel.BackgroundImage = image;
  16. // bouger le panel si besoin
  17. this.DeplacerPanelSiBesoin();
  18. // reprendre les évènement du panel
  19. this.panel.ResumeLayout(true);
  20. }
  21. /// <summary>
  22. /// Déplace le panel au centre de l'image en cas de besoin
  23. /// </summary>
  24. private void DeplacerPanelSiBesoin()
  25. {
  26. // récupère l'image de fond
  27. Image image = this.panel.BackgroundImage;
  28. // si y'en a une
  29. if(image != null)
  30. {
  31.  // récupére la position du panel
  32.  Point newloc = panel.Location;
  33.  // si la largeur de l'image est plus grande que la largeur de la form
  34.  if(image.Width > this.Width)
  35.   // alors le panel doit être placé en x=0 (par rapport à la fenêtre dans scrolling)
  36.   newloc.X = this.AutoScrollPosition.X;
  37.  else // si l'image est plus petite
  38.   // le centre de l'image doit être placé au centre de la form
  39.   newloc.X = ((this.Width - image.Width) >> 1);
  40.  // si la hauteur de l'image est plus grande que la hauteur de la form
  41.  if(image.Height > this.Height)
  42.   // alors le panel doit être placé en y=0 (par rapport à la fenêtre dans scrolling)
  43.   newloc.Y = this.AutoScrollPosition.Y;//0;
  44.  else // si l'image est plus petite
  45.   // le centre de l'image doit être placé au centre de la form
  46.   newloc.Y = ((this.Height - image.Height) >> 1);
  47.  // si on a détécté un changement de taille
  48.  if(newloc != this.panel.Location)
  49.   // on l'applique
  50.   this.panel.Location = newloc;
  51. }
  52. }
  53. /// <summary>
  54. /// En cas de redimensionnement
  55. /// </summary>
  56. protected override void OnResize(EventArgs e)
  57. {
  58. base.OnResize (e);
  59. // déplacer le panel si besoin
  60. this.DeplacerPanelSiBesoin();
  61. }


---------------
Tout est normal, suffit de comprendre pourquoi.
Reply

Marsh Posté le 09-12-2005 à 16:38:20    

Bon alors merci deja pour la reponse, surtout si rapide.
 
Donc pour la methode "ChangerImage", je ne l'ai pas utilise car lorsque je veux chqnger l'imqge de fond, ca veut dire que je cree un nouveau terrain, donc je prefere supprimer tout l'ancien panel et ce qu'il contient (plus sur aussi je trouve, histoire de ne pas me retrouver avec des controls en dehors du panel etc.) => influence du C sur moi je pense, et je n'aime pas faire aveuglement confiance au garbage collector....
 
Sinon, j'ai utilise ce que tu m'as fourni, a une modification pres:
- d'importance mineur, mais j'ai utilise this.ClientSize.Width au lieu de this.Width (resp. pour Height), car sinon, avec des menus, barres de notification, ca centre au niveau de la fenetre et non de la surface de travail.
 
Apres ca, ca ne centre pas exactement tout le temps le panel au centre. En fait, il centre le control contenu dans le panel qui a le focus. S'il n'y en a pas, le panel reste en (0, 0), et le scroll aussi. Sinon, il essaye de garder le control qui a le focus visible.
Ce n'est pas tout a fait ce que je cherchais, mais ca me convient parfaitement, mon but etant de toujours pouvoir acceder a l'integralite de la surface du panel, et de le centrer au maximum.
 
Voici le code final de ma methode:

Code :
  1. private void CenterSoccerGround() // Equivalent de DeplacerPanelSiBesoin()
  2.  {
  3.   // récupère l'image de fond
  4.   Image image = null;
  5.   // Necessaire pour eviter une exception de type NullPointer si on appelle cette methode
  6.   // avant d'instancier le panel (c'est pas moi c'est VS ;) )
  7.   if (this.panel1 != null)
  8.    image = this.panel1.BackgroundImage;
  9.   // si y'en a une
  10.   if(image != null)
  11.   {
  12.    // récupére la position du panel
  13.    Point newloc = this.panel1.Location;
  14.    // si la largeur de l'image est plus grande que la largeur de la form
  15.    if(image.Width > this.ClientSize.Width)
  16.     // alors le panel doit être placé en x=0 (par rapport à la fenêtre dans scrolling)
  17.     newloc.X = this.AutoScrollPosition.X;
  18.    else // si l'image est plus petite
  19.     // le centre de l'image doit être placé au centre de la form
  20.     newloc.X = ((this.ClientSize.Width - image.Width) >> 1);
  21.    // si la hauteur de l'image est plus grande que la hauteur de la form
  22.    if(image.Height > this.ClientSize.Height)
  23.     // alors le panel doit être placé en y=0 (par rapport à la fenêtre dans scrolling)
  24.     newloc.Y = this.AutoScrollPosition.Y; //0;
  25.    else // si l'image est plus petite
  26.     // le centre de l'image doit être placé au centre de la form
  27.     newloc.Y = ((this.ClientSize.Height - image.Height) >> 1);
  28.    // si on a détecté un changement de taille
  29.    if(newloc != this.panel1.Location)
  30.     // on l'applique
  31.     this.panel1.Location = newloc;
  32.   }
  33.  }


 
Enfin, pour la lenteur, ca n'a l'air guere mieux (pas vraiment de difference remarquable), mais je pense toutefois que le probleme ne vient pas de la mais du fait que je "refresh" tous les controls contenus dans le panel un peu trop souvent. Si ca ne gene pas trop, je laisserai comme ca.
 
Merci encore et a la prochaine  :jap:  
 
Mooga

Reply

Marsh Posté le 12-12-2005 à 16:32:30    

Deux précisions et une question :
 
1-> Tu as RAISON pour le vidage de la mémoire. Il faut rajouter, dans ChangerImage :

Code :
  1. //vider la memoire
  2. if(this.panel.BackgroundImage != null)
  3. {
  4.    this.panel.BackgroundImage.Dispose();
  5.    this.panel.BackgroundImage = null;
  6. }

2-> J'ai laissé du code de Geek dans ce que j'ai envoyé : les  (x >> 1)  c'est équivalent à (x / 2)
C'est une vieille technique de demomaker pour gagner des microsecondes : un décalage à droite ça prend un cycle, une division beaucoup plus. En l'occurence on fait pas du temps réel donc c pas très utile.
 
?-> C'est à quel moment qu'il cherche à garder visible le contrôle qui a le Focus ? Au Resize ?


---------------
Tout est normal, suffit de comprendre pourquoi.
Reply

Marsh Posté le 20-12-2005 à 18:50:33    

Desole pour le temps de reaction, ca doit etre les fetes qui approchent...
 
Bref, oui, il cherche a garder visible le controle qui a le focus au resize.
 
PS: Je connais les decalages a gauche, droite et les combines de Geek pour aller plus vite ou pour ecrire moins de code, mais finalement et apres plusieurs maux de crane, c'est quand meme vachement plus clair avec des methodes plus conventionnelles ;)

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed