Ответ 1
Предполагая, что вы не пытаетесь соблюдать выбор шрифта пользовательского интерфейса пользователя (SystemFonts.IconTitleFont) и жестко кодируете свои формы только для одного размера шрифта (например, Tahoma 8pt, Microsoft Sans Serif 8.25pt), вы можете установить свою форму AutoScaleMode
до ScaleMode.Dpi
.
Это уменьшит размер формы и большинство ее дочерних элементов управления с помощью фактора CurrentDpiSetting / 96
, вызвав Form.Scale()
, который поочередно вызывает рекурсивно защищенный метод ScaleControl()
сам по себе и все дочерние элементы управления. ScaleControl
будет увеличивать управляющую позицию, размер, шрифт и т.д. по мере необходимости для нового коэффициента масштабирования.
Предупреждение: Не все элементы управления должным образом масштабируются. Столбцы listview, например, не получит шире по мере увеличения шрифта. В чтобы справиться с тем, что вам придется вручную выполните дополнительное масштабирование как обязательный. я делаю это, переопределяя защищенный метод
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
Если это так, вам нужно масштабировать эти жестко заданные значения с помощью "текущего масштабного коэффициента". К сожалению, "текущий" масштабный коэффициент не предоставляется, нам нужно самому записать его. Решение состоит в том, чтобы предположить, что изначально коэффициент масштабирования равен 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 - это налог который должны заплатить все разработчики. Но тот факт, что никто не хочет, - это почему Microsoft отказалась и добавила в Vista возможность для графической карты растянуть любые приложения, которые не говорят, что они правильно обрабатывают высокие -dpi.