none
Problem code print richtextbox vb net RRS feed

  • Question

  • Hi, help fix this code, this code is print richbox in vb net studio 2012. the problem of this code is if word passes page 1 then suddenly the page formed becomes very much


    Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage

            Static currentChar As Integer
            Static currentLine As Integer
            Dim textfont As Font = RichTextBox1.Font
            Dim h, w As Integer
            Dim left, top As Integer
            With PrintDocument1.DefaultPageSettings
                h = .PaperSize.Height - .Margins.Top - .Margins.Bottom
                w = .PaperSize.Width - .Margins.Left - .Margins.Right
                left = PrintDocument1.DefaultPageSettings.Margins.Left
                top = PrintDocument1.DefaultPageSettings.Margins.Top
            End With
            e.Graphics.DrawRectangle(Pens.Blue, New Rectangle(left, top, w, h))
            If PrintDocument1.DefaultPageSettings.Landscape Then
                Dim a As Integer
                a = h
                h = w
                w = a
            End If
            Dim lines As Integer = CInt(Math.Round(h / textfont.Height))
            Dim b As New Rectangle(left, top, w, h)
            Dim format As StringFormat
            If Not RichTextBox1.WordWrap Then
                format = New StringFormat(StringFormatFlags.NoWrap)
                format.Trimming = StringTrimming.EllipsisWord
                Dim i As Integer
                For i = currentLine To Math.Min(currentLine + lines, RichTextBox1.Lines.Length - 1)
                    e.Graphics.DrawString(RichTextBox1.Lines(i), textfont, Brushes.Black, New RectangleF(left, top + textfont.Height * (i - currentLine), w, textfont.Height), format)
                Next
                currentLine += lines
                If currentLine >= RichTextBox1.Lines.Length Then
                    e.HasMorePages = False
                    currentLine = 0
                Else
                    e.HasMorePages = True
                End If
                Exit Sub
            End If
            format = New StringFormat(StringFormatFlags.LineLimit)
            Dim line, chars As Integer
            e.Graphics.MeasureString(Mid(RichTextBox1.Text, currentChar + 1), textfont, New SizeF(w, h), format, chars, line)
            If currentChar + chars < RichTextBox1.Text.Length Then
                If RichTextBox1.Text.Substring(currentChar + chars, 1) <> " " And RichTextBox1.Text.Substring(currentChar + chars, 1) <> vbLf Then
                    While chars > 0
                        RichTextBox1.Text.Substring(currentChar + chars, 1)
                        RichTextBox1.Text.Substring(currentChar + chars, 1)
                        chars -= 1
                    End While
                    chars += 1
                End If
            End If
            e.Graphics.DrawString(RichTextBox1.Text.Substring(currentChar, chars), textfont, Brushes.Black, b, format)
            currentChar = currentChar + chars
            If currentChar < RichTextBox1.Text.Length Then
                e.HasMorePages = True
            Else
                e.HasMorePages = False
                currentChar = 0
            End If
        End Sub

        
    • Edited by john 1123 Sunday, June 4, 2017 5:34 PM
    Sunday, June 4, 2017 5:04 PM

Answers

  •  Here is a quick example where i used the code from that link but,  i modified it a bit and use it differently than they show.  You can test it in a new form project with 1 Button,  1 RichTextBox,  1 PrintDocument,  and 1 PrintPreviewDialog control added to the form.

     You can load a file or paste the text into it,  i don`t know where you are getting it from so,  i left that up to you.

      Replace the Form1 class code with this code...

    Imports System.Drawing.Printing
    Imports System.Runtime.InteropServices

    Public Class Form1
        Private LastCharPrinted As Integer

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintPreviewDialog1.Document = PrintDocument1
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Try
                PrintPreviewDialog1.ShowDialog()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End Sub

        Private Sub PrintDocument1_BeginPrint(sender As Object, e As PrintEventArgs) Handles PrintDocument1.BeginPrint
            LastCharPrinted = 0
        End Sub

        Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
            LastCharPrinted = RichTextBoxPrintCtrl.Print(RichTextBox1, LastCharPrinted, RichTextBox1.TextLength, e)
            If LastCharPrinted < RichTextBox1.TextLength Then
                e.HasMorePages = True
            Else
                e.HasMorePages = False
            End If
        End Sub
    End Class


    Public Class RichTextBoxPrintCtrl
        Private Const anInch As Double = 14.4
        Private Const EM_FORMATRANGE As Integer = 1081

        <DllImport("USER32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByRef lp As FORMATRANGE) As Integer
        End Function

        <StructLayout(LayoutKind.Sequential)>
        Private Structure RECT
            Public Left, Top, Right, Bottom As Integer
        End Structure

        <StructLayout(LayoutKind.Sequential)>
        Private Structure CHARRANGE
            Public cpMin As Integer
            Public cpMax As Integer
        End Structure

        <StructLayout(LayoutKind.Sequential)>
        Private Structure FORMATRANGE
            Public hdc As IntPtr
            Public hdcTarget As IntPtr
            Public rc As RECT
            Public rcPage As RECT
            Public chrg As CHARRANGE
        End Structure

        Public Shared Function Print(Rtb As Control, ByVal charFrom As Integer, ByVal charTo As Integer, e As PrintPageEventArgs) As Integer
            Dim rectToPrint As RECT
            rectToPrint.Top = CInt(e.MarginBounds.Top * anInch)
            rectToPrint.Bottom = CInt(e.MarginBounds.Bottom * anInch)
            rectToPrint.Left = CInt(e.MarginBounds.Left * anInch)
            rectToPrint.Right = CInt(e.MarginBounds.Right * anInch)

            Dim rectPage As RECT
            rectPage.Top = CInt(e.PageBounds.Top * anInch)
            rectPage.Bottom = CInt(e.PageBounds.Bottom * anInch)
            rectPage.Left = CInt(e.PageBounds.Left * anInch)
            rectPage.Right = CInt(e.PageBounds.Right * anInch)

            Dim hdc As IntPtr = e.Graphics.GetHdc

            Dim fmtRange As FORMATRANGE
            fmtRange.chrg.cpMax = charTo
            fmtRange.chrg.cpMin = charFrom
            fmtRange.hdc = hdc
            fmtRange.hdcTarget = hdc
            fmtRange.rc = rectToPrint
            fmtRange.rcPage = rectPage

            Dim res As Integer = SendMessage(Rtb.Handle, EM_FORMATRANGE, New IntPtr(1), fmtRange)
            e.Graphics.ReleaseHdc(hdc)
            Return res
        End Function
    End Class
     

     EDIT:  Refined code a little.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, June 4, 2017 7:03 PM
    • Marked as answer by john 1123 Monday, June 5, 2017 5:28 AM
    Sunday, June 4, 2017 6:20 PM

All replies

  •  It is hard to make heads or tails of what you posted.  Please use a Code Block to post code,  the button is on the top of the editor window when you are making a post.

     I would recommend looking into the following link.  It shows an example of how you can print the contents of a RichTextBox.

    How to print the content of a RichTextBox control by using Visual Basic .NET or Visual Basic 2005


    If you say it can`t be done then i`ll try it

    Sunday, June 4, 2017 5:15 PM
  •  Here is a quick example where i used the code from that link but,  i modified it a bit and use it differently than they show.  You can test it in a new form project with 1 Button,  1 RichTextBox,  1 PrintDocument,  and 1 PrintPreviewDialog control added to the form.

     You can load a file or paste the text into it,  i don`t know where you are getting it from so,  i left that up to you.

      Replace the Form1 class code with this code...

    Imports System.Drawing.Printing
    Imports System.Runtime.InteropServices

    Public Class Form1
        Private LastCharPrinted As Integer

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintPreviewDialog1.Document = PrintDocument1
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Try
                PrintPreviewDialog1.ShowDialog()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try
        End Sub

        Private Sub PrintDocument1_BeginPrint(sender As Object, e As PrintEventArgs) Handles PrintDocument1.BeginPrint
            LastCharPrinted = 0
        End Sub

        Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
            LastCharPrinted = RichTextBoxPrintCtrl.Print(RichTextBox1, LastCharPrinted, RichTextBox1.TextLength, e)
            If LastCharPrinted < RichTextBox1.TextLength Then
                e.HasMorePages = True
            Else
                e.HasMorePages = False
            End If
        End Sub
    End Class


    Public Class RichTextBoxPrintCtrl
        Private Const anInch As Double = 14.4
        Private Const EM_FORMATRANGE As Integer = 1081

        <DllImport("USER32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByRef lp As FORMATRANGE) As Integer
        End Function

        <StructLayout(LayoutKind.Sequential)>
        Private Structure RECT
            Public Left, Top, Right, Bottom As Integer
        End Structure

        <StructLayout(LayoutKind.Sequential)>
        Private Structure CHARRANGE
            Public cpMin As Integer
            Public cpMax As Integer
        End Structure

        <StructLayout(LayoutKind.Sequential)>
        Private Structure FORMATRANGE
            Public hdc As IntPtr
            Public hdcTarget As IntPtr
            Public rc As RECT
            Public rcPage As RECT
            Public chrg As CHARRANGE
        End Structure

        Public Shared Function Print(Rtb As Control, ByVal charFrom As Integer, ByVal charTo As Integer, e As PrintPageEventArgs) As Integer
            Dim rectToPrint As RECT
            rectToPrint.Top = CInt(e.MarginBounds.Top * anInch)
            rectToPrint.Bottom = CInt(e.MarginBounds.Bottom * anInch)
            rectToPrint.Left = CInt(e.MarginBounds.Left * anInch)
            rectToPrint.Right = CInt(e.MarginBounds.Right * anInch)

            Dim rectPage As RECT
            rectPage.Top = CInt(e.PageBounds.Top * anInch)
            rectPage.Bottom = CInt(e.PageBounds.Bottom * anInch)
            rectPage.Left = CInt(e.PageBounds.Left * anInch)
            rectPage.Right = CInt(e.PageBounds.Right * anInch)

            Dim hdc As IntPtr = e.Graphics.GetHdc

            Dim fmtRange As FORMATRANGE
            fmtRange.chrg.cpMax = charTo
            fmtRange.chrg.cpMin = charFrom
            fmtRange.hdc = hdc
            fmtRange.hdcTarget = hdc
            fmtRange.rc = rectToPrint
            fmtRange.rcPage = rectPage

            Dim res As Integer = SendMessage(Rtb.Handle, EM_FORMATRANGE, New IntPtr(1), fmtRange)
            e.Graphics.ReleaseHdc(hdc)
            Return res
        End Function
    End Class
     

     EDIT:  Refined code a little.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, June 4, 2017 7:03 PM
    • Marked as answer by john 1123 Monday, June 5, 2017 5:28 AM
    Sunday, June 4, 2017 6:20 PM
  • Thanks IronRazerz for the code can already


    Monday, June 5, 2017 5:30 AM