Efficiently Computing Text Widths
I need to compute the width of a column with many rows (column AutoSize feature). Using Canvas.TextWidth
is far too slow.
Current solution: My current solution uses a text measurer class that builds a lookup table for a fixed alphabet once and then computes the width of a given string very fast by adding up character widths retrieved from the lookup table. For characters not contained in the lookup table, the average character width is used (also computed once).
Problem: This works well for European languages but not for Asian lan开发者_StackOverflow中文版guages.
Question: What's the best way to tackle this problem? How can such an AutoSize feature be realized without the relatively slow Canvas
functions and without depending on a specific alphabet?
Thanks for any help.
You said you want to get the maximum text width for a column. Can't you, say, take only the 4 or 5 longest strings and get their widths? That way you won't have to find the width for all items and can save quite some time.
Or you use your cache to find the rough length of the strings and then refine that by getting the actual width for the top 4 or 5 items you found.
I don't think it matters a lot whether you use Canvas.TextWidth or GetTextExtentPoint32. Just use one of these to get the exact widths, after you used one of the methods above to guesstimate the longest/widest strings.
To those who think this doesn't work
If the poster of the original question thinks it could work, I have no reason to think it won't. He knows best what kind of strings can be in the columns he has.
But that is not my main argument. He already wrote that he does a preliminary textwidth by adding the predetermined individual widths of the characters. That does not take into account any kerning. Well, kerning can only make a string narrower, so it still makes sense to check only the top 4 or 5 items for the exact width. The biggest problem that can occur is that the column could be a few pixels too wide, no more. But it will be a lot faster than using TextWidth or GetTextExtentPoint32 or similar functions on each entry (assuming more than 5 entries), and that is what the original poster wanted. I suggest that those who don't believe me simply try it out.
As for using the pure string length: even that is probably good enough. Yes, 'WWW' is probably wider than '!!!!!', but the original poster will probably know best wat kind of string material he has, and if it is feasible. '!!!!!' or 'WWW' are not the usual entries one expects. Especially if you consider that not only one single string is checked, but the longest 4 or 5 strings (or whatever number turns out to be optimal). It is very unlikely that the widest string is not among them. But the original poster can tell if that is possible or feasible. He seems to think it is.
So stop the downvoting and try it out for yourself.
I'm afraid you have to use Canvas.TextWidth
, or your implementation will be imprecise. The width of text depends on the font kerning, where different character sequences may have different widths (not just the total of individual character widths).
Me, I cut out the middle-man and use the Windows API directly. Specifically, I use GetTextExtentPoint32 with the .Handle of the Canvas. There's nothing you can do to be faster, other than caching results in some way, and frankly you'll just add overhead.
精彩评论