2008-10-09 9 views
32

Я создал приложение для малого бизнеса. Некоторые сотрудники в офисе не могут правильно видеть форму. Причина в том, что у них установлен параметр DPI выше 96 точек на дюйм. Кто-нибудь знает, как это контролировать?Как управлять шрифтом DPI в .NET WinForms app

Для всех, у кого есть опыт работы с приложениями winforms, как вы управляете макетом формы, чтобы DPI не влиял на внешний вид приложения?

+0

Возможный дубликат [Как написать код WinForms, который автоматически масштабируется до системных настроек шрифта и dpi?] (Http://stackoverflow.com/questions/22735174/how-to-write-winforms-code-that-auto -scales-to-system-font-and-dpi-settings) – 2015-07-10 11:23:13

+0

Вы также проверяете этот блог на этот вопрос, я думаю, что он содержит хорошую информацию по теме: http://www.telerik.com/blogs/winforms -scaling-at-big-dpi-settings-is-it-even-possible- – checho 2016-12-02 14:16:24

ответ

16

Установите AutoScaleMode для наследования во всем мире (т.е. все ваши UserControls) с помощью глобального поиска/замены, а затем установите AutoScaleMode в Dpi в основной форме.

Я также считаю, что макеты контейнеров работают лучше, чем якоря для такого типа ситуации.

63

Предполагая, что вы не пытаетесь соблюдать шрифт пользовательского интерфейса пользователя (SystemFonts.IconTitleFont) и жестко кодируете свои формы только для одного размера шрифта (например, Tahoma 8pt, Microsoft Sans Serif 8.25pt), вы можете установить форму AutoScaleMode - ScaleMode.Dpi.

Это будет масштабировать размер формы и наиболее его дочерних элементов на коэффициент CurrentDpiSetting/96 по телефону Form.Scale(), который в свою очередь вызывает защищенный метод ScaleControl() recursivly на себя и всех дочерних элементов управления. ScaleControl увеличит положение, размер, шрифт и т. Д., Если потребуется, для нового коэффициента масштабирования.

Предупреждение: Не все элементы управления должным образом масштабируются. Например, столбцы списка не будут получать ширину по мере увеличения шрифта. В вам необходимо выполнить , чтобы выполнить дополнительное масштабирование, так как требуется . я сделать это путем переопределения метода защищен ScaleControl() и масштабирования столбцов ListView вручную:

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

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

  • рисунок 25px высокий прямоугольник
  • рисунок изображение на месте (11,56) в форме
  • растянуть рисунок значок, 48x48
  • текста чертежа с помощью Microsoft Sans Serif 8.25pt
  • получает формат 32x32 значка и начинку его в PictureBox

If Тхи В этом случае вам необходимо масштабировать эти жестко заданные значения с помощью «масштабного коэффициента масштабирования ». К сожалению, «текущий» масштабный коэффициент не предоставляется, нам нужно самому записать его. Решение состоит в том, чтобы предположить, что изначально коэффициент масштабирования равен 1,0, и каждый раз, когда вызывается ScaleControl(), измените коэффициент масштабирования на новый коэффициент.

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

Первоначально коэффициент масштабирования 1.0. Если форма затем масштабируется с помощью 1.25, коэффициент масштабирования становится:

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

Если форма затем масштабируется 0.95, новый масштабный коэффициент становится

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

Причина, по которой SizeF используется (а чем одно значение с плавающей запятой) заключается в том, что величины масштабирования могут отличаться в направлениях x и y. Если форма установлена ​​на ScaleMode.Font, форма масштабируется до нового размера шрифта. Шрифты могут иметь разные пропорции (, напримерSegoe UI более высокий шрифт, чем Tahoma). Это означает, что вы должны масштабировать значения x и y независимо.

Так что, если вы хотите разместить контроль на месте (11,56), вы должны изменить код позиционирования от:

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

в

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

То же самое относится, если вы собираетесь выбрать размер шрифта:

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

должно было стать:

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

и извлечение значок 32x32 в растровое изображение будет меняться от:

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

к

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

т.д.

Поддержка нестандартных DPI дисплеев является tax that all developers should pay. Но тот факт, что никто не хочет, - это то, почему Microsoft gave up and added to Vista the ability for the graphics card to stretch any applications that don't say they properly handle high-dpi.

2

Я знаю, что это несколько радикально, но подумайте над тем, чтобы переписать приложение в WPF. Приложения WPF имеют одинаковый вид при каждом настройке DPI.