合并单元格
只要是表, 就会存在合并单元格的需求,但PDFCreator的表是通过代码一个一个单元格绘制出来的,不存在行列的概念,当然也就不存在合并单元格的概念
但我们可以换个思路,所谓的合并单元格,不过就是这个单元格其高度跨越了多行(合并行),或宽度跨越了多列(合并列)。
说白了,就是绘制一个比较大的方框而已,只不过需要先计算出这个方框的宽度和高度。
看起来比较复杂,实际上很简单,且PDFCreator这种逐个绘制单元格的方式也有优势,就是绝对精确、绝对可控,绝对不存在兼容性问题 ,所以我个人更喜欢用PDFCreator。
示例一
假定要绘制一个下图所示的表格:
我们可以用一个二维数组表格这个表格,每个元素表示一个单元格,用1表示正常的单元格(正常绘制),0表示这个单元格已经被合并(不需要绘制),用"n,m"表示这是一个合并单元格(合并n行m列)。
例如上面的表格,可用二维数组表示为:
Dim
cells(,)As
String
= {
{"3,2",
"0",
"1",
"1",
"1"},
'第一行,第一个单元格合并了3行2列
,第二个单元格被合并了,不需要绘制
{"0",
"0",
"1",
"4,1",
"1"},
'第二行,前两个单元格已经被合并,不需要绘制,第四个单元格合并了4行1列
{"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、我只是提供一个思路,你可以自由发挥,不要被示例代码约束了思路,例如你可以不用行高倍数,直接指定每一行的高度,就像列宽一样。