Suponiendo que no intenta respetar la opción de fuente de IU del usuario (SystemFonts.IconTitleFont) y codifica sus formularios para un solo tamaño de fuente (p. Ej., Tahoma 8pt, Microsoft Sans Serif 8.25pt), puede configurar el formulario. AutoScaleMode
a ScaleMode.Dpi
.
Esto ajustará el tamaño de la forma y la mayoría de que los controles secundarios por el factor CurrentDpiSetting/96
llamando Form.Scale()
, que a su vez llama al método protegido ScaleControl()
recursivamente sobre sí mismo y todos los controles secundarios. ScaleControl
aumentará la posición, el tamaño, la fuente, etc. del control según sea necesario para el nuevo factor de escala.
Advertencia: No todos los controles se escalan correctamente. Las columnas de una vista de lista , por ejemplo, no obtendrán más amplia a medida que la fuente aumente. En para manejar eso, tendrá que realizar manualmente una escala adicional como se requiere . puedo hacer esto reemplazando el método protegida ScaleControl()
y escalar las columnas de vista de lista manualmente:
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);
}
}
}
Esto es todo muy bien si sólo está utilizando controles. Pero si alguna vez usa tamaños de píxel codificados, necesitará escalar el ancho y el largo de sus píxeles según el factor de escala actual del formulario. Algunos ejemplos de situaciones que podrían haber tamaños de pixel no modificable:
- dibujo de un rectángulo de 25 píxeles de alto
- dibujo de una imagen en la posición (11,56) en el formulario
- tramo de dibujo en un icono para 48x48
- texto dibujo utilizando Microsoft Sans Serif 8.25pt
- conseguir el formato 32x32 de un icono y el relleno en un cuadro de imagen
Si Thi s es el caso, necesitará escalar esos valores codificados mediante el "factor de escala actual". Desafortunadamente, no se proporciona el factor de escala "actual", necesitamos registrarlo nosotros mismos. La solución es suponer que inicialmente el factor de escala es 1.0 y cada vez que se llama ScaleControl()
, modifique el factor de escala en ejecución por el nuevo factor.
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);
}
}
Inicialmente, el factor de escala es 1.0
. Si la forma es entonces escalado por 1.25
, el factor de escala se convierte en:
1.00 * 1.25 = 1.25 //scaling current factor by 125%
Si el formulario se escala por 0.95
, el nuevo factor de escala se convierte en
1.25 * 0.95 = 1.1875 //scaling current factor by 95%
La razón se utiliza un SizeF
(en vez que un solo valor de coma flotante) es que las cantidades de escala pueden ser diferentes en las direcciones xey. Si se configura un formulario en ScaleMode.Font
, el formulario se escala al nuevo tamaño de fuente. Las fuentes pueden tener diferentes relaciones de aspecto (, por ejemplo,Segoe UI es una fuente más alta que Tahoma). Esto significa que debe escalar valores xey de forma independiente.
Así que si quería colocar un control en el lugar (11,56)
, que tendría que cambiar su código de posicionamiento a partir de:
Point pt = new Point(11, 56);
control1.Location = pt;
a
Point pt = new Point(
(int)Math.Round(11.0*this.scaleFactor.Width),
(int)Math.Round(56.0*this.scaleFactor.Height));
control1.Location = pt;
Lo mismo se aplica si se va a recoger un tamaño de fuente:
Font f = new Font("Segoe UI", 8, GraphicsUnit.Point);
tendría que ser:
Font f = new Font("Segoe UI", 8.0*this.scaleFactor.Width, GraphicsUnit.Point);
y extraer un icono de 32x32 a un mapa de bits cambiaría de:
Image i = new Icon(someIcon, new Size(32, 32)).ToBitmap();
a
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.
Apoyo pantallas DPI no estándar es una tax that all developers should pay. Pero el hecho de que nadie quiere es por qué 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.
posible duplicado de [¿Cómo escribir el código de WinForms que se escanea automáticamente a la configuración de fuente del sistema y los ppp?] (Http://stackoverflow.com/questions/22735174/how-to-write-winforms-code-that-auto -escalas-a-sistema-fuente-y-ppp-configuraciones) –
Marque también este blog sobre el asunto, creo que proporciona buena información sobre el tema: http://www.telerik.com/blogs/winforms -scaling-at-large-dpi-settings-is-it-even-possible- – checho