多层表头

请先打开CaseStyudy目录下的文件"PDFCreator示例.Table",然后选择"多层表头"这个表,再运行本节的示例代码。

本节的任务还是打印数据表,不过这次是要打印一个有多层表头的数据表,打印结果如下:

多层表头打印的思路来自合并分单元格以及合并单元格实战,首先定义两个二维数组表示多层表头:

Dim HeaderCells(, ) As String = {
{
"2,1", "1,4", "0", "0", "0", "1,4", "0", "0", "0"},
{0,
"1", "1", "1", "1", "1", "1", "1", "1"}
}

Dim HeaderCaptions(, ) As String = {
{
"产品", "东部", "", "", "", "南部", "", "", ""},
{
"", "一季度", "二季度", "三季度", "四季度", "一季度", "二季度", "三季度", "四季度"}
}

然后重写drawHeader过程, 使其支持多层表头:

Dim drawHeader =
Function
(tHeaderCells(,) As String , tHeaderCaptions(,) As String, tWidths() As Integer, tRect As RectangleF)
   
'代码
End
Function

因为drawRow过程有调用drawHeader,所以这个过程也要稍微修改一下,加上两个表示表头的二维数组作为参数:

Dim drawRow =
Function
(dr As DataRow, tFields() As String, tWidths() As Integer, tHeaderCells(,) As String , tHeaderCaptions(,) As String, tRect As RectangleF)
    tRect.Height = rowHeight
'设置行高
   
If tRect.Bottom > rectPage.Bottom Then '如果剩余空间不够
        pdc.NewPage()
'则另起一页
        tRect.Y = rectPage.Y
'定位到页首
        tRect = drawHeader.Invoke(tHeaderCells, tHeaderCaptions, tWidths, tRect)
'给新增加的页面绘制表头
   
End If
    '其他代码
End
Function

示例

下面是完整的代码,请在命令窗口执行,同样这个代码是通用的,你可以用于打印任何有多层表头的数据表:

Dim file As String = "c:\temp\test.pdf"
Dim
pdc As New PDFCreator()
pdc.PaperKind = Drawing.Printing.PaperKind.A3

Dim
rectPage As RectangleF = pdc.PageRectangle
rectPage.Inflate( - 72, - 72)

Dim
sf As New StringFormat
sf.LineAlignment = StringAlignment.Center
'单元格内容垂直居中
Dim
rowHeight As Integer = 20 '行高为20
Dim
fontHeader As New Font("微软雅黑", 12, fontstyle.Bold) '列标题字体
Dim
fontData As New Font("微软雅黑", 10) '数据单元格字体

'
绘制列标题的lambda过程,支持多层表头
Dim
drawHeader =
Function
(tHeaderCells(,) As String , tHeaderCaptions(,) As String, tWidths() As Integer, tRect As RectangleF)
    tRect.Height = rowHeight
'设置行高
   
If tRect.Bottom > rectPage.Bottom Then '如果剩余空间不够
        pdc.NewPage()
'则另起一页
        tRect.Y = rectPage.Y
''定位到页首
   
End If
   
Dim rectBorder = tRect 'rectBorder为单元格边框矩形
    sf.Alignment = StringAlignment.Center
'列标题水平居中
   
For r As Integer = 0 To tHeaderCells.GetLength(0) - 1 '逐行绘制
       
For c As Integer = 0 To tHeaderCells.GetLength(1) - 1 '逐一绘制这行的单元格
           
Dim ifo As String = tHeaderCells(r, c)
           
Dim cellHeight As Double = 0 '单元格高度
           
Dim cellWidth As Double = 0 '单元格宽度
           
If ifo = "0" OrElse ifo = "1" Then
                cellHeight = rowHeight
'
                cellWidth = tWidths(c)
'
           
Else '如果是合并单元格
               
Dim vls() As String = tHeaderCells(r, c).Split(",")
                cellHeight = rowHeight *
CInt(vls(0))
               
For mc As Integer = c To c + CInt(vls(1)) - 1 '根据合并列数计算单元格宽度
                    cellWidth = cellWidth + tWidths(mc)
               
Next
           
End If
           
If ifo <> "0" Then '绘制单元格
                rectBorder.Height = cellHeight
                rectBorder.Width = cellWidth
                pdc.DrawRectangle(pens.DarkGray, rectBorder)
'绘制单元格
               
If tHeaderCaptions(r, c) > "" Then
                   
Dim rectContent As RectangleF = rectBorder
                    rectContent.Inflate( - 3, - 3)
                    pdc.DrawString( tHeaderCaptions(r, c) , fontHeader, color.Black, rectContent, sf)
               
End If
           
End If
            rectBorder.Offset(tWidths(c), 0)
'右移一列
       
Next
        rectBorder.Offset(0, rowHeight)
'下移一行
        rectBorder.X = rectPage.X
'单元格回到水平初始位置,准备绘制下一行
        tRect.Offset(0, tRect.Height)
'移动到下一行位置
   
Next
   
Return tRect '返回rect
End
Function

'
绘制行的lambda过程,dr为要绘制的DataRowtFields为列名,tWidths为列宽,tRect为改行所在的矩形局域,tHeaderCells和tHeaderCaptions两个二维数组用于表示表头
Dim
drawRow =
Function
(dr As DataRow, tFields() As String, tWidths() As Integer, tHeaderCells(,) As String , tHeaderCaptions(,) As String, tRect As RectangleF)
    tRect.Height = rowHeight
'设置行高
   
If tRect.Bottom > rectPage.Bottom Then '如果剩余空间不够
        pdc.NewPage()
'则另起一页
        tRect.Y = rectPage.Y
'定位到页首
        tRect = drawHeader.Invoke(tHeaderCells, tHeaderCaptions, tWidths, tRect)
'给新增加的页面绘制表头
   
End If
   
Dim rectBorder = tRect '单元格边框矩形
   
For c As Integer = 0 To tFields.Length - 1 '逐个列绘制
        rectBorder.Width = tWidths(c)
'设置列宽
        pdc.DrawRectangle(pens.DarkGray, rectBorder)
'绘制单元格边框
       
Dim rectContent As RectangleF = rectBorder '内容矩形
        rectContent.Inflate( - 3, - 3)
'单元格边距为3
       
If dr.DataTable.DataCols(tFields(c)).IsNumeric Then '如果是数值列
            sf.Alignment = StringAlignment.Far
'水平靠右对齐
       
Else
            sf.Alignment = StringAlignment.Near
'否则居中对齐
       
End If
        pdc.DrawString(dr(tFields(c)), fontData, Color.Black, rectContent, sf)
'绘制单元格内容
        rectBorder.Offset(rectBorder.Width, 0)
''rectBorder右移到下一个单元格位置
   
Next
    tRect.Offset(0, tRect.Height)
'移动到下一个内容的起始位置
   
Return tRect '返回rect
End
Function  

'用于定义多层表头的两个二维数组
Dim
HeaderCells(, ) As String = {
{
"2,1", "1,4", "0", "0", "0", "1,4", "0", "0", "0"},
{0,
"1", "1", "1", "1", "1", "1", "1", "1"}
}

Dim
HeaderCaptions(, ) As String = {
{
"产品", "东部", "", "", "", "南部", "", "", ""},
{
"", "一季度", "二季度", "三季度", "四季度", "一季度", "二季度", "三季度", "四季度"}
}

Dim
fields() As String = {"产品", "东部_一季度", "东部_二季度", "东部_三季度", "东部_四季度", "南部_一季度", "南部_二季度", "南部_三季度", "南部_四季度"}
Dim
Widths() As Integer = {92, 72, 72, 72, 72, 72, 72, 72, 72}
Dim
rect As RectangleF = rectPage 'rect将传递给所有用于绘制的lambda过程的tRect参数,相当于一个位置游标,始终都在动态变化中
rect = drawHeader.Invoke(HeaderCells, HeaderCaptions, widths, rect)
'绘制列标题
For
Each r As Row In Tables("多层表头").Rows '逐行绘制
    rect = drawRow.Invoke(r.DataRow, fields, widths, HeaderCells, HeaderCaptions, rect)
'绘制行
Next

pdc.Save(file)
'保存文件
Process.Start(file)
'打开文件

 


本页地址:http://www.foxtable.com/webhelp/topics/6123.htm