Text size calculation problem.

Posted on 2004-11-22
Last Modified: 2011-09-20
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?
Question by:GohdanTheMoblin
    LVL 25

    Accepted Solution

    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
    LVL 2

    Author Comment

    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?
    LVL 25

    Expert Comment

    Well actually it is 1 + 0.5, 1 is for the space between the lines and the 0.5 is for rounding up
    LVL 2

    Author Comment

    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 :)

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Top 6 Sources for Identifying Threat Actor TTPs

    Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

    I'm currently working for a company where I have to upgrade over 50 VB6 programs to VB.NET 2008.  So far I'm about half way through, and I've learned quite a few tricks that drastically improve the performance of VB.NET apps. Because there are a…
    This tutorial demonstrates one way to create an application that runs without any Forms but still has a GUI presence via an Icon in the System Tray. The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Ru…
    Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
    Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

    737 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    18 Experts available now in Live!

    Get 1:1 Help Now