2009-05-07 81 views
6

Ho sottoclassato un controllo in C# WinForms e sono un testo di disegno personalizzato nel mio gestore OnPaint(). Il font è impostato su Courier New utilizzando il seguente codice nella mia forma:Perché DrawString mostra comportamenti inaspettati in C# Winforms?

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

Nel controllo stesso, la stringa viene memorizzata in realText, e io uso il seguente codice per disegnare sullo schermo:

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

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

il risultato per qualche esempio, testo casuale appare come segue: http://img219.imageshack.us/img219/1778/courier.png

Se si ingrandisce, si può vedere, per esempio, che lo spazio tra il primo 'come' è diverso da t spazio tra il secondo "come" (1 pixel contro 2 pixel). Qualcuno ha idea di cosa potrebbe causare questo, o come posso impedire che accada? C'è molta più stranezza nello spaziatura mentre disegno con caratteri diversi, ma presumo che siano tutti risultati dello stesso problema.

Grazie in anticipo per qualsiasi idea tu possa avere.

risposta

6

Ho intenzione di indovinare che è perché si sta utilizzando Graphics.DrawString() anziché TextRenderer.DrawText(). Il precedente dipinge il testo usando GDI + che è un po 'scadente e obsoleto. Quest'ultimo utilizza GDI che è più moderno (in termini di rendering del testo). Credo che questa sia la differenza rilevata dalla risposta precedente (WinForms vs. Windows).

Si potrebbe anche provare il sovraccarico di Graphics.DrawString() che prende un oggetto StringFormat e specificare StringFormat.GenericTypographic. Tuttavia, questo è davvero un problema sul problema. Se utilizzi .NET 2.0 o versioni successive, dovresti utilizzare la classe TextRenderer anziché la classe Graphics scadente per tutte le esigenze di rendering del testo. Graphics.MeasureString() e Graphics.DrawString() esistono rigorosamente per retrocompatibilità con .NET 1.0 e 1.1.

modifica: Oh sì, e il codice perde un oggetto GDI in ogni ciclo di stampa. Gli oggetti pennello sono wrapper gestiti attorno a risorse non gestite, pertanto devono essere disposti in modo esplicito.

+0

Meraviglioso, lo ha fatto senza dover ricorrere al codice win32. Grazie – Ko9

+0

L'oggetto GDI viene rilasciato quando viene eseguito il garbage collector? –

+0

No. Gli oggetti Brush e Pen in .NET sono solo wrapper gestiti attorno a risorse non gestite (il pennello o penna GDI). Quando viene eseguito il programma di raccolta dei rifiuti, elimina il wrapper .NET, ma non l'oggetto GDI sottostante. La regola generale per gli oggetti GDI è quella di avvolgerli in un blocco di utilizzo o di eliminarli esplicitamente nel finalizzatore. Dovresti essere in grado di verificarlo utilizzando Task Manager (attiva la colonna Oggetti GDI) e osserva il conteggio aumentare man mano che perdi le risorse. Il conteggio non diminuirà anche se esegui il kick del GC in azione. –

0

Devo essere onesto, ma non mi è mai successo prima. Tuttavia, provare a impostare lo SmoothingMode a Antialiasing:

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

Un'altra cosa a parte, assicurarsi che il vostro usando da ha DoubleBuffer impostata su true. Inoltre, prova a non creare un nuovo SolidBrush in ogni chiamata OnPaint ..

+0

Provato, non ha cambiato nulla tristemente. Provato tutti i tuoi suggerimenti in realtà, nessuno di loro ha aiutato: -/ – Ko9

0

La mia esperienza con il testo di pittura in controlli sottoclasse utilizzando WinForms è che il motore di rendering del testo che usa (GDI +?) Non è buono come il motore font di Windows e certamente dà risultati diversi anche quando funziona bene.

Io sono l'autore di un add-in di Visual Studio (http://entrian.com/source-search) che deve dipingere i controlli all'interno di Visual Studio e per rendere i caratteri simili ai controlli standard in Visual Studio (visualizzazione elenco, visualizzazioni di alberi, ecc.) Devo ignorare WinForms e dipingere il testo utilizzando l'API 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); 

... e famiglia.

Probabilmente non quello che volevi sentire, ma è così.