[VB.NET] - 打印DataGridView类

Imports System.Drawing.Printing

Public Class PrintDataGridView

Private WithEvents PrintDocument1 As New Printing.PrintDocument

Private WithEvents PageSetupDialog1 As New System.Windows.Forms.PageSetupDialog

Private WithEvents FontDialog1 As New System.Windows.Forms.FontDialog

Private WithEvents PrintPreviewDialog1 As New System.Windows.Forms.PrintPreviewDialog

Private DGV As DataGridView

Private strTitle As String

Private tsiDisplayStyle As ToolStripItemDisplayStyle = ToolStripItemDisplayStyle.Image

Private tirTextImageRelation As TextImageRelation = Windows.Forms.TextImageRelation.ImageAboveText

Private wInc As Single = 5 'wInc 为单元格宽增量

Private hInc As Single = 5 'hInc 为单元格竖增量

Private MainStartHeigth As Single 'MainStartHeigth 为主体表格起始的高度

Shared pNo As Integer = 1 'pNo 为页码

Private StartHeigth As Single

Private StartPos As Single

Shared hi As Integer = 0

Public PrintFont As Font = New Font("Arial", 16)

Private ColumnsWidth() As Single '数组 ColumnsWidth 为计算后的列宽

Private orgColumnsWidth() As Single '数组 orgColumnsWidth 为原始的最大列宽

Private RowHeigth As Single 'RowHeigth 为计算后的行高

Sub New()

AddHandler PrintDocument1.PrintPage, AddressOf Me.pd_PrintMain

End Sub

'按钮显示方式

'遍历整个表格,得到每列的最大宽度

Private Sub GetLargestWidthOfColumn(ByVal g As System.Drawing.Graphics)

ReDim ColumnsWidth(DGV.Columns.Count - 1) '定义列宽数组的长度

ReDim orgColumnsWidth(DGV.Columns.Count - 1)

For i As Integer = 0 To DGV.Columns.Count - 1

If DGV.Columns(i).Visible = False Then Continue For '如果列为隐藏,不打印

ColumnsWidth(i) = DGV.Columns(i).Width

Next

Dim iC, iR As Integer

For iC = 0 To DGV.Columns.Count - 1

If DGV.Columns(iC).Visible = False Then Continue For '如果列为隐藏,不打印

Dim dc As DataGridViewColumn = DGV.Columns(iC)

'计算列头文字需要的宽

Dim sizeFHeader As Drawing.SizeF

sizeFHeader = g.MeasureString(dc.HeaderText, PrintFont)

If sizeFHeader.Width > ColumnsWidth(iC) Then

orgColumnsWidth(iC) = sizeFHeader.Width

Else

If orgColumnsWidth(iC) > ColumnsWidth(iC) * 3 Then

orgColumnsWidth(iC) = ColumnsWidth(iC) * 3

Else

orgColumnsWidth(iC) = ColumnsWidth(iC)

End If

End If

RowHeigth = sizeFHeader.Height

dc.Dispose()

'计算值的宽

For iR = 0 To DGV.Rows.Count - 1

Dim dr As DataGridViewRow = DGV.Rows(iR)

If dr.Cells(iC).Value IsNot Nothing AndAlso Not IsDBNull(dr.Cells(iC).Value) Then

sizeFHeader = g.MeasureString(dr.Cells(iC).Value.ToString, PrintFont)

If orgColumnsWidth(iC) < sizeFHeader.Width Then

orgColumnsWidth(iC) = sizeFHeader.Width

End If

End If

dr.Dispose()

Next

Next

End Sub

'根据纸张宽度,计算出合适的列宽,返回缩小的比例

Private Function GetFitWidthOfColumn(ByVal pWidth As Single) As Integer

'每列按原始宽度的1%递减,直到适合纸张宽度(pWidth)

Dim l, i, k As Integer

l = orgColumnsWidth.Length

For k = 100 To 1 Step -1

Dim WidthSum As Single = 0

'按比例求宽度

For i = 0 To l - 1

ColumnsWidth(i) = orgColumnsWidth(i) * k / 100

WidthSum += orgColumnsWidth(i) * k / 100 + wInc

Next

If Not WidthSum > pWidth Then

Exit For

End If

Next

Return (k)

End Function

'根据合适的列宽和列宽缩小的比例,计算出合适的行高

Private Sub GetFitHeightOfRow(ByVal pScale As Integer)

RowHeigth = RowHeigth * Fix((100 / pScale) + 1) + hInc

End Sub

'打印主体

Private Sub pd_PrintMain(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)

Dim g As Graphics = e.Graphics

'如果是第一页,计算长宽

If pNo = 1 Then

GetLargestWidthOfColumn(g)

GetFitHeightOfRow(GetFitWidthOfColumn(e.MarginBounds.Width))

End If

'添加DataGridView主体

'计算标题的高度,预留空间

Dim sizeFTitle As Drawing.SizeF

sizeFTitle = e.Graphics.MeasureString(Title, New Font("宋体", 30, FontStyle.Bold))

MainStartHeigth = sizeFTitle.Height + e.MarginBounds.Top

StartHeigth = MainStartHeigth

'-------------------再来开始------------------------

'添加列头,按已经求出的最长宽度

'起始位置为纸张可打印边框的左边

StartPos = e.MarginBounds.Left

Dim i As Integer

For i = 0 To DGV.Columns.Count - 1

'如果列为隐藏,不打印

If DGV.Columns(i).Visible = False Then

Continue For

End If

Dim dc As DataGridViewColumn

dc = DGV.Columns(i)

Dim sizeFHeader As New Drawing.SizeF

sizeFHeader = e.Graphics.MeasureString(dc.HeaderText, PrintFont, ColumnsWidth(i)) '写表头

g.DrawString(dc.HeaderText, PrintFont, Drawing.Brushes.Black, New RectangleF(StartPos + wInc, StartHeigth + hInc, ColumnsWidth(i) - wInc, RowHeigth - hInc)) '添加外边框

g.DrawLine(Pens.Black, StartPos, StartHeigth, StartPos + ColumnsWidth(i), StartHeigth) '上

g.DrawLine(Pens.Black, StartPos, StartHeigth, StartPos, StartHeigth + RowHeigth) '左

StartPos += ColumnsWidth(i)

Next '添加主体

StartHeigth += RowHeigth

While hi < DGV.Rows.Count And StartHeigth < e.MarginBounds.Height

StartPos = e.MarginBounds.Left

Dim obj As New Object

Dim wi As Integer = 0

For wi = 0 To DGV.Columns.Count - 1

If DGV.Columns(wi).Visible = False Then Continue For '如果列为隐藏,不打印

Dim dcWidth As Single

dcWidth = ColumnsWidth(wi)

g.DrawLine(Pens.Black, StartPos, StartHeigth, StartPos + dcWidth, StartHeigth) '上

g.DrawLine(Pens.Black, StartPos, StartHeigth, StartPos, StartHeigth + RowHeigth) '左

StartPos += dcWidth

Try

If Not IsDBNull(DGV.Rows(hi).Cells(wi).Value) Then

g.DrawString(DGV.Rows(hi).Cells(wi).Value.ToString(), PrintFont, Drawing.Brushes.Black, New RectangleF(StartPos - dcWidth + 2, StartHeigth + 3, dcWidth + 2, RowHeigth))

End If

Catch ex As Exception

MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error)

End Try

Next

StartHeigth += RowHeigth

hi += 1

End While

'如果是第一页,添加表头

'根据绘制表格的宽度添加标题()

If pNo = 1 Then

If StartPos - e.MarginBounds.Left < sizeFTitle.Width Then

'如果标题的宽度大于表格的宽度,则缩小标题字号

For i = 30 To 1 Step -1

sizeFTitle = e.Graphics.MeasureString(Title, New Font("宋体", i, FontStyle.Bold))

If sizeFTitle.Width < StartPos - e.MarginBounds.Left Then

g.DrawString(Title, New Font("宋体", i, FontStyle.Bold), Brushes.Black, (StartPos - e.MarginBounds.Left - sizeFTitle.Width) / 2 + e.MarginBounds.Left, (MainStartHeigth - sizeFTitle.Height) / 2)

Exit For

End If

Next

Else

g.DrawString(Title, New Font("宋体", 30, FontStyle.Bold), Brushes.Black, (StartPos - e.MarginBounds.Left - sizeFTitle.Width) / 2 + e.MarginBounds.Left, (MainStartHeigth - sizeFTitle.Height) / 2)

End If

End If

g.DrawLine(Pens.Black, e.MarginBounds.Left, StartHeigth, StartPos, StartHeigth) '封底

g.DrawLine(Pens.Black, StartPos, MainStartHeigth, StartPos, StartHeigth) '封右边

If StartHeigth + RowHeigth > e.MarginBounds.Height And hi < DGV.Rows.Count Then

e.HasMorePages = True

pNo += 1 '页码加1

StartPos = e.MarginBounds.Left

StartHeigth = e.MarginBounds.Top

Else

e.HasMorePages = False

End If '结尾标志

'If hi.Equals(dgv.Rows.Count) Then 'And e.HasMorePages.Equals(False) Then

If hi >= DGV.Rows.Count Then 'And e.HasMorePages.Equals(False) Then

hi = 0

pNo = 1

Exit Sub

End If

End Sub

'数据源,输入DataGridView

Public Property MyDataGridView() As DataGridView

Set(ByVal value As DataGridView)

DGV = value

End Set

Get

Return DGV

End Get

End Property

'报表标题

Public Property Title() As String

Set(ByVal value As String)

strTitle = value

End Set

Get

Return strTitle

End Get

End Property

'页面设置

Public Sub PageSetup()

Me.PageSetupDialog1.Document = Me.PrintDocument1

Me.PageSetupDialog1.ShowDialog()

Me.PrintDocument1.DefaultPageSettings = Me.PageSetupDialog1.PageSettings

End Sub

'打印预览

Public Sub PrintPreview()

Me.PrintPreviewDialog1.Document = Me.PrintDocument1

Me.PrintPreviewDialog1.ShowDialog()

End Sub

'设置字体

Public Sub PrintPreviewFont()

Me.FontDialog1.ShowDialog()

PrintFont = Me.FontDialog1.Font

End Sub

'打印

Public Sub Print()

Me.PrintDocument1.Print()

End Sub

End Class