33 votes

Comment contrôler la police DPI dans l'application .NET WinForms

J'ai créé une application pour une petite entreprise. Certains employés du bureau ne peuvent pas voir correctement le formulaire. La raison en est que leur paramètre DPI est supérieur à 96 dpi. Quelqu'un connaît-il un moyen de contrôler cela?

Pour tous ceux qui ont de l'expérience avec les applications Winforms, comment contrôlez-vous la mise en page de votre formulaire pour que DPI n'affecte pas l'apparence de l'application?

63voto

Ian Boyd Points 50743

En supposant que vous n'essayez pas de l'honneur de l'utilisateur de l'INTERFACE utilisateur le choix de la police (SystemFonts.IconTitleFont), et du code en dur vos formes pour une taille de caractères (par exemple, Tahoma 8pt, Microsoft Sans Serif 8.25 pt), vous pouvez définir votre formulaire AutoScaleMode de ScaleMode.Dpi.

Cela va à l'échelle de la taille de la forme et de la plupart des enfants contrôles par le facteur CurrentDpiSetting / 96 en appelant Form.Scale(), qui s'appelle la protégée ScaleControl() méthode recursivly sur lui-même et tous les contrôles enfants. ScaleControl va augmenter d'un contrôle de la position, la taille, la police, etc comme nécessaire pour le nouveau facteur d'échelle.

Attention: Pas tous les contrôles correctement échelle d'eux-mêmes. Les colonnes d'un listview, par exemple, ne sera pas plus large que la police devient plus grand. Dans pour gérer tout cela, vous aurez à effectuer manuellement supplémentaires de mise à l'échelle comme nécessaire. - je le faire en remplaçant la protégés ScaleControl() méthode, et mise à l'échelle de la liste des colonnes manuellement:

public class MyForm : Form
{
   protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   {
      base.ScaleControl(factor, specified);
      Toolkit.ScaleListViewColumns(listView1, factor);
   }
}

public class Toolkit  
{
   /// <summary>
   /// Scale the columns of a listview by the Width scale factor specified in factor
   /// </summary>
   /// <param name="listview"></param>
   /// <param name="factor"></param>
   /// <example>/*
   /// protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   /// {
   ///    base.ScaleControl(factor, specified);
   ///    
   ///    //ListView columns are not automatically scaled with the ListView, so we
   ///    //must do it manually
   ///    Toolkit.ScaleListViewColumns(lvPermissions, factor);
   /// }
   ///</example>
   public static void ScaleListViewColumns(ListView listview, SizeF factor)
   {
      foreach (ColumnHeader column in listview.Columns)
      {
          column.Width = (int)Math.Round(column.Width * factor.Width);
      }
   }
}

C'est très bien si vous êtes juste en utilisant des contrôles. Mais si jamais vous utilisez tout codé en dur tailles de pixel, vous aurez besoin à l'échelle de votre pixels de largeurs et de longueurs par le facteur d'échelle de la forme. Quelques exemples de situations qui pourraient avoir codé en dur, taille de pixel:

  • dessin d'un 25px haute rectangle
  • dessin d'une image à l'emplacement (11,56) sur le formulaire
  • étirer le dessin d'une icône pour 48x48
  • le dessin du texte à l'aide de Microsoft Sans Serif 8.25 pt
  • l'obtention de la 32x32 format de l'icône et la farce dans un PictureBox

Si c'est le cas, vous aurez besoin à l'échelle de ces valeurs codées en dur par le "courant facteur d'échelle". Malheureusement, le "courant" facteur d'échelle n'est pas fourni, nous avons besoin de l'enregistrer nous-mêmes. La solution est de supposer qu'initialement, le facteur d'échelle est de 1,0 et à chaque fois, ScaleControl() est appelé, de modifier le fonctionnement facteur d'échelle par le nouveau facteur.

public class MyForm : Form
{
   private SizeF currentScaleFactor = new SizeF(1f, 1f);

   protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
   {
      base.ScaleControl(factor, specified);

      //Record the running scale factor used
      this.currentScaleFactor = new SizeF(
         this.currentScaleFactor.Width * factor.Width,
         this.currentScaleFactor.Height * factor.Height);

      Toolkit.ScaleListViewColumns(listView1, factor);
   }
}

Initialement, le facteur d'échelle est - 1.0. Si le formulaire est ensuite mis à l'échelle en 1.25, le facteur d'échelle devient alors:

1.00 * 1.25 = 1.25    //scaling current factor by 125%

Si le formulaire est ensuite mis à l'échelle en 0.95, le nouveau facteur d'échelle devient

1.25 * 0.95 = 1.1875  //scaling current factor by 95%

La raison pour laquelle un SizeF est utilisé (plutôt qu'une seule valeur à virgule flottante), c'est que mise à l'échelle, les montants peuvent être différents dans les directions x et y. Si un formulaire est mis à l' ScaleMode.Font, la forme est adaptée à la nouvelle taille de la police. Les polices peuvent avoir différents rapports d'aspect (par exemple, Segoe UI est plus haute police Tahoma). Cela signifie que vous avez à l'échelle des valeurs x et y indépendamment.

Donc si vous voulez placer un contrôle à l'emplacement de (11,56), vous aurez à changer votre positionnement du code à partir de:

Point pt = new Point(11, 56);
control1.Location = pt;

pour

Point pt = new Point(
      (int)Math.Round(11.0*this.scaleFactor.Width),
      (int)Math.Round(56.0*this.scaleFactor.Height));
control1.Location = pt;

La même chose s'applique si vous alliez choisir une taille de police:

Font f = new Font("Segoe UI", 8, GraphicsUnit.Point);

aurait pour devenir:

Font f = new Font("Segoe UI", 8.0*this.scaleFactor.Width, GraphicsUnit.Point);

Et l'extraction d'une 32x32 icône d'une image bitmap allait changer à partir de:

Image i = new Icon(someIcon, new Size(32, 32)).ToBitmap();

pour

Image i = new Icon(someIcon, new Size(
     (int)Math.Round(32.0*this.scaleFactor.Width), 
     (int)Math.Round(32.0*this.scaleFactor.Height))).ToBitmap();

etc.

Soutenir non-standard DPI affiche est un impôt que tous les développeurs devraient payer. Mais le fait que personne ne veut est pourquoi Microsoft a abandonné et est ajouté à Vista, la capacité de la carte graphique pour étirer toutes les applications qui ne disent-ils correctement la poignée de haute résolution.

16voto

Nick Points 7173

Définissez AutoScaleMode pour hériter partout (c'est-à-dire tous vos UserControls) via une recherche / remplacement global, puis définissez AutoScaleMode sur Dpi sur votre formulaire principal.

Je trouve également que les conteneurs de mise en page fonctionnent mieux que les ancres pour ce type de situation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X