CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Raymond Lewallen

Professional Learner

A word wrapping solution using VB.Net

While helping a friend with some code, I ran into a situation where I needed to do something to word wrap lines that were going to print.  The lines were actually data coming from a database where the max length of the field is over 300 characters.  When making this data show up in a multiline textbox, it isn’t a big deal because we can word wrap it easily enough.  The problem comes when you want to print this data.  I needed to take the data stored in the textboxes and write it to a text file for printing at a later time.  That was all fine, except when I printed, naturally, the lines would run off the side of the page.

So here is what I came up with.  It was very difficult looking for solutions to handle word wrapping out on google.  The solutions I did find seems overly complex for the problem that needed to be solved.  If you have written a better solution, please let me know.  This is the best I came up with in the time constraint I had to write it in (2 hours).

Keep in mind, this word wrapping is rather specific, because it is setup for a basic print layout in Portrait mode, 1” margins and printing 10pt Times New Roman font, which is where the 86 characters per line comes from.

My next update to this routine will be to handle changing printer settings and adjusting for those for proper word wrapping.

Word wrapping

    Private Sub SetupForPrint(ByVal currentText As TextBox, ByVal filename As String)

        Dim currentStreamWriter As System.IO.StreamWriter = New System.IO.StreamWriter(filename)

 

        ' This is the max length we want any line to be.  This is based on printing using

        '    the font fact Times New Roman at a font size of 10.

        Dim maxLengthOfALine As Integer = 86

 

        ' This is our starting position within the text body wherewe start a new line

        Dim startingPosition As Integer

 

        ' This is the ending position within the text body where we end a new line

        Dim endingPosition As Integer

 

        ' This is used for the substring for the length of the line we need to pull.

        '    This has to be used because you can't always break apart strings for

        '    word wrapping at exactly 86 characters.  You have to account for not

        '    breaking words in half, so you have to break apart at spaces.  You'll

        '    see this below

        Dim lineLength As Integer = maxLengthOfALine

 

        ' This is the line that we will be writing to the file.

        Dim line As String

 

 

        ' Start looping through the text of the textbox until we reach the end.

        While startingPosition < currentText.Text.Length

            ' This locates the ending position of a line identified by a CRLF.

            endingPosition = currentText.Text.IndexOf(vbCrLf, startingPosition)

 

            ' This tells us that the complete line, from start to CRLF, is less than

            '    86 characters, so no word wrapping needs to be handled.

            If endingPosition - startingPosition < maxLengthOfALine Then

 

                ' This tells us that we have reached the end of the file, so get

                '    the line and get out of the loop.

                If endingPosition = -1 Then

                    line = currentText.Text.Substring(startingPosition, currentText.Text.Length - startingPosition)

                    currentStreamWriter.Write(line)

                    Exit While

                Else

                    ' We are not at the end of the file, but we have a suitable line

                    '    to write that doesn't need word wrapping.  Get the line and

                    '    set the start position of the next line to the end position of the

                    '    current line + 1.

                    line = currentText.Text.Substring(startingPosition, endingPosition - startingPosition)

                    startingPosition = endingPosition + 1

                    currentStreamWriter.Write(line)

                End If

 

            Else

                ' THIS IS WHERE WORD WRAPPING IS HANDLED

                ' This continues to word wrap for every 86 characters in the line

                While lineLength + startingPosition <= endingPosition

                    ' This backtracks in the line in order to find a suitable place to word wrap,

                    ' in this case, a SPACE

                    While currentText.Text.Substring(startingPosition + lineLength - 1, 1) <> Chr(32)

                        lineLength -= 1

                    End While

 

                    ' Get the line.

                    line = currentText.Text.Substring(startingPosition, lineLength)

 

                    ' Write the line.

                    currentStreamWriter.Write(line & vbCrLf)

 

                    ' If we had to backtrack, we can't add 1 to the count.  This

                    ' prevents us from cutting off the first letter of the next word.

                    If lineLength < maxLengthOfALine Then

                        startingPosition += lineLength

                    Else

                        startingPosition += lineLength + 1

                    End If

 

                    ' Reset the lineLength back to the default.

                    lineLength = maxLengthOfALine

 

                End While

 

                ' This is the end of the lines we had to word wrap.  This writes

                ' the last line that got word wrapped to the file.

                line = currentText.Text.Substring(startingPosition, endingPosition - startingPosition)

                currentStreamWriter.Write(line)

 

                ' Set the start position of the next line to the end position of the

                '    current line + 1.

                startingPosition = endingPosition + 1

            End If

        End While

 

        currentStreamWriter.Close()

    End Sub



Comments

Greg said:

This is another example of using MeasureString that worked well for me...

"Print a long series of paragraphs in different fonts, breaking across pages in VB .NET

This example shows how to print a long series of paragraphs in different fonts, breaking across pages in VB .NET. It shows measure text to see where it needs to brake across pages, and how to tell VB not to draw partial words or lines."

http://www.vb-helper.com/howto_net_print_long_text.html
# January 17, 2006 11:55 AM

Raymond Lewallen said:

Great code! I wish I could found that when searching for "Print Word Wrap VB.Net" and other variations when searching on google. I'd never heard of MeasureString until you guys mentioned it. In my defense, I'm not a UI programmer either, so I don't feel bad for not knowing :)
# January 17, 2006 12:14 PM

Jason Bell said:

Doesn't properly handle lines of text > 86 characters with no white space.

# January 23, 2007 1:14 PM

Ninjacodermonkey said:

I dont recall ever hearing of a word over 86 characters long.... (JK)

Great code, Raymond! You just helped me tremendously!  I have a console app that I need to print records from a database to a remote printer at my hospital.  This should work great! Thanks again!

-TJ

# February 15, 2007 12:39 PM

Bob Lott said:

Wow!   This worked great right out of the box, Thank you for sharing!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

# November 26, 2007 9:47 AM

brackett@ufl.edu said:

I had to do a similar requirement for PDF output, and implemented it by splitting the text into words, and then building up words until I got a line's worth. Something like:

using (StreamWriter output = new StreamWriter(..)) {

    string[] words = text.Split(' ', '\n'); // I split on LF, leaving the CR to find an explicit newline

    StringBuilder lineBuilder = new StringBuilder(CHARS_PER_LINE);

    foreach (string word in words) {

         if ((lineBuilder.Length + word.Length) > CHARS_PER_LINE || word.StartsWith("\r")) {

              // wrap to next line

              output.WriteLine(lineBuilder.ToString());

              lineBuilder.Remove(0, lineBuilder.Length);

              word = word.Replace("\r", string.Empty) // remove any explicit newline

         }          

        // Add word

        lineBuilder.Append(word).Append(' ');

    }

    // Last line

   output.WriteLine(lineBuilder.ToString());

}

I actually had to handle page breaks and different font sizes (I chose to make scaled images on a seperate page in deference to my sanity) - so the actual code was a little bit messier. But the basic concept is the same.

# November 26, 2007 12:26 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Raymond Lewallen

Working primarily in the public sector during his career, Raymond has designed and built several high profile enterprise level applications for all levels of the government. Raymond now works as a solutions architect for EMC. Raymond is an agile coach, Microsoft MVP C# and also president of the Oklahoma City Developers Group and Oklahoma Agile Developers Group. Raymond spends a lot of his time learning and teaching such things as Test Driven Development, Domain Driven Design, Design Patterns and Extreme Programming practices and principles, to name a few. Raymond is also an advocate of Alt.Net. Raymond is primarily a framework guy, so don't ask him anything about UI :) Check out Devlicio.us!

Our Sponsors

Free Tech Publications