none
Reports from inputs

    Question

  • Its been a while since I last used VB, but i need to make a housekeeping report for a small motel. Basically i need all our room numbers displayed upon opening the program, then there should be check boxes next to them so i can select which rooms need to be cleaned then i can click print or create report then print it out. How would i even start coding this? the last program i did was some simple tax calculations which was pretty easy. But on this application, i can do the room numbers with the check boxes for selection, but im drawing a blank when it comes to outputting it to a report for printing it, any suggestions??

    thx

    Tuesday, March 14, 2017 2:49 AM

All replies

  • Hi

    This is not as straighforward as it was in 'the old days',

    '

    Here is some code to illustrate. If you choose to try this out, you will need to start a new Project. This will print any graphics on the page as well.

    '

    Step1: add a new Class to the Project. Copy/replace all code with this:

    ' https://support.microsoft.com/en-us/kb/811401
    
    ' https://support.microsoft.com/en-us/help/811401/how-to-print-the-content-of-a-richtextbox-control-by-using-visual-basic-.net-or-visual-basic-2005
    
    ' https://social.msdn.microsoft.com/Forums/vstudio/en-US/7777bae1-3610-43de-802c-2a9842cd6d2c/how-to-print-a-richtextbox-in-visual-basic-2013?forum=vbgeneral
    
    Option Explicit On
    
    Imports System.Runtime.InteropServices
    Imports System.Drawing.Printing
    
    Namespace RichTextBoxPrintCtrl
        Public Class RichTextBoxPrintCtrl
            Inherits RichTextBox
            ' Convert the unit that is used by the .NET framework (1/100 inch) 
            ' and the unit that is used by Win32 API calls (twips 1/1440 inch)
            Private Const AnInch As Double = 14.4
    
            <StructLayout(LayoutKind.Sequential)>
            Private Structure RECT
                Public Left As Integer
                Public Top As Integer
                Public Right As Integer
                Public Bottom As Integer
            End Structure
    
            <StructLayout(LayoutKind.Sequential)>
            Private Structure CHARRANGE
                Public cpMin As Integer          ' First character of range (0 for start of doc)
                Public cpMax As Integer          ' Last character of range (-1 for end of doc)
            End Structure
    
            <StructLayout(LayoutKind.Sequential)>
            Private Structure FORMATRANGE
                Public hdc As IntPtr             ' Actual DC to draw on
                Public hdcTarget As IntPtr       ' Target DC for determining text formatting
                Public rc As RECT                ' Region of the DC to draw to (in twips)
                Public rcPage As RECT            ' Region of the whole DC (page size) (in twips)
                Public chrg As CHARRANGE         ' Range of text to draw (see above declaration)
            End Structure
    
            Private Const WM_USER As Integer = &H400
            Private Const EM_FORMATRANGE As Integer = WM_USER + 57
    
            Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
    
            ' Render the contents of the RichTextBox for printing
            '	Return the last character printed + 1 (printing start from this point for next page)
            Public Function Print(ByVal charFrom As Integer, ByVal charTo As Integer, ByVal e As PrintPageEventArgs) As Integer
    
                ' Mark starting and ending character 
                Dim cRange As CHARRANGE
                cRange.cpMin = charFrom
                cRange.cpMax = charTo
    
                ' Calculate the area to render and print
                Dim rectToPrint As RECT
                rectToPrint.Top = e.MarginBounds.Top * AnInch
                rectToPrint.Bottom = e.MarginBounds.Bottom * AnInch
                rectToPrint.Left = e.MarginBounds.Left * AnInch
                rectToPrint.Right = e.MarginBounds.Right * AnInch
    
                ' Calculate the size of the page
                Dim rectPage As RECT
                rectPage.Top = e.PageBounds.Top * AnInch
                rectPage.Bottom = e.PageBounds.Bottom * AnInch
                rectPage.Left = e.PageBounds.Left * AnInch
                rectPage.Right = e.PageBounds.Right * AnInch
    
                Dim hdc As IntPtr = e.Graphics.GetHdc()
    
                Dim fmtRange As FORMATRANGE
                fmtRange.chrg = cRange                 ' Indicate character from to character to 
                fmtRange.hdc = hdc                     ' Use the same DC for measuring and rendering
                fmtRange.hdcTarget = hdc               ' Point at printer hDC
                fmtRange.rc = rectToPrint              ' Indicate the area on page to print
                fmtRange.rcPage = rectPage             ' Indicate whole size of page
    
                Dim res As IntPtr = IntPtr.Zero
    
                Dim wparam As IntPtr = IntPtr.Zero
                wparam = New IntPtr(1)
    
                ' Move the pointer to the FORMATRANGE structure in memory
                Dim lparam As IntPtr = IntPtr.Zero
                lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
                Marshal.StructureToPtr(fmtRange, lparam, False)
    
                ' Send the rendered data for printing 
                res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam)
    
                ' Free the block of memory allocated
                Marshal.FreeCoTaskMem(lparam)
    
                ' Release the device context handle obtained by a previous call
                e.Graphics.ReleaseHdc(hdc)
    
                ' Return last + 1 character printer
                Return res.ToInt32()
            End Function
    
        End Class
    End Namespace

    Step 2: rebuild the project

    '

    Step 3:

    Add the following to the Form1 in the Designer

    ' this example needs a Form1 with:
    '
    ' GroupBox1 containing as many 'room'
    ' CheckBoxes as are needed.
    '
    ' Button1 - Print Prevfiew
    ' Button2 - Page SetUp
    ' Button3 - Print
    '
    ' RichTextBoxPrintCtrl1 - (should be in the toolbox after the rebuild)
    '
    ' PageSetUpDialog1 - from toolbox
    ' PrintPreviewDialog1 - from toolbox
    ' PrintDialog1 - from toolbox
    ' PrintDocument1 - from toolbox

    '

    Step 4:

    Copy/replace all the Form1 code with this:

    ' this example needs a Form1 with:
    
    ' GroupBox1 containing as many 'room' 
    ' CheckBoxes as are needed.
    
    ' Button1 - Print Prevfiew
    ' Button2 - Page SetUp
    ' Button3 - Print
    
    ' RichTextBoxPrintCtrl1 - (from Class RichTextBoxPrintCtrl)
    
    ' PageSetUpDialog1 - from toolbox
    ' PrintPreviewDialog1 - from toolbox
    ' PrintDialog1 - from toolbox
    ' PrintDocument1 - from toolbox
    
    Option Strict On
    Option Explicit On
    Option Infer Off
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintDialog1.Document = PrintDocument1
            PrintPreviewDialog1.Document = PrintDocument1
            PageSetupDialog1.Document = PrintDocument1
        End Sub
    
        Private checkPrint As Integer
        Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
            checkPrint = 0
        End Sub
        Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
            ' Print the content of the RichTextBox. Store the last character printed.
            checkPrint = RichTextBoxPrintCtrl1.Print(checkPrint, RichTextBoxPrintCtrl1.TextLength, e)
    
            ' Look for more pages
            If checkPrint < RichTextBoxPrintCtrl1.TextLength Then
                e.HasMorePages = True
            Else
                e.HasMorePages = False
            End If
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button1.Click
            SetText()
            PrintPreviewDialog1.ShowDialog()
        End Sub
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button2.Click
            SetText()
            PageSetupDialog1.ShowDialog()
        End Sub
        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button3.Click
            SetText()
            If PrintDialog1.ShowDialog() = DialogResult.OK Then
                PrintDocument1.Print()
            End If
        End Sub
        Private Sub SetText()
            RichTextBoxPrintCtrl1.Clear()
            RichTextBoxPrintCtrl1.AppendText("This is the Header Text" & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("Rooms requiring severe scrub down" & vbCrLf & vbCrLf)
            For i As Integer = GroupBox1.Controls.Count - 1 To 0 Step -1
                If GroupBox1.Controls(i).GetType() Is GetType(CheckBox) Then
                    If CType(GroupBox1.Controls(i), CheckBox).Checked Then
                        RichTextBoxPrintCtrl1.AppendText(CType(GroupBox1.Controls(i), CheckBox).Text & vbCrLf)
                    End If
    
                End If
            Next
        End Sub
    End Class
    Step 5:

    Rebuild Project - hopefully it compiles OK. If so, run and try it out.

    '

    I hope I have included all the necessary info. There are a couple of links in the code that may help if any problems with what I posted.


    Regards Les, Livingston, Scotland


    • Edited by leshay Tuesday, March 14, 2017 10:06 PM
    Tuesday, March 14, 2017 6:02 AM
  • Here is an easy high quality text printout.

    Imports System.Drawing.Printing
    
    Public Class Form2
        Private WithEvents PrintDocument1 As PrintDocument = New PrintDocument
        Private PrintPreviewDialog1 As New PrintPreviewDialog
        Private thePrintString, theString As String
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            'make the list
            CheckedListBox1.Items.Add("President Suite")
            For i = 1 To 10
                CheckedListBox1.Items.Add("Room " & i.ToString)
            Next
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Try
                'create the string
                If CheckedListBox1.CheckedItems.Count <> 0 Then
                    theString = "Today's Room Report" & vbLf & vbLf
                    For i = 0 To CheckedListBox1.CheckedItems.Count - 1
                        theString = theString & "  * " & CheckedListBox1.CheckedItems(i).ToString & vbLf
                    Next
                End If
    
                'show print preview with printdoc
                'click print icon button on print preview to print
                thePrintString = theString      'reset printstring
                PrintPreviewDialog1.Document = PrintDocument1
                PrintPreviewDialog1.ShowDialog()
            Catch ex As Exception
                MsgBox("Problem Printing:" & Chr(13) & ex.Message, MsgBoxStyle.Exclamation)
            End Try
    
        End Sub
    
        Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
    
            Dim charactersOnPage, linesPerPage As Integer
    
            Using f As Font = New Font("Arial", 12)
                ' Sets the value of charactersOnPage to the number of characters  
                ' of stringToPrint that will fit within the bounds of the page.
                e.Graphics.MeasureString(thePrintString, f, e.MarginBounds.Size, StringFormat.GenericTypographic, charactersOnPage, linesPerPage)
    
                ' Draws the string within the bounds of the page
                e.Graphics.DrawString(thePrintString, f, Brushes.Black, e.MarginBounds, StringFormat.GenericTypographic)
    
            End Using
    
            ' Remove the portion of the string that has been printed.
            thePrintString = thePrintString.Substring(charactersOnPage)
    
            ' Check to see if more pages are to be printed.
            e.HasMorePages = thePrintString.Length > 0
    
            If Not e.HasMorePages Then thePrintString = theString
    
        End Sub
    End Class

    • Proposed as answer by Frank L. Smith Wednesday, March 15, 2017 12:06 AM
    Tuesday, March 14, 2017 9:51 PM
  • thats nice, very similiar to what i need, but my room numbers are from 105 to 126 and each room has 3 options from which i pick from for example the first couple lines on the program would read something like this 
    Room 105 (chkbx) check-out(chkbox) Stay-over(chkbox) Weekly-Service(Chkbox)
    Room 106 (chkbx) check-out(chkbox) Stay-over(chkbox) Weekly-Service(Chkbox)
    Room 107 (chkbx) check-out(chkbox) Stay-over(chkbox) Weekly-Service(Chkbox)
    Room 108 (chkbx) check-out(chkbox) Stay-over(chkbox) Weekly-Service(Chkbox)
    Room 109 (chkbx) check-out(chkbox) Stay-over(chkbox) Weekly-Service(Chkbox)
    and so forth all the way down to room 126. Now granted we dont rent all the rooms everyday. So it should only print the room we have selected along with what type of service they need. also now that i think of it we may not even need the chk box for the actual room, just the fact that we selected what type of service they need that room should automatically be selected. 
    any help would be great.
    thx
    Tuesday, March 14, 2017 11:52 PM
  • Hi

    It would have been helpful if you had explained your requirements from the start rather than moving the goalposts as you go.

    However, here is the code as I posted above (minus the Class code which remains the same), amended for your new requirements. This uses a DataGridView to allow for the extra Room requirements.

    The code will create/use a file called 'RoomData.xml' to save/load the Room data and is located in the same folder as the application executable.

    ' this example needs a Form1 with:
    
    ' Default empty DataGridView1
    
    ' Button1 - Print Preview
    ' Button2 - Page SetUp
    ' Button3 - Print
    ' Button4 - Reset to all rooms with none checked
    
    ' RichTextBoxPrintCtrl1 - (from Class RichTextBoxPrintCtrl)
    
    ' PageSetUpDialog1 - from toolbox
    ' PrintPreviewDialog1 - from toolbox
    ' PrintDialog1 - from toolbox
    ' PrintDocument1 - from toolbox
    
    Option Strict On
    Option Explicit On
    Option Infer Off
    Public Class Form1
        Dim myTable As New DataTable("Rooms")
        Dim view As New DataView(myTable)
        Dim DataFilePath As String = Application.StartupPath & "\RoomData.xml"
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            myTable.WriteXml(DataFilePath)
        End Sub
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            PrintDialog1.Document = PrintDocument1
            PrintPreviewDialog1.Document = PrintDocument1
            PageSetupDialog1.Document = PrintDocument1
            With myTable
                .Columns.Add("Room", GetType(String))
                .Columns.Add("CheckOut", GetType(Boolean))
                .Columns.Add("StayOver", GetType(Boolean))
                .Columns.Add("WeeklyClean", GetType(Boolean))
            End With
            If Not IO.File.Exists(DataFilePath) Then
                Button4.PerformClick()
                myTable.WriteXml(DataFilePath)
            Else
                myTable.ReadXml(DataFilePath)
            End If
            DataGridView1.DataSource = view
        End Sub
    
        Private checkPrint As Integer
        Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, ByVal e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
            checkPrint = 0
        End Sub
        Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
            ' Print the content of the RichTextBox. Store the last character printed.
            checkPrint = RichTextBoxPrintCtrl1.Print(checkPrint, RichTextBoxPrintCtrl1.TextLength, e)
    
            ' Look for more pages
            If checkPrint < RichTextBoxPrintCtrl1.TextLength Then
                e.HasMorePages = True
            Else
                e.HasMorePages = False
            End If
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button1.Click
            SetText()
            PrintPreviewDialog1.ShowDialog()
        End Sub
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button2.Click
            SetText()
            PageSetupDialog1.ShowDialog()
        End Sub
        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button3.Click
            SetText()
            If PrintDialog1.ShowDialog() = DialogResult.OK Then
                PrintDocument1.Print()
            End If
        End Sub
        Private Sub SetText()
            ' this sets the text in the RTB for the
            ' different room requirements (by group)
    
            RichTextBoxPrintCtrl1.Clear()
    
            RichTextBoxPrintCtrl1.AppendText("This is the Header for Check Out today" & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("Rooms Checking Out today" & vbCrLf & vbCrLf)
            Dim checkout() As DataRow = myTable.Select("CheckOut = true")
            For Each r As DataRow In checkout
                RichTextBoxPrintCtrl1.AppendText(r.Item("Room").ToString & vbCrLf)
            Next
    
            RichTextBoxPrintCtrl1.AppendText(vbCrLf & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("This is the Header for StayOver" & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("Rooms Stay Over today" & vbCrLf & vbCrLf)
            Dim stayover() As DataRow = myTable.Select("StayOver = true")
            For Each r As DataRow In stayover
                RichTextBoxPrintCtrl1.AppendText(r.Item("Room").ToString & vbCrLf)
            Next
    
            RichTextBoxPrintCtrl1.AppendText(vbCrLf & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("This is the Header for Room Cleaning" & vbCrLf)
            RichTextBoxPrintCtrl1.AppendText("Rooms requiring severe scrub down" & vbCrLf & vbCrLf)
            Dim clean() As DataRow = myTable.Select("WeeklyClean = true")
            For Each r As DataRow In clean
                RichTextBoxPrintCtrl1.AppendText(r.Item("Room").ToString & vbCrLf)
            Next
        End Sub
        Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
            ' this will reset the DataTable for all Rooms
            ' with all checkboxes blank
            myTable.Rows.Clear()
            For i As Integer = 105 To 126
                myTable.Rows.Add(i.ToString)
            Next
        End Sub
    End Class
    



    Regards Les, Livingston, Scotland



    • Edited by leshay Wednesday, March 15, 2017 5:07 PM
    Wednesday, March 15, 2017 2:36 PM
  • Thanks, really appreciate it.
    Wednesday, March 15, 2017 11:07 PM
  • Just started doing this with the code u posted, however i have visual studio 2012, an older version. the problem im having is that RichTextBoxPrintCtrl is not there that i can see, everything else is. Is there a simple work around for this? or do i need to find another solution?

    thx

    Friday, March 17, 2017 7:34 PM
  • Hi

    The control is not a standard control. It is created by the Class (code I posted). That is why you needed to add that Class and Rebuild the Project - once you have done that, the control should be available at the very top of the ToolBox - called RichTextBoxPrintCtrl. It is this one that you need to use instead of the standard RichTextBox.


    Regards Les, Livingston, Scotland

    Friday, March 17, 2017 8:33 PM
  • Hi

    I have uploaded full Project to OneDrive. If you want to try it out I will leave it there for a short time.Letme know if you decide to download it and I can then remove it.

    VB Example


    Regards Les, Livingston, Scotland


    • Edited by leshay Friday, March 17, 2017 10:03 PM
    Friday, March 17, 2017 10:01 PM