打印关联表之二

请先打开CaseStyudy目录下的文件"PDFCreator示例.Table"再运行本节的示例代码。

出库表和出库明细表通过出库单号建立了关联,其中出库表为父表,出库明细表为子表。

本节的任务还是用PDFCreator打印一个出库单:

上一节我们已经完成了这个任务,其中来自出库表表的数据采用了手工定位的方式,过程清晰易懂。

但有的场景,来自主表(这里是出库表)的内容很多,如果继续采用手工定位的方式,工作量会随内容的增加而同比增加,且后续需要改变布局的时候,需要调整大量的代码。

所以这一节提供了另一种方式,这个方式不会因为布局的变动和内容的增加而修改代码,这个方式我们之前讲过,参考:合并单元格实战

整个出库单的内容可以当做一个表格来处理:

这个表格的数据来自两个数据表,前三行和最后一行来自出库表,中间的数据来自于出库明细表。

所以我们可以将出库单的打印拆分成两个任务,一部分来自出库表,一部分来自出库明细表,其中来自出库表的部分为:

只需在打印该表格的最后一行之前,先打印出库明细,即可完成任务,如此一来,我们的思路就清晰了 ,步骤为:

1、参考合并单元格实战,打印上图的四行表格。

2、在打印上图表格的最后一行(第四行)之前,插入打印出库明细的代码,参考:打印数据表

不过还有一个问题,在上图的表格中,不同的单元格字体不同,水平对齐方式也不同。

单元格的水平对齐方式,我们当然可以新增一个二维数组来表示之,但是这次我采用不同的方式,在定义表示单元格的二维数组时,加上前缀符号表示单元格的对齐方式, "<"表示左对齐,">"表示右对齐,"="表示居中对齐。

示例

因为同时要实现合并单元格和打印数据表,所以代码有点长,前面的代码是原样从打印数据表这一节复制过来的,后半节的代码因为要通过二维数组指定单元格对齐方式,所以在合并单元格这一节的基础上有所调整。

考虑到这个代码是通用的,以后类似的打印需求都可以用下面的代码完成,所以还是值得花点时间消化的:

Dim file As String = "c:\temp\test.pdf"
Dim
pdc As New PDFCreator()
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("微软雅黑", 10) '列标题字体
Dim
fontData As New Font("微软雅黑", 10) '数据单元格字体
'
绘制列标题的lambda过程,注意这里有变动,首先不需要填充背景了,其次字体颜色改为黑色
Dim
drawHeader =
Function
(tFields() 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 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
        pdc.DrawString(tFields(c), fontHeader, Color.Black, rectContent, sf)
'绘制单元格内容(列标题)
        rectBorder.Offset(rectBorder.Width, 0)
'rectBorder右移到下一个列标题位置
   
Next
    tRect.Offset(0, tRect.Height)
'移动到下一个内容的起始位置
   
Return tRect '返回rect
End
Function
'
绘制行的lambda过程,dr为要绘制的DataRowtFields为列名,tWidths为列宽,tRect为改行所在的矩形局域
Dim
drawRow =
Function
(dr As DataRow, tFields() As String, tWidths() As Integer, tRect As RectangleF)
    tRect.Height = rowHeight
'设置行高
   
If tRect.Bottom > rectPage.Bottom Then '如果剩余空间不够
        pdc.NewPage()
'则另起一页
        tRect.Y = rectPage.Y
'定位到页首
        tRect = drawHeader.Invoke(tFields, 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
pr As DataRow = Tables("出库").Current.DataRow
Dim
cells(, ) As String = {
{
"=1,6", 0, 0, 0, 0, 0},
{
"<1,6", 0, 0, 0, 0, 0},
{
"<1,2", "0", "=1,2", "0", ">1,2", "0"},
{
"<1,3", "0", "0", ">1,3", "0", "0"}
}

Dim
contents(,) As String =
{
{
"湛江辉迅出库单", "", "", "", "", ""},
{
"出库单号:" & pr("出库单编号"), "", "", "", "", ""},
{
"领用部门:" & pr("领用部门"), "", "出库日期:" & pr("出库日期"), "", "领料人:" & pr("领料人"), ""},
{
"库管员:" & pr("库管员"), "", "", "合计:" & pr("数量"), "", ""}
}

Dim
fields() As String = {"商品代码", "商品名称", "规格", "单位", "数量", "备注"} '来自出库明细的列
Dim
Widths() As Integer = {78, 78, 78, 78, 78, 78} '列宽
Dim
Heights() As Double = {25, 20, 20, 20} '行高,第一行为出库单标题,比其他行高一点
Dim
rect As RectangleF = rectPage 'rect将传递给所有用于绘制的lambda过程的tRect参数,相当于一个位置游标,始终都在动态变化中
For
r As Integer = 0 To cells.GetLength(0) - 1 '逐行绘制
   
If r = 3 Then '在打印第四行之前 ,先打印出库明细
        rect = drawHeader.Invoke(fields, Widths, rect)
       
For Each cr As DataRow In pr.GetChildRows("出库明细") '逐行绘制
            rect = drawRow.Invoke(cr, fields, widths, rect)
'绘制行
       
Next
   
End If
   
For c As Integer = 0 To cells.GetLength(1) - 1 '逐一绘制这行的单元格
       
Dim ifo As String = cells(r, c)
       
If ifo = "0" Then
           
'0 不绘制单元格
       
Else
           
Dim align As String = ifo.Substring(0, 1).Trim()
           
Select Case align '设置水平对齐方式
               
Case "<"
                    sf.Alignment = StringAlignment.Near
               
Case ">"
                    sf.Alignment = StringAlignment.Far
               
Case "="
                    sf.Alignment = StringAlignment.Center
           
End Select
            ifo = ifo.Substring(1)
           
If ifo = "1" Then '1正常绘制
                rect.Height = Heights(r)
                rect.Width = Widths(c)
           
Else 'n,m为合并单元格
               
Dim cellHeight As Double = 0
               
Dim cellWidth As Double = 0
               
Dim vls() As String = ifo.Split(",")
               
Dim rowCount As Integer = CInt(vls(0)) '合并行数
               
Dim colCount As Integer = CInt(vls(1)) '合并列数
               
For mr As Integer = r To r + rowCount - 1 '根据合并行数计算单元格高度
                    cellHeight = cellHeight + Heights(mr)
               
Next
               
For mc As Integer = c To c + colCount - 1 '根据合并列数计算单元格宽度
                    cellWidth = cellWidth + Widths(mc)
               
Next
                rect.Height = cellHeight
                rect.Width = cellWidth
           
End If
           
Dim content As String = contents(r, c)
           
If content > "" Then
               
Dim rectContent As RectangleF = rect
               
Dim cellFont As Font = fontData
               
If r = 0 Then '第一行是标题,字体加大加粗
                    cellFont =
New Font("微软雅黑", 16, fontstyle.Bold)
               
End If
                rectContent.Inflate( - 3, - 3)
'单元格内容边距为3
                pdc.DrawString(content, cellFont, color.Black, rectContent, sf)
'绘制单元格文本
           
End If
           
'pdc.DrawRectangle(pens.Black, rect) '绘制单元格
       
End If
        rect.Offset(Widths(c), 0)
'右移一列
   
Next
    rect.Offset(0, Heights(r))
'下移一行
    rect.X = rectPage.X
'单元格回到水平初始位置,准备绘制下一行
Next

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

 

 


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