合并单元格

只要是表, 就会存在合并单元格的需求,但PDFCreator的表是通过代码一个一个单元格绘制出来的,不存在行列的概念,当然也就不存在合并单元格的概念

但我们可以换个思路,所谓的合并单元格,不过就是这个单元格其高度跨越了多行(合并行),或宽度跨越了多列(合并列)。

说白了,就是绘制一个比较大的方框而已,只不过需要先计算出这个方框的宽度和高度。

看起来比较复杂,实际上很简单,且PDFCreator这种逐个绘制单元格的方式也有优势,就是绝对精确、绝对可控,绝对不存在兼容性问题 ,所以我个人更喜欢用PDFCreator。

示例一

假定要绘制一个下图所示的表格:

我们可以用一个二维数组表格这个表格,每个元素表示一个单元格,用1表示正常的单元格(正常绘制),0表示这个单元格已经被合并(不需要绘制),用"n,m"表示这是一个合并单元格(合并n行m列)。

例如上面的表格,可用二维数组表示为:

Dim cells(,)As String = {
{
"3,2", "0", "1", "1", "1"}, '第一行,第一个单元格合并了32列 ,第二个单元格被合并了,不需要绘制
{
"0", "0", "1", "4,1", "1"},   '第二行,前两个单元格已经被合并,不需要绘制,第四个单元格合并了41
{
"0", "0", "1", "0", "1"},   '第三行,第1、2和第4个单元格已经被合并,不需要绘制
{
"1", "1", "1", "0", "1"},   '第四行,第4个单元格已经被合并,不需要绘制  
{
"1", "1", "1", "0", "1"}    '第五行,第4个单元格已经被合并,不需要绘制  
}

基于上述逻辑,可以轻松写出生成上述表格的代码:

'定义一个二维数组,一个元素表示一个单元格
Dim
cells(,)As String = {
{
"3,2", "0", "1", "1", "1"},
{
"0", "0", "1", "4,1", "1"},
{
"0", "0", "1", "0", "1"},
{
"1", "1", "1", "0", "1"},
{
"1", "1", "1", "0", "1"}
}

'
下面的代码是通用的,不管表格如何变化,你都不需要修改代码,只需修改前面的二维数组即可:
Dim
file As String = "c:\temp\test.pdf"
Dim
pdc As New PDFCreator()
Dim
rectPage As RectangleF = pdc.PageRectangle
rectPage.Inflate( - 72, - 72)

Dim
rectCell As RectangleF = rectPage
Dim
rowHeight As Integer = 20 '行高
Dim
colWidth As Double = 93.6 '列宽
For
r As Integer = 0 To cells.GetLength(0) - 1 '逐行绘制
   
For c As Integer = 0 To cells.GetLength(1) - 1 '逐一绘制这行的单元格
       
Dim ifo As String = cells(r, c) '从二维数组获得这个单元格的设置信息
       
If ifo = "0" Then
           
'0 不绘制单元格
       
Else
           
If ifo = "1" Then '1正常绘制
                rectCell.Height = rowHeight
                rectCell.Width = colWidth
           
Else 'n,m为合并单元格
               
Dim vls() As String = cells(r, c).Split(",")
               
Dim rowCount As Integer = CInt(vls(0)) '合并行数
               
Dim colCount As Integer = CInt(vls(1)) '合并列数
                rectCell.Height = rowHeight * rowCount
'根据合并行数计算行高
                rectCell.Width = colWidth * colCount
' '根据合并列数计算列宽
           
End If
             pdc.DrawRectangle(pens.Black, rectCell)
'绘制单元格
       
End If
        rectCell.Offset(colWidth, 0)
'右移一列
   
Next
    rectCell.Offset(0, rowHeight)
'下移一行
    rectCell.X = rectPage.X
'单元格回到水平初始位置,准备绘制下一行
Next

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

示例二

上一个例子,行高和列宽都是统一的,如果行高和列宽不一致,例如下面的表格:

可以在上述代码的基础上,增加两个一维数组,一个用于表示行高倍数,一个用于表示列宽,参考代码如下: 

'定义一个二维数组,一个元素表示一个单元格
Dim
cells(,)As String = {
{
"1", "1", "1", "1", "5,1"},
{
"1", "1", "1", "1", "0"},
{
"1", "1", "1", "1", "0"},
{
"1", "1,3", "0", "0", "0"},
{
"1", "1", "1", "1", "0"},
{
"1,5", "0", "0", "0", "0"}
}

Dim
defaultRowHeight As Integer = 28 '默认(单倍)行高
Dim
colWidths() As Double = {50, 130, 50, 130, 128} '各列宽度
Dim
rowTimes() As Integer = {1, 1, 1, 1, 1, 3} '各行的行高倍数,第6行为3倍行高,其他为默认(单倍)行高
'
下面的代码是通用的,不管表格如何变化,你都不需要修改代码,只需修改前面的各数组即可:

Dim file As String = "c:\temp\test.pdf"
Dim
pdc As New PDFCreator()
Dim
rectPage As RectangleF = pdc.PageRectangle
rectPage.Inflate( - 72, - 72)

Dim
rectCell As RectangleF = rectPage
For
r As Integer = 0 To cells.GetLength(0) - 1 '逐行绘制
   
For c As Integer = 0 To cells.GetLength(1) - 1 '逐一绘制这行的单元格
       
Dim ifo As String = cells(r, c)
       
Dim cellHeight As Double = 0 '单元格高度
       
Dim cellWidth As Double = 0 '单元格宽度
       
If ifo = "0" OrElse ifo = "1" Then
            cellHeight = defaultRowHeight * rowTimes(r)
'根据行高倍数计算单元格高度
            cellWidth = colWidths(c)
'取列宽为单元格宽度
       
Else '如果是合并单元格
           
Dim vls() As String = cells(r, c).Split(",")
           
For mr As Integer = r To r + CInt(vls(0)) - 1 '根据合并行数计算单元格高度
                cellHeight = cellHeight + defaultRowHeight * rowTimes(mr)
           
Next
           
For mc As Integer = c To c + CInt(vls(1)) - 1 '根据合并列数计算单元格宽度
                cellWidth = cellWidth + colWidths(mc)
           
Next
       
End If
       
If ifo <> "0" Then '绘制单元格
            rectCell.Height = cellHeight
            rectCell.Width = cellWidth
            pdc.DrawRectangle(pens.Black, rectCell)
'绘制单元格
       
End If
        rectCell.Offset(colWidths(c), 0)
'右移 一列
   
Next
    rectCell.Offset(0, defaultRowHeight * rowTimes(r))
'下移一行
    rectCell.X = rectPage.X
'单元格回到水平初始位置,准备绘制下一行
Next

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

重要提示:

1、 上述代码是通用的,不管表格结构如何变化,也不管表格是简单还是复杂,你都不需要修改代码,你要做的只是修改二维数组的定义。

2、我只是提供一个思路,你可以自由发挥,不要被示例代码约束了思路,例如你可以不用行高倍数,直接指定每一行的高度,就像列宽一样。


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