本文要介绍在写入Excel工作表中单元格值的时候用到的工具类:SheetWriter。获得一个Excel工作表的对象句柄后,写其中的某个单元格本来是很平凡的事。
sheet.Cells(2, 3).Value=”Book”
但是在程序中,批量写大量的连续单元格,就会变得有一些繁琐。在我们之前的报表样例中,如果是采用上面这种直接写的方式,就会类似这样的代码:
…
While Not doc Is Nothing
rowNum = rowNum + 1
‘Write each column in the current row
‘Column book
sheet.Cells(rowNum, 1).Value=doc.Book(0)
‘Column price
sheet.Cells(rowNum, 2).Value=doc.Price(0)
‘Column book number
sheet.Cells(rowNum, 3).Value=doc.BookNumber(0)
…
set doc = dc.GetNextDocument(doc)
Wend
在循环体中,要记得增加记录行数的变量。一般情况下,某一列的值需要做一些特定的计算,无法将列数也像行数一样循环,而是每写一列的值都必须写一次sheet.Cells(rowNum, 2).Value。这样在整个写值的过程中,都必须清楚和操作当前单元格的位置。这样既累人又易出错,特别是当报表比较复杂,牵涉到工作表的不同区域,或是计算列值比较复杂,要放在单独的方法中时。
SheetWriter正是为了解决这个问题而开发的。我们只要调用它的简单的方法,传入要写的值,而无需时刻操心当前单元格的位置。
这个类的字段和方法名称都简单明了,也附有注释。最普通的情况下,只需要创建一个实例writer,将其移动到报表的初始位置MoveTo(),在循环中写值WriteCell(),换行NextRow(),就可以了。其他一些属性和方法,是为了更复杂和特殊的情况。比如当报表的某个部分是需要纵向循环书写的,就可以设置writer的模式为MODE_COLUMN,这是writer每写一个单元格就会往下移动一格,而不是像在普通的横向书写时向右移动一格;写完一列后要换列NextColumn(),还可以设置此时要跳转到的单元格所在的行数,也就是正在被写入的方形区域的上界TopBound。这些应用都在39. 面向对象的LotusScript(十一)之导出Excel(三)里可以看到。
%REM
Class SheetWriter
Description: Comments for Class
%END REM
Public Class SheetWriter
Private sheet As Variant 'xls sheet
Public row As Integer
Private col As Integer
Public LeftBound As Integer 'The most left column of the current region
Public TopBound As Integer 'The most top column of the current region
Public MODE_ROW As Integer 'Write horizontally
Public MODE_COLUMN As Integer 'Write vertically
Public Mode As Integer
%REM
Sub New
Description: Comments for Sub
%END REM
Sub New(xlsSheet As Variant)
Set me.sheet=xlsSheet
me.LeftBound=1
me.TopBound=1
me.row=1
me.col=1
me.MODE_COLUMN=1
me.MODE_ROW=0
me.Mode=me.MODE_ROW
End Sub
%REM
Function WriteCell
Description: Write the current cell and move the cursor to
the right neighbour cell
%END REM
Public Function WriteCell(value As Variant)
sheet.Cells(row, col).Value=value
If me.Mode=me.MODE_ROW then
col=col+1
Else
me.row=me.row+1
End if
End Function
%REM
Function CurrentValue
Description: Comments for Function
%END REM
Public Function CurrentValue()
me.CurrentValue()=sheet.Cells(row, col)
End Function
%REM
Function NextRow
Description: Move the cursor to the next row.
%END REM
Public Function NextRow
row=row+1
col=me.LeftBound
End Function
%REM
Function NextColumn
Description: Move the cursor to the next column
%END REM
Public Function NextColumn
col=col+1
row=me.TopBound
End Function
%REM
Function MoveTo
Description: Move the cursor to the given position.
%END REM
Public Function MoveTo(row As Integer, column As Integer)
me.row=row
me.col=column
End Function
%REM
Function MoveBy
Description: Move the cursor the given number of cells
%END REM
Public Function MoveBy(rows As Integer, columns As Integer)
me.row=me.row+rows
me.col=me.col+columns
End Function
%REM
Function UpdateLeftBound
Description: Update LeftBound with the current column number
%END REM
Public Function UpdateLeftBound()
me.LeftBound=me.col
End Function
%REM
Function UpdateTopBound
Description: Update TopBound with the current row number
%END REM
Public Function UpdateTopBound()
me.TopBound=me.row
End Function
End Class
有了SheetWriter类,我们开始的例子就会变成这样:
…
While Not doc Is Nothing
‘Write each column in the current row
‘Column book
writer.WriteCell(doc.Book(0))
‘Column price
writer.WriteCell(doc.Price(0))
‘Column book number
writer.WriteCell(doc.BookNumber(0))
…
call writer.NextRow()
set doc = dc.GetNextDocument(doc)
Wend
SheetWriter所用到的思路和解决问题的模式,我相信在其他情况下,甚至其他语言中,都可以找到应用的机会。