2009-05-07 28 views
6

He subclasificado un control en C# WinForms, y estoy escribiendo texto personalizado en mi controlador OnPaint(). La fuente se establece en Courier New usando el siguiente código en mi forma:¿Por qué DrawString muestra un comportamiento inesperado en C# Winforms?

FontFamily family = new FontFamily("Courier New"); 
this.myControl.Font = new Font(family, 10); 

En el control de sí misma, la cadena se almacena en realText, y utilizo el siguiente código para llamar a la pantalla:

protected override void OnPaint(PaintEventArgs e) 
{ 
    base.OnPaint(e); 

    e.Graphics.DrawString(realText, Font, new SolidBrush(ForeColor), ClientRectangle); 
} 

el resultado de algún ejemplo de texto al azar se ve de la siguiente manera: http://img219.imageshack.us/img219/1778/courier.png

Si se acerca, se puede ver, por ejemplo, que el espacio entre la primera 'como' es diferente de t El espacio entre el segundo "como" (1 píxel frente a 2 píxeles). ¿Alguien tiene alguna idea de lo que podría estar causando esto o cómo puedo evitar que ocurra? Hay muchas más rarezas similares en el espaciado al dibujar con diferentes fuentes, pero supongo que son todos los resultados del mismo problema.

Gracias de antemano por cualquier idea que pueda tener.

Respuesta

6

Voy a adivinar que es porque estás usando Graphics.DrawString() en lugar de TextRenderer.DrawText(). El primero pinta texto usando GDI +, que es una especie de mierda y obsoleto. Este último usa GDI que es más moderno (en términos de representación de texto). Creo que esta es la diferencia notada por la respuesta anterior (WinForms vs. Windows).

También puede probar la sobrecarga de Graphics.DrawString() que toma un objeto StringFormat y especifique StringFormat.GenericTypographic. Sin embargo, esto es realmente un hack alrededor del problema. Si usa .NET 2.0 o posterior, debe utilizar la clase TextRenderer en lugar de la clase Graphics para todas sus necesidades de representación de texto. Graphics.MeasureString() y Graphics.DrawString() existen estrictamente para compatibilidad con versiones anteriores de .NET 1.0 y 1.1.

editar: Ah sí, y su código gotea un objeto GDI en cada ciclo de pintura. Los objetos de pincel son envoltorios administrados alrededor de recursos no administrados, por lo que deben eliminarse explícitamente.

+0

Maravilloso, eso lo hizo sin tener que recurrir al código win32. Gracias – Ko9

+0

¿Se libera el objeto GDI cuando se ejecuta el recolector de elementos no utilizados? –

+0

No. Los objetos Brush y Pen en .NET solo son envoltorios gestionados alrededor de recursos no administrados (el pincel o bolígrafo GDI). Cuando se ejecuta el recolector de elementos no utilizados se elimina el contenedor .NET, pero no el objeto GDI subyacente. La regla general para los objetos GDI es envolverlos en un bloque de uso o disponerlos explícitamente en el finalizador. Debería poder verificar esto utilizando el Administrador de tareas (activar la columna Objetos de GDI) y ver cómo aumenta el recuento a medida que se filtran los recursos. El recuento no disminuirá incluso si se inicia el GC en acción. –

0

Tengo que ser honesto, pero esto nunca me había sucedido antes. Sin embargo, intente configurar el SmoothingMode a Antialiasing:

e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; 

Otra cosa a un lado, asegurarse de que el uso de su DoubleBuffer ha establecido en true. Además, trate de no crear un nuevo SolidBrush en cada llamada OnPaint ..

+0

Lo intenté, no cambié nada tristemente. Intenté todas sus sugerencias en realidad, ninguna de ellas me ayudó: -/ – Ko9

0

Mi experiencia con la pintura de texto en controles subclasificados utilizando WinForms es que el motor de representación de texto que utiliza (GDI +?) No es tan bueno como el propio motor de fuente de Windows y ciertamente da resultados diferentes incluso cuando funciona bien.

Soy el autor de un complemento de Visual Studio (http://entrian.com/source-search) que necesita para pintar controles dentro de Visual Studio, y para hacer que las fuentes tengan el mismo aspecto que los controles estándar en Visual Studio (listviews, treeviews, etc.) tengo que pasar por alto WinForms y pintar el texto usando la API de Win32:

[DllImport("gdi32.dll")] 
public static extern bool ExtTextOut(IntPtr hdc, int X, int Y, 
    uint fuOptions, [In] ref RECT lprc, string lpString, uint cbCount, 
    [In] int[] lpDx); 

... y la familia.

Probablemente no sea lo que quería escuchar, pero ahí está.

Cuestiones relacionadas