Detect if all text in TextBox is visible

Posted on 2006-06-09
Last Modified: 2012-06-21
Wish to change the background color of a TextBox if the text is not all displayed.
Wish this to work with Multiline True or False, as well as for different client rectangle sizes, and different font sizes and bold/italic etc.

Purpose is to let user know that there is more text than is shown.

Tried this solution, but it is not exact.

' Control inherits from TextBox
Protected Overrides Sub OnTextChanged (ByVal e as System.EventArgs)
   ' If it all fits, then background color is Window, else Control
   Dim clientWidth as Integer = ClientSize.Width
   Dim clientHeight as Integer = ClientSize.height
   Dim grfx as Graphics = CreateGraphics
   Dim fudgeWidth as Double = grfx.MeasureString(" X", Font, Integer.MaxValue)
   Dim actualSizeF as SizeF = grfx.MeasureString(Text, Font, clientWidth + fudgeWidth)

    If actualSizef.Height <= clientHeight then
        BackColor = Drawing.SystemColors.Window
        BackColor = Drawing.SystemColors.Control
    End If

End Sub      
' This works most of the time, but would like it to work all the time.
' Does TextBox use vanilla DrawString, or does it use some proprietary method of drawing text?
' Alternative is to build my own TextBox from scratch, but that doesn't sound pleasant!

Thank you,
Brother Bill
Question by:brotherbill999
LVL 28

Expert Comment

ID: 16870651
In a multiline textbox you won't have to worry about "letting the user know" because it will display scroll bars. As for a single-line textbox the is no EXACT way to do this because all browsers interpret the textbox "columns" property slightly differently. The best thing to do would be to do a textbox.Text.Length and see if it is greater than the column numbers, that will typically mean there is more text, but not always.

Author Comment

ID: 16871216
Clarification: This is a Winforms TextBox, not ASP.NET.
A single line textbox may have an overflow of data, without visually indicating so.
A multi-line textbox may not have scroll bars, therefore the user may not be aware of additional data.

Thus, the reason for the question.  It would be nice to provide a background color difference if some data is hidden.

Expert Comment

ID: 16872031
Try this

          if (textBox1.PreferredSize.Width > textBox1.Size.Width)
                textBox1.BackColor = Color.Red;
                textBox1.BackColor = Color.Blue;

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.


Author Comment

ID: 16872695
Hi AdGroot.  
Your solution is *close* for Multiline = False, but it displays overflow color, even when text fits.
Your solution doesn't work at all for MultiLine=True.

Would appreciate other suggestions...
Brother Bill

Accepted Solution

shy_talk earned 500 total points
ID: 16873308
Just to add to the confusion...

I got this working after a fashion. Dont' gush with gratitude. The code is crap,  but it worked OK at first glance with single line textbox and another invisible textbox of the same size on the same form. I know for a fact that this will not work as it is with multiline, but who knows, a genius like yourself may well be able to succeed where a sucker like me has failed. Good luck.

   private void textBox3_TextChanged(object sender, EventArgs e)
         TextBox txt = (TextBox)sender;
  // Just bulletproofing
         if (textBox4.Size != txt.Size)
            textBox4.Size = txt.Size;

// Copy the text to the invisible TextBox
         textBox4.Text = txt.Text;

// Sample the index at the left of the box
         textBox4.SelectionStart = 0;  
         c1 = textBox4.GetCharIndexFromPosition(new Point(2, 2));

// Try to scroll the box
         textBox4.SelectionStart = txt.Text.Length;   //textBox4.Text.Length;
         c2 = textBox4.GetCharIndexFromPosition(new Point(2, 2));
// Well, here goes sod all...
         if (c1 != c2)
            txt.BackColor = Color.Pink;
            txt.BackColor = Color.White;

// You did ask for suggestions, not solutions...

Author Comment

ID: 16875056
Great job shy_talk.  Just streamlined your solution, and figured out the Multi-line solution.  Just count the lines used, vs. available lines.  Anyway, here is the documented source code.  Thank you all.
Thus, the user can be informed, via background color, that there is hidden text in a TextBox.

    ' Inherited from TextBox, so Me is a TextBox
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
        ' If it all fits, then background color is Window, else Control
        If FullyVisible(Me) Then
            BackColor = Drawing.SystemColors.Window
            BackColor = Drawing.SystemColors.Control
        End If
    End Sub

    ' This is the work horse...
    Public Function FullyVisible(ByVal txtBox As TextBox) As Boolean
        If txtBox Is Nothing Then Throw New ArgumentException("FullyVisible: txtBox may not be Nothing")
        Dim Result As Boolean
        If txtBox.Text.Length = 0 Then
            ' No matter how small the textbox is, you see all that there is, that is Nothing
            Result = True
        ElseIf txtBox.Multiline = False Then
            ' Create a copy of original text box, and copy key attributes
            Dim txtBox2 As New TextBox
            Dim pt2_2 As New Point(2, 2)
            txtBox2.Font = txtBox.Font
            txtBox2.Size = txtBox.Size
            txtBox2.Text = txtBox.Text
            ' c1 is char index 2 pixels from left, typically 0
            txtBox2.SelectionStart = 0
            Dim c1 As Integer = txtBox2.GetCharIndexFromPosition(pt2_2)
            ' c2 is char index 2 pixels from left, after scrolling to make last character visible
            txtBox2.SelectionStart = txtBox2.Text.Length
            Dim c2 As Integer = txtBox2.GetCharIndexFromPosition(pt2_2)
            ' If character indexes are equal, then you see all there is to see
            Result = (c1 = c2)
            ' MultiLine = True
            ' Client Height is the maximum vertical area inside the box where text may be written, excluding margins
            Dim clientHeight As Integer = txtBox.ClientSize.Height
            ' Line Height is number of pixels for each row, including white space
            Dim lineHeight As Integer = Math.Ceiling(txtBox.Font.GetHeight)
            ' Max Lines is number of visible lines of text
            Dim maxLines = Math.Floor(clientHeight / lineHeight)  ' Maximum rows that can be shown

            Dim len = txtBox.Text.Length
            ' Find which line (origin 1) that the last character is on
            Dim line1 As Integer = 1 + IIf(len = 0, 0, Me.GetLineFromCharIndex(len))
            ' If its within the max lines, its fully visible, else there is some hidden text
            Result = (line1 <= maxLines)
        End If

        Return Result
    End Function

Expert Comment

ID: 16882148
Well, what a pleasant surprise! Two heads and all that. Great little puzzle. Thanks for the points, bro'.

Author Comment

ID: 16884895
When making the project Option Strict, noticed that certain variables need to be cleaned up, such as maxLines and len.  I'll post that at a later time.

Featured Post

Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A basic question.. “What is the Garbage Collector?” The usual answer given back: “Garbage collector is a background thread run by the CLR for freeing up the memory space used by the objects which are no longer used by the program.” I wondered …
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.

821 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