Quantcast
Viewing all articles
Browse latest Browse all 12583

ClearType + Transparency = Messy Repaint :(

Hey there,

I'm stuck here and would appreciate any help.

Below is a simple class that demonstrates a problem that I have not been able to find a nice workaround for that is acceptable to me.  Obviously my real classes are much more complex than this, but this *very simple* class shows the problem.  I can't imagine why this doesn't work, but it just doesn't.  Verified on Windows 7 64-bit, 32-bit, Windows 2008 R2 64-bit.

The problem is whether you use DrawText or DrawString, when rendering ClearType text, every time the text is rendered their appears to be some form of "round-off" that results in the new text to not reside directly over top of the old text.  As such, when implementing my own transparent controls, there is no way to avoid "cruft" form previous renders, and over time the text ecomes thicker and jagged, until at some point it reaches a "maximum" amount of cruft (almost like the font has become "bold").

Here is the code which reproduces this.  You simply drop it into a project, drop it onto a form, and then run it and click on the rendered text.  So far I have not been able to find a font that doesn't reproduce this:

using System; using System.Drawing; using System.Drawing.Text; using System.Windows.Forms; namespace Test
{ public class TestLabel : Control { public TestLabel() { this.Click += new System.EventHandler(this.OnClick); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT return cp; } } protected override void OnPaintBackground(PaintEventArgs pevent) { //do not allow the background to be painted } protected override void OnPaint(PaintEventArgs e) { // the problem is only evident with ClearType hint. AntiAlias works fine (either one); e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; //e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; // either GDI (DrawText or GDI+ (DrawString) will cause the re-paint problem on click //TextRenderer.DrawText(e.Graphics, Text, Font, new Point(0, 0), ForeColor); e.Graphics.DrawString(Text, Font, Brushes.Black, new Point(0, 0)); } private void OnClick(object sender, EventArgs e) { // invalidating the parent would avoid the problem, but then it will flicker, and is unusable for mouse enter/leave/move Invalidate(); } } }

The same problem is visible with GDI or GDI+.  Changing the hint to either AntiAlias fixes it for both GDI and GDI+.

OK so the reason I want to do this is I am writing a transparent control library: labels, checkboxes, radio buttons, textbox, etc.  I pretty much have it all working, except for this rendering text bug (rendering images is perfect).

The reason I'm stuck is I can't find an acceptable alternative:

a) live with this (unacceptable visually)

b) use antialiasing instead of cleartype (unacceptable visually)

c) invalidate the parent rect under the control and repaint the background for every repaint (unacceptable flashing especially for mouse enter / mouse leave)

d) use a system Label common control for all text rendering (unacceptable for some of my controls, for example I have multicolor text which Label does not support).

So in short I haven't been able to find an acceptable solution.  Help!?!

There MUST be a way to do this as the standard Label control supports transparency and does this just fine.  I beginning to wonder if that control caches an image of it's first render and keeps re-using it?  While that would "work", it isn't exactly transparent.  I want my library to be able to work fine with and render correctly regardless of what the parent container is doing paint-wise.  If the parent simply invalidates itself and all children after painting a few new lines or something, the control would need to know that the background changed and then on next repaint redo the image.  Again, in theory this could be made to work with BackgroundChanged event, but I still feel this is a hack as it should just work as is, should it not?

Before you sugest it, WPF is out of the question, I need to target 2.0.

Again, the code works great for either AntiAliased.  It is ClearType only that causes the problem.  It sounds like a bug or quirk in ClearType implementation, one that MS folks have worked around for Label control.

One last note: when testing this make sure you have system ClearType enabled, and that you aren't testing over remote desktop or anything like that, as in those scenarios the hint will be ignored and you'll end up with something other than ClearType anyway, and the problem won't be visible.

Any help would be greatly appreciated.  Is the only / best solution to use a cached image that I render once and keep re-using it?  I will do that if there is no other solution, but it's a hack.

Thanks in advance,
Ryan



Viewing all articles
Browse latest Browse all 12583

Trending Articles