在Excel VBA中迭代一个类

我为一个名为Terminal的实体创build了一个类模块。 我有一个方法来填充这个类,通过175个单独的工作表,并从特定的单元格中提取正确的数据。 这个过程非常快(大约2秒),但是当我尝试将这个数据写回到一个新的工作表时,它花费了更长的时间(45秒)。 看起来,这个过程应该像填充课程一样快,因为它永远不必离开工作表,但事实并非如此。 下面是我用来将数据写入工作表的过程,我是否忽略了导致它运行得太慢的原因?

Application.ScreenUpdating = False Dim rowNumber As Integer Dim colNumber As Integer Dim terminalCode As String Dim terminal As clsTerminal rowNumber = 7 colNumber = 1 For Each terminal In terminals 'Add hyperlink to each terminal code Sheets("Terminal Summary").Hyperlinks.Add Anchor:=Cells(rowNumber, colNumber), Address:="", _ SubAddress:=terminal.terminalCode + "!A1", TextToDisplay:=terminal.terminalCode Sheets("Terminal Summary").Cells(rowNumber, colNumber + 1).Value = "Current" 'Current period Sheets("Terminal Summary").Cells(rowNumber, colNumber + 2).Value = terminal.iBShipments Sheets("Terminal Summary").Cells(rowNumber, colNumber + 3).Value = terminal.oBShipments Sheets("Terminal Summary").Cells(rowNumber, colNumber + 4).Value = terminal.iBNetRevenue Sheets("Terminal Summary").Cells(rowNumber, colNumber + 5).Value = terminal.oBNetRevenue Sheets("Terminal Summary").Cells(rowNumber, colNumber + 6).Value = terminal.iBWeight Sheets("Terminal Summary").Cells(rowNumber, colNumber + 7).Value = terminal.oBWeight Sheets("Terminal Summary").Cells(rowNumber, colNumber + 8).Value = terminal.iBMileage Sheets("Terminal Summary").Cells(rowNumber, colNumber + 9).Value = terminal.oBMileage Sheets("Terminal Summary").Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 11).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 12).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 13).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 14).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8] / 100),0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 15).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8] / 100),0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 16).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" Sheets("Terminal Summary").Cells(rowNumber, colNumber + 17).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" rowNumber = rowNumber + 1 Next terminal 

编辑我应该注意到terminal是terminal类的集合

这种types的代码常见的缺陷是,每次向电子表格写入数据时,Excel都会运行一个计算(它将评估工作簿中的所有公式,以查看是否需要使用新数据计算它们)。

如果在循环之前禁用自动计算,然后重新启用它,事情将会更快:

 Application.Calculation = xlCalculationManual For Each terminal In terminals ... Next terminal Application.Calculation = xlCalculationAutomatic 

你已经有了很大的节约(在写作时关掉自动计算),但是还有其他一些小技巧要记住。

首先,每次从VBA写入一个单元格时,都会由于VBA进入工作簿/表单/单元格地址并执行写入而导致开销。 在一次通话中写入多个信元只会导致一次开销。 因此,将几个值打包到一个数组中,并将这个数组写入多个单元格会获得时间 不值得几行,但值得数百努力。

而且,每个“点”还有一点额外的开销。 如“ Sheets("Terminal Summary").Cells(rowNumber, colNumber + 2)中的“点”expression式的Sheets("Terminal Summary").Cells(rowNumber, colNumber + 2)需要Excel / VBA来确定每个调用中涉及哪些对象。 在某些情况下(特别是在引用远程对象时),开销可能很大。 VB为我们提供了With...End With结构,以减lessparsing这些引用的需要:以点开头的每个expression式自动引用下一个最外面的With的对象。

所以我们可能会得到这样的东西:

 With Sheets("Terminal Summary") .Cells(rowNumber, colNumber + 2).Resize(1, 8) = terminal.InfoArray .Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" .Cells(rowNumber, colNumber + 11).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" .Cells(rowNumber, colNumber + 12).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" .Cells(rowNumber, colNumber + 13).FormulaR1C1 = "=IFERROR(RC[-8]/RC[-10],0)" .Cells(rowNumber, colNumber + 14).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8] / 100),0)" .Cells(rowNumber, colNumber + 15).FormulaR1C1 = "=IFERROR(RC[-10]/(RC[-8] / 100),0)" .Cells(rowNumber, colNumber + 16).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" .Cells(rowNumber, colNumber + 17).FormulaR1C1 = "=IFERROR(RC[-12]/RC[-8],0)" End With 

我将这个数组放入terminal类,如下所示:

 Public Property Get InfoArray() As Variant InfoArray = Array(iBShipments, oBShipments, iBNetRevenue, oBNetRevenue, iBWeight, oBWeight, iBMileage, oBMileage) End Property 

在terminal信息全部完成之后,可以通过每列写入一次公式来更高效地输出公式。

有些事情要考虑,至less…

你已经有了90%的答案,但是这里还有一个性能提示。 而不是做:

 Sheets("Terminal Summary").Cells(rowNumber, colNumber + 10).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)" 

你可以使用这样一个事实,即将同一个公式分配给列中的所有单元格,并用一个语句来完成:

 Sheets("Terminal Summary").Cells(7, 11).Resize(terminals.Count, 1).FormulaR1C1 = "=IFERROR(RC[-4]/RC[-8],0)"