Проблемы AutoScaleMode с измененным шрифтом по умолчанию

У меня есть некоторые проблемы со свойством Form.AutoScaleMode вместе с элементами управления фиксированного размера при использовании шрифта не по умолчанию. Я свел его к простому тестовому приложению (WinForms 2.0) только с одной формой, некоторыми элементами управления с фиксированным размером и следующими свойствами:

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);
        // ...
    }
}

В Windows XP с разрешением 96 точек на дюйм форма выглядит правильно, как в следующем примере с разрешением 96 точек на дюйм:

96dpi WinForm

При разрешении 120 т / д в Windows XP функция автоматического масштабирования Windows Forms создает следующий пример: 120 т / д:

Предыдущая WinForm масштабируется до 120 точек на дюйм

Как видите, групповые блоки, кнопки, представления списка или дерева масштабируются правильно, многострочные текстовые поля становятся слишком большими по вертикальной оси, а метка фиксированного размера неправильно масштабируется как по вертикали, так и по горизонтали. Кажется, ошибка в.NET Framework?

РЕДАКТИРОВАТЬ: некоторые подсказки: изменение шрифта применяется только к содержащей форме, элементы управления наследуют свой шрифт из формы. Я хотел бы сохранить это, если это возможно.

При использовании шрифта по умолчанию (Microsoft Sans Serif 8.25pt) эта проблема не возникает. С помощью AutoScaleMode = Font (конечно, с соответствующими AutoScaleDimensions) либо не масштабируется вообще, либо масштабируется точно так, как показано выше, в зависимости от того, когда установлен шрифт (до или после изменения AutoScaleMode). Проблема не является специфичной для шрифта Tahoma, она также возникает в Microsoft Sans Serif, 9.25pt.

И да, я уже прочитал это ТАК сообщение о проблемах с высоким DPI, но это не очень помогает мне.

Любые предложения, как это обойти?

РЕДАКТИРОВАТЬ 2: Дополнительная информация о моем намерении: у меня есть около 50 уже работающих диалогов фиксированного размера с несколькими сотнями правильно размещенных элементов управления фиксированного размера. Они были перенесены из более старой среды C++ GUI в C#/Winforms, поэтому все они имеют фиксированный размер. Все они выглядят хорошо с 96dpi, используя шрифт 9.25pt. При старой структуре масштабирование до 120 точек на дюйм работало нормально - все элементы управления фиксированного размера масштабировались одинаково в обоих измерениях. На прошлой неделе мы обнаружили странное поведение масштабирования в WinForms при переключении на 120 dpi. Вы можете себе представить, что большинство наших диалогов теперь выглядят очень плохо при 120 dpi. Я ищу решение, которое позволяет избежать полного перепроектирования всех этих диалогов.

РЕДАКТИРОВАТЬ 3: Чтобы проверить это поведение, IMHO, это хорошая идея, чтобы настроить виртуальную среду Windows XP с 120 точек на дюйм, в то время как среда разработки находится на 96 точек на дюйм (по крайней мере, это то, что я сделал). Для переключения между 96 и 120 dpi обычно требуется перезагрузка под Win XP, иначе вы не увидите, что происходит на самом деле.

// 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());
    }

8 ответов

Решение

Я наконец нашел ответ на свой вопрос. Короче говоря, эффект не возникает, когда задается шрифт каждого элемента управления отдельно, а не шрифт содержащей формы. Таким образом, функция автоматического масштабирования работает так, как и должна. Интересно, что установка шрифта элементов управления изменяет поведение автоматического масштабирования, даже если для свойства AutoScaleMode установлено значение AutoScaleMode.Dpi, а не только когда он установлен AutoScaleMode.Font,

В качестве прагматичного решения мы создали небольшую программу командной строки, которая считывает файлы designer.cs, сканирует, все ли элементы управления имеют явное назначение шрифта, и, если нет, добавляет это назначение во вновь созданную копию кода конструктора. Мы встроили эту программу в наш набор автоматических тестов, поэтому всякий раз, когда форма получает новые элементы управления или добавляется новая форма, а разработчик забывает добавить явное назначение шрифта, тесты не пройдут. Между прочим, у нас есть это решение, работающее со времени, когда я впервые задал этот вопрос (4 года назад), и с тех пор оно несколько раз спасало нас от проблем масштабирования.

Однако из-за этой расстраивающей проблемы пробел в форме стал непропорциональным, изменив AutoScaleMode на "None", и проблема полностью исчезла.

Имейте в виду, что, поскольку многие из упомянутых проблем связаны с размером шрифта, важно соответствовать семейству и размеру шрифта. Это означает установить шрифт в базовой форме или базовом пользовательском контроле (если он у вас есть) и позволить элементам управления наследовать этот параметр. Я заметил, что когда у меня есть форма с UserControl внутри, если я выбрал элемент управления и изменил размер шрифта, некоторые элементы изменили размер, а некоторые нет. Я понял, что для элементов, которые не меняются, была специально установлена ​​настройка шрифта (переопределена). Именно тогда я понял, что это значит, когда свойства выделены жирным шрифтом. Так, например, если у вас есть метка, а опора шрифта выделена жирным шрифтом, это означает, что кто-то изменил ее. Вы должны очистить все те реквизиты шрифтов, которые были установлены таким образом, чтобы они получали свой шрифт от родителя, в данном случае содержащую форму. Вы можете просто выделить текст свойства шрифта и удалить его или щелкнуть правой кнопкой мыши на шрифте и выбрать очистить. Это удалит строку шрифта из файла конструктора и позволит элементу управления наследовать шрифт от его родителя. Это, вероятно, приведет к возврату к Microsoft Sans Serif, но если вы соберете его, то подберете шрифт от его родителя. Конечно, вы должны следовать правильному дизайну с использованием панелей макета и свойств привязки и дока, но я считаю, что в общем случае, если вы удалите все перезаписи. Если вы выберете пользовательский элемент управления из своей формы и измените режим автомасштабирования на None, вам повезет. Также для тестирования, если вы затем измените размер шрифта для userontrol, все элементы в нем должны изменить размер (до тех пор, пока никакие реквизиты шрифтов не будут переопределены) И пока форма спроектирована с использованием правильных панелей макета, все должно хорошо отображаться в других разрешениях. По крайней мере, пока для меня это сработало.

Мне удалось решить аналогичную проблему с компактной платформой 3.5 на VS 2008. В моем случае у меня есть tabcontrol, и у каждой вкладки есть Panel, и все они пристыкованы к своим родителям. Каждая панель содержит несколько элементов управления надписью и текстовым полем, поэтому идея заключается в том, что когда пользователь открывает SIP (мягкая панель ввода / клавиатура), полоса прокрутки будет отображаться справа, а элементы управления текстовым полем будут масштабироваться по ширине, чтобы избежать рисования дополнительной горизонтальной полосы прокрутки.,

В моей первоначальной попытке было задано значение dpi для режима автомасштабирования форм, для свойства автопрокрутки каждой вкладки установлено значение true, а для свойства автопрокрутки каждой панели установлено значение true. Каждая метка была привязана к верху, левому краю, а каждый элемент управления текстового поля был привязан к левому, верхнему и правому краям. Формы были созданы в конструкторе с шириной экрана 240 пикселей, и при запуске на устройстве vga с шириной экрана 480 пикселей текстовые поля будут закрашены с правым пространством, достаточным для двух полос прокрутки (предположительно, одно для вкладки и один для панели), хотя полосы прокрутки не появлялись. При активации SIP поведение было корректным, все текстовые поля были изменены, но у меня все еще оставалось около 40 пикселей мертвого пространства между правой стороной текстового поля и полосой прокрутки.

Я смог решить эту проблему, просто установив для свойства автопрокрутки панелей значение false, а затем установив для истины время выполнения, когда был активирован SIP. Это привело к желаемому результату автоматического масштабирования по всей ширине экрана в ширину пикселя и динамического изменения размеров элементов управления текстовым полем, когда полоса прокрутки активирована или деактивирована.

В качестве примечания, у компактной среды (3.5) нет режима автомасштабирования шрифта (только none, dpi и наследовать), но я попытался сбросить шрифт каждого элемента управления текстового поля, как предлагал оригинальный автор, но этого не было любой эффект на автоматическое масштабирование элементов управления.

Я также обнаружил странное поведение и разделял похожие головные боли при попытке автоматически масштабировать элементы управления (и связанные с ними шрифты) в моем приложении в ответ на изменение размера или разрешения.

Для чего это стоит, вот краткое описание того, что я пытался применить ручное исправление:

Во-первых, при запуске приложения я фиксирую системное разрешение пользователя, получая доступ к члену Bounds в свойстве Screen::PrimaryScreen и изменяю программный размер формы на основе процентного различия от системы времени разработки. Этот новый размер формы сохраняется и используется в качестве базового размера для всех будущих корректировок. Кроме того, изменяя размер формы во время выполнения, он вызывает событие SizeChanged, которое я обработал для выполнения моего масштабирования. Короче говоря, обработчик событий делает следующее:

  • Изменяет размеры всех элементов управления в соответствии с новыми процентами ширины и высоты после того, как пользователь выбирает размер с помощью мыши или предварительно определенного размера.

  • Изменяет размер шрифта, связанный с каждым элементом управления, новым коэффициентом масштабирования

Теоретически, если элементы управления перемещаются в новое местоположение в зависимости от процента изменения размера формы, они должны быть сохранены относительно всех других элементов управления. Конечно, каждый раз, когда пользователь изменяет размер формы, происходит вышеупомянутое, а не только во время начального выполнения.

Я не уверен, глупо это решение или нет, но время, которое я потратил или потратил на борьбу с AutoScale, AutoSize и Anchoring безрезультатно, было астрономическим. Я не пытаюсь похитить ваш раздел, Док, я просто подумал, что поделюсь с вами своими мыслительными процессами и, возможно, возродлю эту тему в надежде, что у кого-то есть превосходное понимание этого кошмара.

У меня тоже была эта проблема. Особенно LinkLabels отображались слишком крупным шрифтом, а метки AutoSize были обрезаны где-то в конце. Изменение AutoScaleMode на Dpi только в первом диалоговом окне (Main) решило проблему для всех форм. Спасибо за чаевые.

Для принятого решения о внесении изменений для каждого элемента управления: Вы тестировали изменение шрифта контейнера, но устанавливали AutoScaleXXX опять значения?

Что-то вроде:

 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();

Я сделал это при добавлении динамически элементов управления, но не для изменения шрифтов.

У моего приложения WinForms есть Настройки размера шрифта, где шрифт может быть установлен на трех уровнях (8pt, 10pt или 12pt) на главном экране, и он должен распространяться на все подформы.

Конкретные проблемы, с которыми я столкнулся, связаны с метками, которые не имеют авторазмера (обычно используются для многострочных меток) и многострочными текстовыми полями.

Решение, которое я нашел, состояло в том, чтобы добавить следующую строку с соответствующим элементом управления в файлах Designer.cs в InitializeComponent():

this.Label1.Font = this.Font;

или же

this.MultiLineTextbox.Font = this.Font;

Кажется, это правильно настроило автоматическое масштабирование.

Другие вопросы по тегам