2009-05-07 12 views
6

Podklasowałem kontrolkę w WinForm C# i mam niestandardowy tekst do rysowania w mojej procedurze obsługi OnPaint(). Czcionka jest ustawiony na Courier New stosując następujący kod w moim formularzu:Dlaczego DrawString wykazuje nieoczekiwane zachowanie w WinFormach C#?

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

w samej kontroli, ciąg jest przechowywany w realText i używam poniższy kod, żeby wyciągnąć go na ekranie:

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

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

wynik jakiegoś losowego przykład tekst wygląda następująco: http://img219.imageshack.us/img219/1778/courier.png

Jeśli powiększać, można zobaczyć na przykład, że przestrzeń pomiędzy pierwszym „jako” jest inny niż t ma przestrzeń między drugim "as" (1 piksel w stosunku do 2 pikseli). Czy ktokolwiek ma pojęcie, co może być przyczyną tego lub jak mogę temu zapobiec? Jest o wiele więcej podobnych dziwactw w odstępach, jak rysuję różnymi czcionkami, ale zakładam, że wszystkie są wynikiem tego samego problemu.

Z góry dziękuję za wszelkie pomysły.

Odpowiedz

6

Zgaduję, że to dlatego, że używasz Graphics.DrawString() zamiast TextRenderer.DrawText(). Ten pierwszy maluje tekst za pomocą GDI +, który jest w pewnym sensie bzdurny i przestarzały. Ten drugi używa GDI, który jest bardziej nowoczesny (pod względem renderowania tekstu). Wierzę, że jest to różnica zauważona przez poprzednią odpowiedź (WinForms vs. Windows).

Możesz również spróbować przeciążenia Graphics.DrawString(), które pobiera obiekt StringFormat i określić StringFormat.GenericTypographic. Jednak jest to naprawdę trochę hack wokół problemu. Jeśli używasz środowiska .NET 2.0 lub nowszego, powinieneś używać klasy TextRenderer zamiast klasycznej klasy Graphics dla wszystkich potrzeb związanych z renderowaniem tekstu. Graphics.MeasureString() i Graphics.DrawString() istnieją wyłącznie w celu zapewnienia zgodności wstecznej z .NET 1.0 i 1.1.

edytuj: O tak, a twój kod wycieka obiekt GDI na każdym cyklu malowania. Obiekty pędzla to zarządzane owijki wokół niezarządzanych zasobów, dlatego muszą być jawnie usuwane.

+0

Cudownie, zrobił to bez konieczności uciekania się do kodu win32. Dzięki – Ko9

+0

Czy obiekt GDI zostanie zwolniony po uruchomieniu Kosza ze śmieciami? –

+0

Nie. Obiekty pędzla i pióra w programie .NET to po prostu zarządzane opakowania wokół niezarządzanych zasobów (pędzla lub pióra GDI). Kiedy uruchamia się garbage collector, pozbywa się wrappera .NET, ale nie bazowego obiektu GDI. Ogólna zasada dla obiektów GDI polega na zawijaniu ich w blokach lub jawnym ich usuwaniu w finalizatorze. Powinieneś być w stanie to zweryfikować za pomocą Menedżera zadań (włączyć kolumnę Obiekty GDI) i obserwować wzrost liczby podczas wycieku zasobów. Liczba nie spadnie, nawet jeśli włączysz GC do działania. –

0

Muszę być szczery, ale nigdy mi się to nie zdarzyło. Jednak próby ustawiania SmoothingMode do antyaliasingu:

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

Inną rzeczą na bok, upewnij się, ze używasz ma DoubleBuffer wartość true. Spróbuj także nie tworzyć nowej SolidBrush w każdym wywołaniu OnPaint.

+0

Wypróbowałem, nic nie zmieniłem ze smutkiem. Wypróbowałem wszystkie twoje sugestie, żadna z nich nie pomogła: -/ – Ko9

0

Moje doświadczenie w malowaniu tekstu na podklasowe elementy sterujące za pomocą WinForms jest takie, że silnik renderujący tekst (GDI +?) Nie jest tak dobry jak własny silnik czcionek systemu Windows i na pewno daje różne wyniki, nawet jeśli działa dobrze.

Jestem autorem dodatku Visual Studio (http://entrian.com/source-search), który musi malować kontrolki w Visual Studio, i aby czcionki wyglądały tak samo, jak standardowe formanty w Visual Studio (widoki list, widok drzewa, itp.) mam na ominięcie WinForms i malować tekst za pomocą 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); 

... i rodzinę.

Prawdopodobnie nie to, co chciałeś usłyszeć, ale jest.