gpt4 book ai didi

performance - 如何加速更新多个单元格的 OpenOffice Calc 宏?

转载 作者:行者123 更新时间:2023-12-04 02:35:42 25 4
gpt4 key购买 nike

我有一个 OpenOffice Calc 宏(在 Basic 中),它将事件工作表中的所有数字四舍五入到给定的小数位数。处理 9000 行电子表格的 100 行大约需要 4 秒。每行有 35 列,其中 19 列是数字。

我怎样才能让这个执行得更快?这是我为 OpenOffice 编写的第一个宏,所以很可能有我从未听说过的更快的方法。这是我的代码:

Dim oFunction as Object 


' Round all Value cells (cells that do not contain Text or Functions) on the current sheet to as many decimal places as user requests.
Sub RoundUsedCells

Dim oSheet As Object, oUsedRange as Object, oCursor as Object, oCell As Object
Dim row, column,lastRow, lastColumn
Dim places$, placesToRound
Dim roundedValue as Double

' Ask user how many decimal places to round
places$ = InputBox ("Round to how many places (leave blank to cancel)?")
if (places$ is Nothing or places$ = "") then
' Do nothing.
else
placesToRound = CInt(places$)

' Get the currently active sheet.
oSheet = thiscomponent.getcurrentcontroller.activesheet

' Create a one cell range at the origin,
' then create a cursor that allows us to extend the range to include all the "used" cells.
' The cursor will then allow us to find out how large is that used range.
oUsedRange = oSheet.getCellRangeByPosition(0,0,0,0)
oCursor = oSheet.createCursorByRange(oUsedRange)
oCursor.GotoEndOfUsedArea(false)

' Obtain the last rows and colums in the "used" range from the cursor.
lastRow = oCursor.RangeAddress.EndRow
lastColumn = oCursor.RangeAddress.EndColumn

' Loop through all cells from the origin (0,0) to the last used column and row.
for row = 0 to lastRow
if (row mod 50 = 0) then
StatusBar "Rounding row " + (row + 1) + " of " + (lastRow + 1) + "..."
endif
for column = 0 to lastColumn
oCell = oSheet.getCellByPosition(column, row)
Select Case oCell.Type
Case com.sun.star.table.CellContentType.VALUE
' Only round value cells. Skip over empty cells, formuls and text.
roundedValue = Round(oCell.Value, placesToRound)
if (roundedValue <> oCell.Value) then
oCell.Value = roundedValue
endif
Case com.sun.star.table.CellContentType.EMPTY
Case com.sun.star.table.CellContentType.TEXT
Case com.sun.star.table.CellContentType.FORMULA

End Select
next column
next row
StatusBar "Rounding complete."
endif
End Sub

' Obtain access to worksheet functions, such as the "round" function.
Sub InitRound
if (oFunction is Nothing) then
oFunction = createUnoService("com.sun.star.sheet.FunctionAccess")
endif
End Sub

' Round the value to the given number of places after the decimal.
Function Round(value, decimalPlaces)
InitRound()
Dim args( 1 to 2 ) As Variant
args(1) = value
args(2) = decimalPlaces
Round = oFunction.callFunction( "round", args() )
End Function

global vStatusBarText as string '=text that is been displayed on the statusbar
sub StatusBar(optional vNewText, optional vAddText) 'set or add text to the statusbar, nothing = clear&reset it.
if isError(vNewText) then
if isError(vAddText) then 'clear statusbar
vStatusBarText=""
else 'add text to the previous statusbar
vStatusBarText=vStatusBarText & vAddText
endif
else
if isError(vAddText) then 'use new text
vStatusBarText=vNewText
else 'use new text and add the other text as well
vStatusBarText=vNewText & vAddText
endif
endif
vStatusBarText=right(vStatusBarText,int(ThisComponent.CurrentController.VisibleArea.Width/150)) 'Select last part that could be displayed.
if isNull(ThisComponent.CurrentController) then exit sub 'Because the last XEventListener-event can't be written to the statusbar, because it's no longer there!
if vStatusBarText="" then 'reset statusbar
ThisComponent.CurrentController.StatusIndicator.Reset
else 'change the text in the statusbar
ThisComponent.CurrentController.StatusIndicator.Start(vStatusBarText,0)
endif
end sub

更新:我重写了 Round 以不调用 Calc,这使速度提高了一倍。还是太慢了。必须比每秒五十行好得多。
Function Round2(value, decimalPlaces) as Double
Round2 = Int(value * 10 ^ decimalPlaces + 0.5) / 10 ^ decimalPlaces
'Dim multiplier as Double, bigValue as Double
'multiplier = 10 ^ decimalPlaces
'bigValue = (value * multiplier) + 0.5
'Round2 = CDbl( CLng(bigValue) ) / multiplier
End Function

更新 2:

找到了一种在宏执行期间禁用自动更新和屏幕刷新的方法,这使速度再次提高了三倍(现在是每秒 200 行):
myDoc = ThisComponent
myDoc.lockControllers()
myDoc.addActionLock()
' --- modify your cells here ---
myDoc.removeActionLock()
myDoc.unlockControllers()

最佳答案

我的计时测试表明您最大的问题是您一次访问一个单元格。我的测试表明有两种方法可以显着增加这种类型的操作。

最有效的方法是使用一些本地工具来做到这一点;例如,将显示样式设置为以特定格式显示,如果可能,将在指定点处舍入显示。

下一个最佳解决方案是分块获取数据并分块更新数据。您用于获取数据的方法将取决于数据的一致性。例如, getDataArray() 和 setDataArray() 可能比一次查看一个单元格快大约 100 倍(至少)。这里有两种不同的可能方法:

getData() 将获取数值数据作为嵌套的值序列(数组中的数组)。

getDataArray() 与 getData() 相同,但可能包含 String 或 Double。

关于performance - 如何加速更新多个单元格的 OpenOffice Calc 宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12148323/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com