tags:

views:

159

answers:

4

Hello everyone, I have a long string, ex: "Please help me to solve this problem." This string is so long to fit in a width of 100 pixels. I need to get a substring of this string and substring will fit in 100 pixels. Ex: substring "Please help me to sol" is fit in 100 pixels.

Please help me how to estimate a substring like this. Thanks.

My application is Win Forms and C#.

A: 

Looks like you could use TextRenderer::MeasureText().

jeffamaphone
A: 

this should work... not really tested and no optimisations, though

var g = Graphics.FromImage(someimage); // or any from hwnd etc... should use your panel/whatever
var f = new Font("YOURFONT", 12f, FontStyle.Regular, GraphicsUnit.Pixel); // replace with your vals
var yourtext = "yourtextyourtextyourtextyourtextyourtext";
while (g.MeasureString(yourtext, f).Width > 100)
    yourtext = yourtext.Remove(yourtext.Length - 2, 1);
Luke Schafer
I think it should be g.MeasureString(yourtext... instead of g.MeasureString("yourtext"...
juharr
`yourtext` should not be quoted in the while condition.
Kevin Brock
This seems like it would be very slow for strings much longer than 100 characters.
Michael Petito
I need the best solution with optimization. Thanks.
Lu Lu
@juharr and Kevin - thanks. @Michael - pixels, not characters.
Luke Schafer
@Lu Lu - are you for real? It's a (probably) working solution. There are many optimisations possible (like, guess the average width of chars and do a first-pass substring before the loop). Do what fits your needs. This is 'help me solve a problem' not 'write my program for me for free'. Also, the time to run this code is trivial regardless, even on lengthy strings.
Luke Schafer
A binary search will help you find the optimal break point quickly, even for very long strings.
Ben Voigt
@Ben - great! :)
Luke Schafer
A: 

If all you are looking for is a good estimate, you might first measure the width of a representative string to determine the average character width of your font once. A good representative might not be just the alphabet; you might look for a character frequency histogram to get a better average width.

string Representative = "abcdefghijklmnopqrstuvwxyz";
float CharacterWidth;

using(Bitmap b = new Bitmap(0, 0))
using(Graphics g = Graphics.FromImage(b))
using(Font f = /* some font definition */)
{
    CharacterWidth = g.MeasureString(Representative, f).Width / Representative.Length;
}

Then use that to estimate how many characters would fit within N pixels.

string Text = ...

int DisplayWidth = 100;

int FitLength = Math.Min(Text.Length, (int)(DisplayWidth / CharacterWidth));
string FitText = Text.Substring(0, FitLength);
Michael Petito
@abatishchev: Thanks for the edit, I didn't realize you could stack "using" statements in that way. How convenient!
Michael Petito
+1  A: 

As usual, the Win32 API has a function designed exactly for this: GetTextExtentExPoint

P/invoke declaration: http://pinvoke.net/default.aspx/gdi32/GetTextExtentExPoint.html

Ben Voigt
Actually it looks like the `System.Drawing.Graphics` class has a similar overload for `MeasureString`: http://msdn.microsoft.com/en-us/library/957webty(v=VS.100).aspx
Michael Petito
So it does. Which one of us should put that link on the pinvoke.net page (under "equivalent managed API")?
Ben Voigt
ooooooh. Nice on the measurestring overload, never noticed.
Luke Schafer
Ok, that link has been added to pinvoke.net now, to save time for the next person who thinks about using `GetTextExtentExPoint` from .NET
Ben Voigt