Text size calculation problem.

I'm working on a RichTextBox that allows for specific portions of the text to have a ToolTip.  So far everything works, but there are two small problems.

I'm accomplishing this by handling the MouseMove event and using GetCharIndexFromPosition to figure out where the cursor is.  This works fine, except the function returns the character nearest the cursor at all times.  So if a ToolTip region of text is at the edge of a line, the ToolTip is displayed even when the mouse is over blank space.  The same thing happens if a ToolTip region is on the last line of the box and the cursor is over the blank region underneath.

The solution to this seemed pretty straightforward at first.  I'd use the Font.GetHeight property and MeasureString to calculate the bounds of the line the character belonged to, and if the cursor is within the region display the ToolTip.  However, I've played with this for several hours now, and I cannot seem to make the calculations right.  Using 16 point MS Sans Serif (actually it gets rounded to 15.75 points), the value returned by Font.GetHeight is off by a tiny bit, and the error is amplified more each line.  I discovered this first through outputting the current line index, the predicted location of the next line, and the current Y coordinate to the console.  So I decided to get Windows to draw me a picture; I drew lines where the upper bounds of each line should be, and this screenshot shows the problem:

Notice how each line is more and more outside of the calculated lines.  The code I used to calculate the lines is below (messy because I'm still hacking at it):


        Dim g As Graphics = RichTextBox1.CreateGraphics()
        Dim p As Pen = New Pen(Color.Green)

        For index As Integer = 1 To 11
            g.DrawLine(p, 0, index * RichTextBox1.Font.GetHeight(g), RichTextBox1.Width, index * RichTextBox1.Font.GetHeight(g))


Now's where it gets weird.  If I set the text to 8.25 point or 20 point, the lines are perfect.  If I use GetHeight as the measurement for successive DrawStrings, the text is drawn perfectly no matter what font size I choose.  The problem has to be something stupid I'm overlooking.  Can anyone tell me how to accurately get this value for an arbitrary font size?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Hi GohdanTheGoblin,

The problem is both the GetHeight, and the measurestring return a single, but the text in a richtextbox is positioned by integers (roundedup), also to get the correct height of the string in the RTB use StringFormat.GenericTypographic instead of the default StringFormat.GenericDefault, also the first line doesn't start at Y position 0 but at Y position 1

this will demonstrated it (this will draw the lines perfectly whatever the font)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim g As Graphics = RichTextBox1.CreateGraphics()
        Dim p As Pen = New Pen(Color.Green)
        Dim sf As StringFormat = New StringFormat(StringFormat.GenericTypographic)
        Dim stringHeight As Single = Math.Round(g.MeasureString(RichTextBox1.Lines(0), RichTextBox1.Font, RichTextBox1.Width, sf).Height() + 1.5)
        g.DrawLine(p, CInt(0), CInt(stringHeight) + 1, CInt(RichTextBox1.Width), CInt(stringHeight) + 1)

        For index As Integer = 2 To RichTextBox1.Lines.GetUpperBound(0)
            g.DrawLine(p, CInt(0), CInt(index * stringHeight) + 1, CInt(RichTextBox1.Width), CInt(index * stringHeight) + 1)
    End Sub

hopes this helps, if you need more help just let me know

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
GohdanTheMoblinAuthor Commented:
Yes, this works perfectly!  I'm not exactly sure about why some of it works, but I think a little research into GenericTypographic could do me some good.

The only real question I have, not really part of the main question but about your code, is why the extra 1.5?  I'm assuming it's a padding "magic number" that 's not documented (like the little bit you have to add to a ListViewColumn to account for the border), but what exactly is it for?
Well actually it is 1 + 0.5, 1 is for the space between the lines and the 0.5 is for rounding up
GohdanTheMoblinAuthor Commented:
Oh, I understand; there's a little bit of space between the lines in addition to the value returned from GetHeight..  I need to remember that that space is there, the program doesn't work properly without accounting for it.  I wish little details like that were documented!  Thanks for the help :)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.