Results 1 to 14 of 14

Thread: VB.NET Print total items of ListBox

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    VB.NET Print total items of ListBox

    Trying to print the complete list of items from a listbox using this code. When I set 'e.HasMorePages' to True, it will continue to run on forever. Not sure what I am missing here, but the way this is now only gives me a single page of items. Thanks for any assistance on this.



    Code:
        Private Sub BtnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnPrint.Click
            PrintDocument1.Print()
        End Sub
    
        Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    
            Dim fnt As New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Point)
            Dim ListBoxItem As String = String.Empty
    
            For Each LBItem As String In ListBox2.Items
                ListBoxItem = ListBoxItem & vbCrLf & LBItem
            Next
    
            ListBoxItem = ListBoxItem.Substring(vbCrLf.Length)
            e.Graphics.DrawString(ListBoxItem, fnt, Brushes.Black, 0, 0)
            e.HasMorePages = False
    
        End Sub

  2. #2
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,370

    Re: VB.NET Print total items of ListBox

    Printing is a bit difficult. Basically what you will need to do is draw the String of each item in the ListBox and if the total height of all that has been drawn will exceed the total height of the page then you need to set HasMorePages to true.

    Try something like this (untested and modified from ChatGPT):
    Code:
    Imports System.Drawing.Printing
    Public Class MyForm
        Private _startIndex As Integer = 0
    
        Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
            Dim printFont = New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Point)
            Dim lineHeight = printFont.GetHeight(e.Graphics)
            Dim printArea = New RectangleF(e.MarginBounds.Left, e.MarginBounds.Top, e.MarginBounds.Width, e.MarginBounds.Height)
            Dim itemIndex = _startIndex
            Dim listboxItemCount = ListBox2.Items.Count
    
            While (itemIndex < listboxItemCount)
                Dim itemText = ListBox2.Items(itemIndex).ToString()
                Dim textLayout = New StringFormat()
    
                printArea.Y += lineHeight
    
                Dim linesPerPage = Convert.ToInt32(Math.Floor(printArea.Height / lineHeight))
    
                For i = 0 To linesPerPage - 1
                    If (itemIndex < listboxItemCount) Then
                        Dim lineRectangle = New RectangleF(printArea.Left, printArea.Y, printArea.Width, lineHeight)
                        e.Graphics.DrawString(itemText, printFont, Brushes.Black, lineRectangle, textLayout)
                        printArea.Y += lineHeight
                        itemIndex += 1
                    Else
                        Exit For
                    End If
                Next
    
                If (itemIndex < listboxItemCount) Then
                    e.HasMorePages = True
                    _startIndex = itemIndex
                    Return
                End If
            End While
    
            _startIndex = 0
            e.HasMorePages = False
        End Sub
    End Class
    Update -
    Reviewing this code a little bit, it is potentially flawed a little bit based on your situation.

    This code assumes that each item in the ListBox only takes up a single line on the printed document. If that's not the case, then you'll need to adjust the lineHeight variable in the For/Next loop to be recalculated the height of the drawn text.

    If you don't have any items that span multiple lines though, then this solution should be fine.
    Last edited by dday9; Jan 4th, 2024 at 05:56 PM.
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

  3. #3

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    Thanks dday9... this does produce strange results like you said. My listbox is populated with info after searching multiple files for a part number and returning filename and qty of each part number within. Here is an example of the listbox contents: "PART NUMBER" is what was searched. "-TOP & -BTM" lines are the filenames found containing the part number and then QTY used. The typical print range on this can be 1 to 10 pages.

    Code:
    PART NUMBER:  GR29-028B
    _______________________________
    
    2-900-09-TOP
    QTY Per = 4
    --------------
    2-189-02-BTM
    QTY Per = 8
    --------------
    2-3389-01-TOP
    QTY Per = 17
    --------------
    4-988-023-TOP
    QTY Per = 12

  4. #4
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,370

    Re: VB.NET Print total items of ListBox

    I'm not fully understanding the issue, could you elaborate a bit more on what happened when you tried the solution I provided?
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

  5. #5

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    Sorry, I should have posted that as well. Your code now prints like this:

    Code:
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    PART NUMBER:  GR29-028B
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    --------------------------
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5
    QTY Per = 5

  6. #6
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,370

    Re: VB.NET Print total items of ListBox

    So this loops over every item in your ListBox. If you setup a debugger at the top of the PrintPage event handler, what is the result of ListBox2.Items?
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

  7. #7
    PowerPoster
    Join Date
    Sep 2005
    Location
    Modesto, Ca.
    Posts
    5,508

    Re: VB.NET Print total items of ListBox

    Looks like your loop is setup wrong. Need to post your current code.

    btw - That data really seems to lend itself to being displayed in a DataGridView. Each file would only use one line, not 3. Save a lot of pages.

    I believe in the Code Bank there is an example of how to print a datagridview.

  8. #8

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    dday9 - I must be doing this wrong because I cannot get the listbox items to change when I set a breakpoint and step through it.

    wes4dbt - I am open to doing a DataGridView rather than a listbox if it makes printing easier. I have it set this way now simply for user readability.

    Here is the complete code I am using now to search and populate the listbox. I am certain it lacks efficiency.

    Code:
    Imports System.Drawing.Printing
    Imports System.IO
    Imports System.Text.RegularExpressions
    
    Public Class Form1
    
        Dim fpath = Directory.GetCurrentDirectory
        Dim filesPath = fpath
        Dim thePart As String
        Private _startIndex As Integer = 0
    
        Private Sub BtnSearch_Click(sender As System.Object, e As System.EventArgs) Handles BtnSearch.Click
    
            If txtPartNum.Text = "" Then Exit Sub
    
            Me.ListBox2.Items.Clear()
    
            thePart = $"{txtPartNum.Text}" 'match whole word
            ListBox2.Font = New Font("Arial", 10, FontStyle.Regular)
            Me.ListBox2.Items.Add("PART NUMBER:    " & thePart)
            Me.ListBox2.Items.Add("________________________________________")
            Me.ListBox2.Items.Add("")
    
            Dim startFolder As String = fpath & "\prg"
            Dim fileList As IEnumerable(Of FileInfo) = GetFiles(startFolder)
            Dim searchTerm As New Regex(thePart)
    
    
            Dim queryMatchingFiles = From afile In fileList
                                     Where afile.Extension = ".dp"
                                     Let fileText = File.ReadAllText(afile.FullName)
                                     Let matches = searchTerm.Matches(fileText)
                                     Where (matches.Count > 0)
                                     Select Name = afile.Name,
                                            Matches = From match As Match In matches
                                                      Group By match.Value Into g = Group
                                                      Select New With {Value, g.Count}
    
    
            Try
                Dim folder As String = fpath & "\parts\"
                Dim filename As String = System.IO.Path.Combine(folder, thePart & ".jpg")
                PictureBox1.Image = Image.FromFile(filename)
            Catch ex As Exception
                'Leave image blank
            End Try
    
    
            For Each fileMatches In queryMatchingFiles
                Dim s = fileMatches.Name
                Dim newFile As String = (Path.Combine(Path.GetDirectoryName(s), Path.GetFileNameWithoutExtension(s)))
                ListBox2.Items.Add(newFile)
                For Each match In fileMatches.Matches
                    'ListBox2.Items.Add(match.Value + ": " + match.Count.ToString)
                    ListBox2.Items.Add("QTY Per =   " + match.Count.ToString)
                Next
                ListBox2.Items.Add("------------------------------")
            Next
    
        End Sub
    
        Shared Function GetFiles(root As String) As IEnumerable(Of FileInfo)
            Return From file In My.Computer.FileSystem.GetFiles(
                       root, FileIO.SearchOption.SearchAllSubDirectories, "*.*")
                   Select New FileInfo(file)
        End Function
    
        Private Sub txtPartNum_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtPartNum.KeyPress
            If e.KeyChar = Chr(13) Then
                BtnSearch.Focus()
                BtnSearch.PerformClick()
            End If
        End Sub
    
        Private Sub BtnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnPrint.Click
            PrintDocument1.Print()
        End Sub
    
        'Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    
        '    Dim fnt As New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Point)
        '    Dim ListBoxItem As String = String.Empty
    
        '    For Each LBItem As String In ListBox2.Items
        '        ListBoxItem = ListBoxItem & vbCrLf & LBItem
        '        ListBoxItem = ListBoxItem.Substring(vbCrLf.Length)
        '    Next
    
        '    ListBoxItem = ListBoxItem.Substring(vbCrLf.Length)
        '    e.Graphics.DrawString(ListBoxItem, fnt, Brushes.Black, 0, 0)
        '    e.HasMorePages = False
    
        'End Sub
    
        Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
            Dim printFont = New Font("Arial", 10, FontStyle.Regular, GraphicsUnit.Point)
            Dim lineHeight = printFont.GetHeight(e.Graphics)
            Dim printArea = New RectangleF(e.MarginBounds.Left, e.MarginBounds.Top, e.MarginBounds.Width, e.MarginBounds.Height)
            Dim itemIndex = _startIndex
            Dim listboxItemCount = ListBox2.Items.Count
    
            While (itemIndex < listboxItemCount)
                Dim itemText = ListBox2.Items(itemIndex).ToString()
                Dim textLayout = New StringFormat()
    
                printArea.Y += lineHeight
    
                Dim linesPerPage = Convert.ToInt32(Math.Floor(printArea.Height / lineHeight))
    
                For i = 0 To linesPerPage - 1
                    If (itemIndex < listboxItemCount) Then
                        Dim lineRectangle = New RectangleF(printArea.Left, printArea.Y, printArea.Width, lineHeight)
                        e.Graphics.DrawString(itemText, printFont, Brushes.Black, lineRectangle, textLayout)
                        printArea.Y += lineHeight
                        itemIndex += 1
                    Else
                        Exit For
                    End If
                Next
    
                If (itemIndex < listboxItemCount) Then
                    e.HasMorePages = True
                    _startIndex = itemIndex
                    Return
                End If
            End While
    
            _startIndex = 0
            e.HasMorePages = False
        End Sub
    
    End Class
    Last edited by mikeg71; Jan 5th, 2024 at 01:46 PM.

  9. #9
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: VB.NET Print total items of ListBox

    I’m not sure what data you have in your ListBox. If you do decide to switch to a DataGridView, check the DataGridView Printing link in my signature below this post…

  10. #10
    PowerPoster
    Join Date
    Sep 2005
    Location
    Modesto, Ca.
    Posts
    5,508

    Re: VB.NET Print total items of ListBox

    Code:
            While (itemIndex < listboxItemCount)
                Dim itemText = ListBox2.Items(itemIndex).ToString()
                Dim textLayout = New StringFormat()
    
                printArea.Y += lineHeight
    
                Dim linesPerPage = Convert.ToInt32(Math.Floor(printArea.Height / lineHeight))
    
                For i = 0 To linesPerPage - 1
                    If (itemIndex < listboxItemCount) Then
                        Dim lineRectangle = New RectangleF(printArea.Left, printArea.Y, printArea.Width, lineHeight)
                        e.Graphics.DrawString(itemText, printFont, Brushes.Black, lineRectangle, textLayout)
                        printArea.Y += lineHeight
                        itemIndex += 1
                    Else
                        Exit For
                    End If
                Next
    
                If (itemIndex < listboxItemCount) Then
                    e.HasMorePages = True
                    _startIndex = itemIndex
                    Return
                End If
            End While
    There is definitely a problem with you For loop. This line just keep printing the same thing over and over. "e.Graphics.DrawString(itemText, printFont, Brushes.Black, lineRectangle, textLayout)"

    My guess is it should be something like,

    Code:
    e.Graphics.DrawString(ListBox2.Items(itemIndex).ToString, printFont, Brushes.Black, lineRectangle, textLayout)
    That's just a guess, I didn't do any testing.

  11. #11

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    @wes4dbt - Your guess was genius, it works . Thanks so much for your help on this. I honestly did not realize how difficult it was to print the contents of a listbox until this came up. Thanks again!

  12. #12

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    Quote Originally Posted by .paul. View Post
    I’m not sure what data you have in your ListBox. If you do decide to switch to a DataGridView, check the DataGridView Printing link in my signature below this post…
    @.paul. - I am planning to try out DataGridView as I have never used it for anything. In your experience, is it better than a listbox when just adding smaller amounts of data?

  13. #13
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    26,413

    Re: VB.NET Print total items of ListBox

    DGVs are great for displaying and or editing tabular data. They have many properties and are fully (well, within reason) customizable. Listboxes are great if you just want to display data. They don’t work well with tabular data, so no columns…

  14. #14

    Thread Starter
    Addicted Member
    Join Date
    Jan 2021
    Posts
    191

    Re: VB.NET Print total items of ListBox

    Good info to know. I will for sure look at using the DGV, and even possibly converting this project over to it at some point.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width