[.net] [C#] Drawing a string in different colors?

Started by
14 comments, last by Zipster 14 years, 8 months ago
I've been trying to draw a string in multiple colors for the past couple of hours now and I haven't had much luck. Basically, I want to take the existing functionality I have with Graphics.DrawString and add the ability to change the color sub-strings to be different than the brush color, i.e. change all instances of "foo" to red and "blah" to blue. That's pretty much it. I thought this would be simple enough. First render the string using the base color. Then use Graphics.MeasureCharacterRanges to find all the sub-string regions. Iterate the regions, and re-render all the sub-strings in their special colors. Since I'm not changing any font sizes, styles, layouts, etc., they would align perfectly with the full string and I'd be done. Well hours later and I'm still fiddling with all the parameters for DrawString and MeasureCharacterRanges (mainly string formats) trying to get the damn sub-strings to align. I've messed with every setting I could find, in all manner of combinations. Either the regions are off horizontally by a few pixels, or they're too small and clip/wrap the text, or they're completely off the bitmap altogether. And that's assuming that the sub-strings don't wrap! I haven't even attempted to code that case yet since I get even get the basics working. Has anyone ever attempted this before? Hours on Google and nothing I've seen has either been relevant or worked. For now I've hacked in some offsetting code because it's always off by 7 pixels to the right, but that's a horrible solution.
Advertisement
I played around with some code and ran into the same issue and then found this article.

My guess is that the stringformat and textformatflag incompatibility is messing things up.

I haven't got the time to test it but de example code (download at the top of the article) might be of use to you.
Oi, try using System.Windows.Forms.TextRenderer. It has DrawText and MeasureText functions that have been accurate for my purposes. IIRC, you may have to fiddle with the TextFormatFlags a wee bit, but TextFormatFlags.TextBoxControl should work nicely.

I'm thinking I've read somewhere that the reason MeasureString and DrawString don't match up is 'cause it uses GDI+, whereas TextRenderer uses GDI. Something about how GDI+ handles pixel/sub-pixel I'm guessing?

Hope this helps!

[Edit: Blergh. Didn't bother to read the article linked in the post above. [disturbed]]

[Edited by - nerd_boy on August 16, 2009 1:06:00 PM]
Thanks for the replies, I wasn't even aware that the Forms namespace had text rendering. The problem with MeasureText though is that it measures text in "local space", so to speak. MeasureCharacterRanges allows me to pass in a full string with bounding rectangle, and then ask for a sub-rectangle bounding a particular range of characters (i.e. characters 23-29 in "global space"). I can then (ideally) just render that range of characters in a different color, using the returned sub-rectangle.

If I were to use MeasureText, I would need to split the string using the colored keywords as delimiters, and then render it in pieces. It could work, but it would take a lot more effort than what I have now. I would also have to implement word wrap functionality myself, for instance, but all things considered I believe the extra work is worth finding a robust solution.

Thanks again! I'll let you know how it goes [smile]
Using anything other than MeasureCharacterRanges gave me hideously wrong results when I did this. You might try looking at the owner draw code in this code to see how I handle it. The results look like this:

Cleaned up version of dotTrace style visualizer

[Edited by - Promit on August 17, 2009 12:56:54 PM]
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Promit, the link to your code is broken. DotTracestyle.cs with a capital 'S' ;)
Quote:Since I'm not changing any font sizes, styles, layouts, etc., they would align perfectly with the full string and I'd be done.
You'd need to clear underneath the subranges first, as the antialiasing will cause problems otherwise.

[Website] [+++ Divide By Cucumber Error. Please Reinstall Universe And Reboot +++]

MeasureCharacterRanges and DrawString will not return the same results for substrings as for the whole string. Let me repeat: what you are trying to do will *not* work.

It's a known limitation of GDI+ text rendering. One potential solution is to use TextRenderer.MeasureText and TextRenderer.DrawText which rely on GDI instead. However, you will have to turn off text antialiasing for this to work, which is not advisable (edit: or clear the subranges, as benryves suggested - not always possible).

Solution: split your text into text runs (one run per [font, style, size, color] combination) and draw the runs sequentially.

Better solution: use a RichTextControl which offers this functionality out of the box.

Another solution: use a WebBrowser Control and format your text using HTML.

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

Quote:Original post by ernow
Promit, the link to your code is broken. DotTracestyle.cs with a capital 'S' ;)
o_O

I can't fix the link. Every time I change it, the S snaps back to lowercase. It happens without the link too:
http://slimtune.googlecode.com/svn/trunk/SlimTuneUI/DotTracestyle.cs
style.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Quote:Original post by Promit
Quote:Original post by ernow
Promit, the link to your code is broken. DotTracestyle.cs with a capital 'S' ;)
o_O

I can't fix the link. Every time I change it, the S snaps back to lowercase. It happens without the link too:
http://slimtune.googlecode.com/svn/trunk/SlimTuneUI/DotTracestyle.cs
style.

You can get around it using HTML entities.

http://slimtune.googlecode.com/svn/trunk/SlimTuneUI/DotTraceStyle.cs =>
http://slimtune.googlecode.com/svn/trunk/SlimTuneUI/DotTraceStyle.cs

This topic is closed to new replies.

Advertisement