web-dev-qa-db-fra.com

Problèmes AutoScaleMode avec la police par défaut modifiée

J'ai des problèmes avec la propriété Form.AutoScaleMode avec des contrôles de taille fixe lorsque j'utilise une police autre que celle par défaut. Je l'ai réduite à une simple application de test (WinForms 2.0) avec un seul formulaire, des contrôles de taille fixe et les propriétés suivantes:

class Form1 : Form
{
    // ...
    private void InitializeComponent()
    {
        // ...
        this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
        this.Font = new System.Drawing.Font("Tahoma", 9.25F);
        // ...
    }
}

Sous 96 dpi, Windows XP, le formulaire ressemble correctement à cet exemple 96 dpi:

96 dpi WinForm

Sous 120 dpi, Windows XP, la fonctionnalité de mise à l'échelle automatique de Windows Forms génère cet exemple en 120 dpi:

Previous WinForm scaled to 120 dpi

Comme vous pouvez le constater, les zones de groupe, les boutons, les vues de liste ou d'arborescence sont correctement mis à l'échelle, les zones de texte multilignes deviennent trop grandes sur l'axe vertical et une étiquette de taille fixe ne se met pas correctement à la verticale et à l'horizontale. Semble être un bogue dans le framework .NET?

EDIT: quelques astuces: le changement de police n’est appliqué qu’au formulaire, les contrôles héritent de la police du formulaire. J'aimerais que cela reste ainsi, si possible.

À l'aide de la police par défaut (Microsoft Sans Serif 8.25pt), ce problème ne se produit pas. L'utilisation de AutoScaleMode = Font (avec AutoScaleDimensions adéquat, bien sûr) n'échelle pas du tout ou est identique à celle décrite ci-dessus, en fonction du moment où la police est définie (avant ou après le changement d'AutoScaleMode). Le problème n'est pas spécifique à la police "Tahoma", il se produit également avec Microsoft Sans Serif, 9.25pt.

Et oui, j'ai déjà lu ce SO post problèmes de DPI élevés , Mais cela ne m'aide pas vraiment.

Des suggestions comment venir à ce sujet?

EDIT2: Quelques informations supplémentaires sur mon intention: J'ai environ 50 dialogues de taille fixe avec plusieurs centaines de contrôles de taille fixe correctement placés. Ils ont migré d'un ancien framework d'interface graphique C++ vers C #/Winforms, c'est pourquoi ils ont tous une taille fixe. Tous ont l'air bien avec 96 dpi en utilisant une police de 9.25pt. Sous l'ancienne structure, le redimensionnement à 120 dpi fonctionnait parfaitement - tous les contrôles de taille fixe étaient redimensionnés de la même manière. La semaine dernière, nous avons détecté ce comportement étrange de mise à l'échelle sous WinForm lors du passage à 120 dpi. Vous pouvez imaginer que la plupart de nos dialogues sont maintenant très mauvais en dessous de 120 dpi. Je cherche une solution qui évite une refonte complète de tous ces dialogues.

EDIT3: Pour tester ce comportement, à mon humble avis, il est judicieux de configurer un environnement Windows XP virtuel avec 120 dpi, tandis que l’environnement de développement réside sous 96 dpi (du moins, c’est ce que j’ai fait). Le changement entre 96 et 120 dpi nécessite normalement un redémarrage sous Win XP, sinon vous ne voyez pas ce qui se passe réellement.

// As requested: the source code of Form1.cs 
namespace DpiChangeTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Font f = this.textBox1.Font;
        }
    }
}

 // here the source of Form1.Designer.cs:
namespace DpiChangeTest
{
    partial class Form1
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Forms Designer generated code

        private void InitializeComponent()
        {
            System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("A list view control");
            System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("A TreeView control");
            this.button1 = new System.Windows.Forms.Button();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.listView1 = new System.Windows.Forms.ListView();
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(12, 107);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(150, 70);
            this.button1.TabIndex = 0;
            this.button1.Text = "Just a button";
            this.button1.UseVisualStyleBackColor = true;
            // 
            // groupBox1
            // 
            this.groupBox1.Location = new System.Drawing.Point(12, 12);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(150, 70);
            this.groupBox1.TabIndex = 1;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Just a groupbox";
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(180, 12);
            this.textBox1.Multiline = true;
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(150, 70);
            this.textBox1.TabIndex = 2;
            this.textBox1.Text = "A multiline text box";
            // 
            // label1
            // 
            this.label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.label1.Location = new System.Drawing.Point(179, 107);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(150, 70);
            this.label1.TabIndex = 3;
            this.label1.Text = "A label with AutoSize=False";
            // 
            // listView1
            // 
            this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
            listViewItem2});
            this.listView1.Location = new System.Drawing.Point(12, 201);
            this.listView1.Name = "listView1";
            this.listView1.Size = new System.Drawing.Size(150, 70);
            this.listView1.TabIndex = 4;
            this.listView1.UseCompatibleStateImageBehavior = false;
            // 
            // treeView1
            // 
            this.treeView1.Location = new System.Drawing.Point(179, 201);
            this.treeView1.Name = "treeView1";
            treeNode2.Name = "Knoten0";
            treeNode2.Text = "A TreeView control";
            this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
            treeNode2});
            this.treeView1.Size = new System.Drawing.Size(150, 70);
            this.treeView1.TabIndex = 5;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
            this.ClientSize = new System.Drawing.Size(343, 289);
            this.Controls.Add(this.treeView1);
            this.Controls.Add(this.listView1);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.textBox1);
            this.Controls.Add(this.button1);
            this.Controls.Add(this.groupBox1);
            this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.25F);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button button1;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.ListView listView1;
        private System.Windows.Forms.TreeView treeView1;
    }
}

 // and Main.cs
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
32
Doc Brown

J'ai finalement trouvé une réponse à ma question. En bref, l'effet ne se produit pas lorsque l'on définit la police de chaque contrôle individuellement au lieu de définir la police du formulaire contenant. De cette façon, la fonctionnalité de mise à l'échelle automatique fonctionne comme il se doit. Il est intéressant de noter que la définition de la police des contrôles modifie le comportement de la mise à l'échelle automatique, même si la propriété AutoScaleMode est définie sur AutoScaleMode.Dpi, et pas uniquement si elle est définie sur AutoScaleMode.Font

En tant que solution pragmatique, nous avons créé un petit programme en ligne de commande, qui lit les fichiers designer.cs, analyse si tous les contrôles ont une affectation de police explicite et, dans le cas contraire, ajoute cette affectation dans une copie nouvellement créée du code du concepteur. Nous avons intégré ce programme à notre suite de tests automatiques. Ainsi, chaque fois qu'un formulaire reçoit de nouveaux contrôles ou qu'un nouveau formulaire est ajouté, et que le développeur oublie d'ajouter l'attribution de police explicite, les tests échouent. Entre les deux, nous avons cette solution qui fonctionne à partir du moment où j'ai posé cette question pour la première fois (il y a 4 ans), et cela nous a évité plusieurs problèmes d'échelle depuis.

33
Doc Brown

Si ce problème frustrant avait rendu l’espacement sur la forme déconcertant, le paramètre AutoScaleMode avait été remplacé par "Aucune" et le problème avait complètement disparu.

3
Cuckcoobird

Moi aussi, j'ai trouvé le comportement étrange et j'ai partagé des maux de tête similaires en essayant de redimensionner automatiquement les contrôles (et les polices associées) dans mon application en réponse à un changement de taille ou de résolution. 

Voici un bref aperçu de ce que j'ai essayé d'appliquer à un correctif manuel: 

Tout d'abord, au lancement de l'application, je capture la résolution système de l'utilisateur en accédant à la propriété Bounds member dans Screen :: PrimaryScreen et redimensionne le formulaire par programme en fonction du pourcentage de différence par rapport au système de temps de développement. Cette nouvelle taille de formulaire est stockée et utilisée comme taille de base pour tous les ajustements futurs. De plus, en modifiant la taille du formulaire au moment de l'exécution, il appelle l'événement SizeChanged que j'ai géré pour effectuer ma mise à l'échelle. En résumé, le gestionnaire d'événements effectue les opérations suivantes:

  • Redimensionne toutes les commandes en fonction des nouveaux pourcentages de largeur et de hauteur après que l'utilisateur a choisi une taille, à la souris ou à une taille prédéfinie.

  • Change la taille de police associée à chaque contrôle par le nouveau facteur de mise à l'échelle 

Théoriquement, si les contrôles sont déplacés vers un nouvel emplacement en fonction du pourcentage de la taille du formulaire modifié, ils doivent être conservés par rapport à tous les autres contrôles. Bien sûr, chaque fois que la taille du formulaire est modifiée par l'utilisateur, ce qui précède se produit, pas seulement lors de l'exécution initiale.

Je ne suis pas sûr que cette solution soit idiote ou non, mais le temps que j'ai passé ou perdu à me battre avec AutoScale, AutoSize et Anchoring en vain a été astronomique. Je n'essaie pas de détourner votre section, Doc, je pensais juste que je partagerais mes processus de pensée avec vous et que je ressusciterais peut-être ce sujet dans l'espoir que quelqu'un ait une idée supérieure de ce cauchemar.

1
B L

N'oubliez pas que, dans la mesure où de nombreux problèmes sont liés à la taille de la police, il est important de rester cohérent avec la famille et la taille de la police . Cela signifie que vous devez définir la police sur le formulaire de base ou sur usercontrol (le cas échéant) et laissez les contrôles hériter de ce paramètre . J'ai remarqué que lorsque j'ai un formulaire avec un UserControl à l'intérieur, si j'ai sélectionné le contrôle et modifié la taille de la police, certains éléments ont été redimensionnés et d'autres non. les paramètres de police des éléments qui n'ont pas été redimensionnés ont été définis (remplacés). C’est à cette époque que j’ai réalisé ce que cela signifiait lorsque les propriétés étaient mises en surbrillance en caractères gras . Ainsi, par exemple, si vous avez une étiquette et que l’accessoire de police est en gras, cela signifie que quelqu'un l’a modifié . les accessoires qui ont été définis de cette manière pour obtenir leur police du parent, dans ce cas le formulaire contenant . Vous pouvez simplement mettre en surbrillance le texte de la propriété de police et supprimer ou cliquer avec le bouton droit de la souris sur la police et sélectionner Clear . supprimera la ligne de police du fichier du concepteur et autorisera le contrôle à hériter de la police de son parent. Cela va probablement revenir à Microsoft Sans Serif, mais si vous construisez, il récupérera la police de son parent Bien sûr, vous devez suivre une conception appropriée en utilisant des panneaux de présentation et des propriétés d'ancrage et de dock, mais je trouve qu'en général si vous effacez tout Si vous sélectionnez le contrôle utilisateur dans votre formulaire et que vous modifiez le mode automatique en Aucun, vous aurez plus de chance Aussi pour le test, si vous modifiez ensuite la taille de la police pour userontrol all les contrôles qu’il contient doivent être redimensionnés (tant qu’aucun accessoire de police n’est écrasé) Et aussi longtemps que le formulaire est conçu à l’aide des panneaux de présentation appropriés, tout devrait apparaître correctement sous d’autres résolutions . Du moins jusqu’à présent pour moi cela a fonctionné.

1
billymac

J'ai été en mesure de résoudre un problème similaire avec Compact Framework 3.5 sur VS 2008. Dans mon cas, j'ai un contrôle de tabulation, et chaque page comporte un panneau, et tous sont ancrés comme remplis à leurs parents. Chaque panneau contient plusieurs libellés et contrôles de zone de texte. L’idée est donc que lorsque l’utilisateur ouvre le SIP (panneau de saisie logicielle/clavier), la barre de défilement apparaît à droite et les contrôles de zone de texte s’agrandissent pour éviter de peindre une barre de défilement horizontale supplémentaire.

Lors de ma première tentative, le mode d'échelle automatique des formulaires était défini sur dpi, la propriété de défilement automatique de chaque page d'onglet définie sur true et la propriété de défilement automatique de chaque panneau définie sur true. Chaque étiquette était ancrée en haut, à gauche, et chaque contrôle de zone de texte était ancré à gauche, en haut et à droite. Les formulaires ont été créés dans le concepteur avec une largeur d'écran de 240 pixels et, lorsqu'ils sont exécutés sur un périphérique vga d'une largeur d'écran de 480 pixels, les zones de texte sont peintes avec un espace à droite suffisant pour 2 barres de défilement (probablement une pour la page de tabulation et un pour le panneau) bien que les barres de défilement n'apparaissent pas. Lors de l'activation du SIP, le comportement était correct, en ce sens que toutes les zones de texte étaient redimensionnées, mais il me restait une quarantaine de pixels d'espace mort entre le côté droit de la zone de texte et la barre de défilement.

J'ai pu résoudre le problème simplement en définissant la propriété autoscroll des panneaux sur false, puis en définissant sur true une heure d'exécution lorsque le SIP était activé. Cela a eu le résultat souhaité de mise à l'échelle automatique sur toute la largeur de l'écran en largeur de pixel et en redimensionnant dynamiquement les contrôles de la zone de texte lorsque la barre de défilement est activée ou désactivée.

Notons que le framework compact (3.5) n’a pas le mode Font autoscale (seulement none, dpi et inherit), mais j’ai essayé de réinitialiser la police de chaque contrôle de zone de texte comme suggéré par l’auteur original, mais cela n’a pas eu lieu. aucun effet sur la mise à l'échelle automatique des contrôles.

1
Woody0

Pour la solution acceptée lors de la modification de chaque contrôle: Avez-vous testé la modification de la police du conteneur, mais en définissant à nouveau les valeurs AutoScaleXXX?

Quelque chose comme:

 this.SuspendLayout();
 this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; // Font in this case
 this.Font = new Font(....); // set your new font
 this.ResumeLayout();

Je l'ai fait lors de l'ajout de contrôles dynamiques, mais pas pour changer de police.

0
mastro

J'ai eu ce problème aussi. En particulier, les étiquettes de lien étaient affichées avec une police trop grande et les étiquettes AutoSize étaient coupées quelque part à la fin. Changer le mode AutoScaleMode en Dpi uniquement dans le premier dialogue (principal) l'a résolu pour tous les formulaires. Merci pour le conseil.