如何在 vb.net 中打印带有标题的 datagridview 表?

Posted

技术标签:

【中文标题】如何在 vb.net 中打印带有标题的 datagridview 表?【英文标题】:How to print datagridview table with its header in vb.net? 【发布时间】:2017-04-22 06:26:12 【问题描述】:

我正在我正在开发的系统中创建一个打印预览功能,它将预览我想要打印的数据网格视图。我使用了 ooopsoft 的 codes 作为参考,它工作正常,除了一个小问题。

问题:

您可以看到序列号为 1 的 dgv 行丢失了。似乎标题已覆盖第一行。我尝试了无数种方法来解决它,但我仍然找不到解决方案。我尝试退出打印预览对话框并再次打开它,但this 是我得到的结果。我想我错过了一行代码,但我不知道是什么。请帮忙。

【问题讨论】:

我建议你应该尝试使用数据集,我假设你只想得到输出。也许您可以尝试在报告表中每行绑定数据表中的每个数据。它会自动为每个绘制的数据字段创建一个标题。 错误在于For Each cell 循环。如果是(newpage),您可以看到它会打印标题。你需要它来做这两件事;打印新页面的标题然后打印第一行。只需将新页面代码放在自己的循环中即可。 @GNMercado 您的意思是使用 Microsoft Report Viewer 吗?我已经试了一下,但我遇到了一个异常cannot convert sql datetime value to system.datetime 看起来它会将每一页的最后一行复制为下一页的第一行 @Plutonix 我不认为将每一页的最后一行复制到下一页的第一行。在我现在的打印预览中,它从第 39 行变为第 40 行,没有任何重复。 【参考方案1】:

original code 是一个不错的开始,但存在一些错误和效率低下:

当有新页面时,它使用newpage 标志打印标题第一行。显然你真的希望它两者兼得 每页打印一次列标题,因此根本不需要在数据打印循环中 它不允许不可见的列或非默认对齐方式的列,您可能需要考虑其他此类设置。 因为它实际上没有打印正确的行数,一旦你修复它,你会发现它重新打印上一页的最后一行作为新页面的第一行。 有一个内部装订线或边距,因此文本不会打印得太靠近网格线 - 这只是使用 1 或 2 的偏移量 也不必要地使用singleRectangleF 还没有准备好再次显示或打印文档。您还需要在按钮单击或BeginPrint 事件中重置mRownewpage

我添加了一些 cmets 以及为标题行着色并演示了如何实现诸如 RowPrePaint 规则之类的东西。

Private mRow As Integer = 0
Private newpage As Boolean = True

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

    ' sets it to show '...' for long text
    Dim fmt As StringFormat = New StringFormat(StringFormatFlags.LineLimit)
    fmt.LineAlignment = StringAlignment.Center
    fmt.Trimming = StringTrimming.EllipsisCharacter
    Dim y As Int32 = e.MarginBounds.Top
    Dim rc As Rectangle
    Dim x As Int32
    Dim h As Int32 = 0
    Dim row As DataGridViewRow

    ' print the header text for a new page
    '   use a grey bg just like the control
    If newpage Then
        row = dgvZZ.Rows(mRow)
        x = e.MarginBounds.Left
        For Each cell As DataGridViewCell In row.Cells
            ' since we are printing the control's view,
            ' skip invidible columns
            If cell.Visible Then
                rc = New Rectangle(x, y, cell.Size.Width, cell.Size.Height)

                e.Graphics.FillRectangle(Brushes.LightGray, rc)
                e.Graphics.DrawRectangle(Pens.Black, rc)

                ' reused in the data pront - should be a function
                Select Case dgvZZ.Columns(cell.ColumnIndex).DefaultCellStyle.Alignment
                    Case DataGridViewContentAlignment.BottomRight,
                         DataGridViewContentAlignment.MiddleRight
                        fmt.Alignment = StringAlignment.Far
                        rc.Offset(-1, 0)
                    Case DataGridViewContentAlignment.BottomCenter,
                        DataGridViewContentAlignment.MiddleCenter
                        fmt.Alignment = StringAlignment.Center
                    Case Else
                        fmt.Alignment = StringAlignment.Near
                        rc.Offset(2, 0)
                End Select

                e.Graphics.DrawString(dgvZZ.Columns(cell.ColumnIndex).HeaderText,
                                            dgvZZ.Font, Brushes.Black, rc, fmt)
                x += rc.Width
                h = Math.Max(h, rc.Height)
            End If
        Next
        y += h

    End If
    newpage = False

    ' now print the data for each row
    Dim thisNDX As Int32
    For thisNDX = mRow To dgvZZ.RowCount - 1
        ' no need to try to print the new row
        If dgvZZ.Rows(thisNDX).IsNewRow Then Exit For

        row = dgvZZ.Rows(thisNDX)
        x = e.MarginBounds.Left
        h = 0

        ' reset X for data
        x = e.MarginBounds.Left

        ' print the data
        For Each cell As DataGridViewCell In row.Cells
            If cell.Visible Then
                rc = New Rectangle(x, y, cell.Size.Width, cell.Size.Height)

                ' SAMPLE CODE: How To 
                ' up a RowPrePaint rule
                'If Convert.ToDecimal(row.Cells(5).Value) < 9.99 Then
                '    Using br As New SolidBrush(Color.MistyRose)
                '        e.Graphics.FillRectangle(br, rc)
                '    End Using
                'End If

                e.Graphics.DrawRectangle(Pens.Black, rc)

                Select Case dgvZZ.Columns(cell.ColumnIndex).DefaultCellStyle.Alignment
                    Case DataGridViewContentAlignment.BottomRight,
                         DataGridViewContentAlignment.MiddleRight
                        fmt.Alignment = StringAlignment.Far
                        rc.Offset(-1, 0)
                    Case DataGridViewContentAlignment.BottomCenter,
                        DataGridViewContentAlignment.MiddleCenter
                        fmt.Alignment = StringAlignment.Center
                    Case Else
                        fmt.Alignment = StringAlignment.Near
                        rc.Offset(2, 0)
                End Select

                e.Graphics.DrawString(cell.FormattedValue.ToString(),
                                      dgvZZ.Font, Brushes.Black, rc, fmt)

                x += rc.Width
                h = Math.Max(h, rc.Height)
            End If

        Next
        y += h
        ' next row to print
        mRow = thisNDX + 1

        If y + h > e.MarginBounds.Bottom Then
            e.HasMorePages = True
            ' mRow -= 1   causes last row to rePrint on next page
            newpage = True
            Return
        End If
    Next


End Sub

请注意,在 DGV 中有一个 Id 列设置为不可见,Color 列居中,Price 左对齐 - 这些都是从控件中获取的所有设置。另请注意,文本稍微远离网格线。


上面的最后一个要点,您还需要在按钮单击或BeginPrint 事件中重置mRownewpage 意思是:

Private Sub PrintDocument1_BeginPrint(sender As Object, 
          e As PrintEventArgs) Handles PrintDocument1.BeginPrint
    mRow = 0
    newpage = True
    PrintPreviewDialog1.PrintPreviewControl.StartPage = 0
    PrintPreviewDialog1.PrintPreviewControl.Zoom = 1.0
End Sub

预览后,mRow 变量将指示所有行都已打印。如果用户单击打印或返回另一个预览,则不会打印任何内容。此代码还重置要显示的第一页和初始缩放。

【讨论】:

以上是关于如何在 vb.net 中打印带有标题的 datagridview 表?的主要内容,如果未能解决你的问题,请参考以下文章

如果在 vb.net 中有多个页面要打印的数据,如何打印 gridview 内容

如何将带有枚举的 VB.net 接口转换为 C#

如何在带有 VB.net GUI 的 C++ OpenCV 项目中使用 C# 库?

在 vb.net 中使用带有 shouldquote 的 csvhelper writer

如何使用 vb.net 从查询创建访问报告

VB NET 如何暂停打印机队列?