Detect if all text in TextBox is visible

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)
   MyBase.OnTextChanged(e)
   ' 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
    Else
        BackColor = Drawing.SystemColors.Control
    End If

    grfx.Dispose
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
brotherbill999Asked:
Who is Participating?
 
shy_talkCommented:
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;
         Application.DoEvents();

// 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;
         }
         else
         {
            txt.BackColor = Color.White;
         }
      }

// You did ask for suggestions, not solutions...
0
 
strickddCommented:
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.
0
 
brotherbill999Author Commented:
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.
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
AdGrootCommented:
Try this

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

Ad
0
 
brotherbill999Author Commented:
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
0
 
brotherbill999Author Commented:
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)
        MyBase.OnTextChanged(e)
        ' If it all fits, then background color is Window, else Control
        If FullyVisible(Me) Then
            BackColor = Drawing.SystemColors.Window
        Else
            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)
        Else
            ' 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
0
 
shy_talkCommented:
Well, what a pleasant surprise! Two heads and all that. Great little puzzle. Thanks for the points, bro'.
0
 
brotherbill999Author Commented:
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.
0
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.

All Courses

From novice to tech pro — start learning today.