本文要介绍在写入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所用到的思路和解决问题的模式,我相信在其他情况下,甚至其他语言中,都可以找到应用的机会。