2008-10-09 19 views
32

Creé una aplicación para una pequeña empresa. Algunos de los empleados de la oficina no pueden ver el formulario correctamente. La razón es que tienen su configuración de DPI configurada en más de 96 ppp. ¿Alguien sabe de una forma de controlar esto?Cómo controlar la fuente DPI en la aplicación .NET WinForms

Para todos los que tienen experiencia con las aplicaciones de winforms, ¿cómo se controla el diseño del formulario para que DPI no afecte el aspecto de la aplicación?

+0

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) –

+0

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

Respuesta

16

Establezca AutoScaleMode en Heredar en todas partes (es decir, todos sus UserControls) a través de una búsqueda/reemplazo global, luego configure AutoScaleMode en Dpi en su formulario principal.

También encuentro que los contenedores de disposición funcionan mejor que los anclajes para este tipo de situación.

+0

Esto me ayudó a lidiar con una desagradable situación de escalado de DPI con un kit de herramientas de interfaz de usuario de terceros. ¡Gracias! – pelazem

63

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.

2

Sé que es algo drástico, pero considere reescribir su aplicación en WPF. Las aplicaciones WPF tienen el mismo aspecto en cada configuración de DPI.

Cuestiones relacionadas