0

I have a Listbox in a SplitterPanel. I have overriden it's MeasureItem() and DrawItem() methods.

What I want to do is, depending on Listbox.Width, return either the entire string or a shortened version of it, like "Dance toni...".

I've browsed SO and found two questions that pertain to my problem. One of the problems is measuring the width of the text, which I am doing with e.Graphics.MeasureString() in DrawItem().

Summary - I have the width of a listbox, and the width, in pixels, of a string. If the string is shorter than the width of a listbox, I want to display the string in entirety. However, if it's longer, I would like to return a version like "Hello every..." that would fit in within the width of the listbox.

So far I have:

        private string FitText(string s)
    {
        int width = (TextRenderer.MeasureText(s, titleFont)).Width;
        if (width <= mailList.Width)
        {
            return s;
        }
        else if (width > mailList.Width)
        {
            // What goes here?
        }
    }

I'm pretty sure it's just simple math, but I still can't figure it out.

Dominic K
  • 6,975
  • 11
  • 53
  • 62
  • 1
    possible duplicate of [indicate truncation in ToolTipStatusLabel automatically](http://stackoverflow.com/questions/2903172/indicate-truncation-in-tooltipstatuslabel-automatically) – Hans Passant Jul 12 '11 at 20:33

3 Answers3

1

http://msdn.microsoft.com/en-us/library/aa904308%28v=vs.71%29.aspx

    string ts = s;
    while((TextRenderer.MeasureText(ts, titleFont)).Width > mailList.Width + (TextRenderer.MeasureText("...", titleFont)).Width)
{
ts = ts.SubString(0,ts.Length-1);
}
return ts + "..."
rlemon
  • 17,518
  • 14
  • 92
  • 123
  • this will simply truncate the string at the maximum width, if you would like to end on a real word you would need to implement something along the lines that TheCapn showed you. – rlemon Jul 12 '11 at 20:27
  • So what happens when you have a ListBox with `Width` = 50 and a 15-character string? (Hint: the value of `Width` is in pixels) :P – Dan J Jul 12 '11 at 20:27
  • Good update. But you're going to have to replace that `+ 3` with `+ TextRenderer.MeasureText("...", titleFont).Width`, or something, because I assure you an ellipsis is wider than 3 pixels. – Dan J Jul 12 '11 at 20:39
  • Looking over the code, it seems to work, but 1)It always leaves "..." (though that's an easy fix) and it still seems to get text chopped off. – Dominic K Jul 12 '11 at 20:44
1

Here's the pseudocode I'd use...

1) Shorten the string in some form (remove the last character/word)
2) Retest the length against width
3) Insert of valid repeat if not
4) If string is too short use some default form

String s = "A long string that you're trying to fit into the button."
while (width > mailList.Width) {
   s = s.SubString(0,s.lastIndexOf(" ")-1); //Change this to whatever you'd want to shorten the string by
  width = (TextRenderer.MeasureText(s, titleFont)).Width; 
  if (width < 5) { //Some value indicating it's too short
    s = "Button...";
    break;
  }
}

return s;
Grambot
  • 4,370
  • 5
  • 28
  • 43
  • Am I correct in saying that width is initially the length of the string in pixels? And that if (width < Listbox.Width), I should return `s + "...";`? – Dominic K Jul 12 '11 at 20:38
  • What issues are you having? Unforunately the code was a mental exercise of mine and untested. I'm happy to try and improve it for you. – Grambot Jul 12 '11 at 21:27
  • When I finish resizing and call Update() on my control, it does not display the ... when required, it just overflows like without the code. – Dominic K Jul 12 '11 at 21:43
1

i think you would need check if it fits, if so, return the whole string, otherwise modify your code to run a loop that keeps measuring the size of s minus one more character and plus the ellipsis, until it fits or until there are no more characters left, and then return that, or just the ellipsis otherwise.

string EllipsisString = "..."; // you could also just set this as the unicode ellipsis char if that displays properly

private string FitText(string s)
{
    bool WidthFound = true;
    string TestString = s;
    string StringToReturn = s;

    int width = (TextRenderer.MeasureText(s, titleFont)).Width;

    if (width > mailList.Width)
    {
        WidthFound = false;

        for (int i=1; i < s.Length; ++i)
        {
           TestString = s.Substring(0, s.Length - i) + EllipsisString;
           width = (TextRenderer.MeasureText(TestString, titleFont)).Width;

           if (width <= mailList.Width)
           {
              StringToReturn = TestString;
              WidthFound = true;
              break;
           }
        }
    }

    if (WidthFound)
        return StringToReturn;
    else
        return EllipsisString;
}

[edits: too many to name]

shelleybutterfly
  • 3,216
  • 15
  • 32
  • seesh, i edited a lot of times to correct not-so-smart errors; be sure to re-check it if you are validating :) – shelleybutterfly Jul 12 '11 at 20:32
  • What is the value of Length in ` TestString = s.Substring(0, Length - i);`? – Dominic K Jul 12 '11 at 20:32
  • wow, sorry for all the flails, had to change to test (width <= mailList.Width) in the loop instad of (width > mailList.Width) – shelleybutterfly Jul 12 '11 at 20:36
  • repeating to self 100x: "never ever post code you haven't tested" :) – shelleybutterfly Jul 12 '11 at 20:38
  • Still testing this, but I'm assuming Ellipsis is equal to EllipsisString :) – Dominic K Jul 12 '11 at 20:39
  • sigh, indeed. :) still repeating to myself... will edit to fix. – shelleybutterfly Jul 12 '11 at 20:43
  • This seems to work reasonably well, but this seems to happen: http://i.imgur.com/0nO9z.png – Dominic K Jul 12 '11 at 20:46
  • Actually, this does work. I just had to add some padding. I've accepted this answer because it's the only one that seems to work accurately, including resizing. Thanks a bunch! – Dominic K Jul 12 '11 at 20:57
  • if i had to guess i would say the scrollbar's width is not taken into account and you're going to need to either ["right way"] somehow figure out whether the scrollbar is displayed and measure it and then subtract that off of the width you test against, or ["quick-but-not-totally-reliable" way] just subtract a fudge factor that accounts for the possible width of the scrollbar and test the heck out of it :) – shelleybutterfly Jul 12 '11 at 20:58
  • The problem actually was (my fault I didn't say) that I had added padding to the text in the listbox before hand. I just subtracted that in the Width of the listbox ;) – Dominic K Jul 12 '11 at 21:04