在 LibreOffice 中使用专门与 Microsoft 工具绑定的解决方案不是一个好主意。您失去了该软件包的主要优势 - 多平台,您的解决方案无法在 Linux 或 MacOS 上运行。
计时器的原理非常简单——一个单独的线程只是简单地倒计时并向您的主代码发出信号。
在 Basic LibreOffice 中,无法创建线程。但 Basic 并不是您唯一可用的编程语言。
让我们看看这个例子。它很旧,但仍然有效。
C:\FakePath\DemoTimer.ods
基本代码不是很复杂
Sub Timermacro
Rem This procedure is called by pressing the START button -
Rem indicates to the timer how often it should work and how many times and starts it.
Dim nTime As Long, nCount As Long
Rem These variables - oJob1 and oP - are described in the adjacent module.
oP = GenerateTimerPropertySet()
oJob1 = createUnoListener("JOB1_", "com.sun.star.task.XJobExecutor")
oP.xJob = oJob1
getParams(nTime, nCount)
oP.lMaxIterations = nCount
oP.lPeriodInMilliSec = nTime * 1000
oP.start()
End Sub
Sub StopTimer
Rem This is the handler for pressing the STOP button. Everything is very simple here.
oP.stop()
End Sub
Function GenerateTimerPropertySet() As Any
Dim oSP As Variant
Dim oScript As Variant
oSP = ThisComponent.getScriptProvider("")
Rem Pay attention to this line - this is the main trick of this solution
Rem The current document (location=document) contain BeanShell code (language=BeanShell))!
Rem It's called timer.bsh and is in the timer library (timer.timer.bsh)
oScript = oSP.getScript("vnd.sun.star.script:timer.timer.bsh?language=BeanShell&location=document")
GenerateTimerPropertySet = oScript.invoke(Array(), Array(), Array())
End Function
Sub JOB1_trigger(s As String)
Rem Here we are simply demonstrating that the timer is doing its job.
Rem After each timer is triggered, add the current date and time and countdown number.
Dim oSheet As Variant
Dim oCursor As Variant
Dim aRangeAddress As New com.sun.star.table.CellRangeAddress
Dim nEndRow As Long
Dim oCellRangeByPosition As Variant
Dim oDataArray As Variant
oSheet = ThisComponent.getSheets().getByIndex(0)
oCursor = oSheet.createCursor()
oCursor.gotoEndOfUsedArea(False)
aRangeAddress = oCursor.getRangeAddress()
nEndRow = aRangeAddress.EndRow+1
oCellRangeByPosition = oSheet.getCellRangeByPosition(0, nEndRow, 1, nEndRow)
oDataArray = oCellRangeByPosition.getDataArray()
oDataArray(0)(0) = Format(Now,"YYYY-MM-DD HH:mm:SS")
oDataArray(0)(1) = s
oCellRangeByPosition.setFormulaArray(oDataArray)
End Sub
Sub getParams(nTime As Long, nCount As Long)
Rem This procedure prepares parameters for the timer.
Rem In this case, they are simply read from the cells of the first sheet of the current book.
Rem But you can set them in any way - ask in the dialog, calculate by the current time,
Rem generate according to a special algorithm, etc.
Dim oSheet As Variant
oSheet = ThisComponent.getSheets().getByIndex(0)
nTime = oSheet.getCellByPosition(4, 4).getValue()
nCount = oSheet.getCellByPosition(4, 5).getValue()
End Sub
解决方案的主要技巧在这里:
基于代码中的一个 cmets,ms777 很久以前就发布了这个,当时 OOO 2.4 还在使用中。已经很难在任何地方找到 OpenOffice,发布此解决方案的站点已经存在很长时间了 - 但该解决方案有效。
我引用 ms777 的代码没有改变,“原样”:
import com.sun.star.uno.Type;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.lib.uno.helper.PropertySet;
import com.sun.star.lib.uno.helper.WeakBase;
import com.sun.star.task.XJobExecutor;
import com.sun.star.lang.XInitialization;
import com.sun.star.beans.PropertyValue;
import com.sun.star.beans.XPropertyChangeListener;
import com.sun.star.beans.PropertyChangeEvent;
import com.sun.star.lang.EventObject;
import com.sun.star.uno.AnyConverter;
import com.sun.star.xml.crypto.sax.XElementStackKeeper ; // defines a start and a stop routine
// Workaround for http://qa.openoffice.org/issues/show_bug.cgi?id=89978 needed from OO 2.4 onwards
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
// This prevents an error message when executing the script a second time
try { Class.forName("ms777Timer_06");}
catch (ClassNotFoundException e) {
System.out.println( "class not found - compiling start" );
public class ms777Timer_06 extends PropertySet implements XElementStackKeeper
{
// These are the properties of the PropertySet
public boolean bFixedRate = true;
public boolean bIsRunning = false;
public int lPeriodInMilliSec = 2000;
public int lDelayInMilliSec = 0;
public int lMaxIterations = 5;
public int lCurrentIteration = 0;
public XJobExecutor xJob = null;
// These are some additional properties
Task xTask =null;
Timer xTimer = null;
public ms777Timer_06() {
registerProperty("bFixedRate", (short) 0);
registerProperty("bIsRunning", (short) com.sun.star.beans.PropertyAttribute.READONLY);
registerProperty("lPeriodInMilliSec", (short) 0);
registerProperty("lDelayInMilliSec", (short) 0);
registerProperty("lMaxIterations", (short) 0);
registerProperty("lCurrentIteration", (short) 0);
registerProperty("xJob", (short) com.sun.star.beans.PropertyAttribute.MAYBEVOID);
xTimer = new Timer();
}
//XElementStackKeeper
public void start() {
stop();
if (xJob==null) {return;}
xTask = new Task();
lCurrentIteration = 1;
bIsRunning = true;
if (bFixedRate) {
xTimer.scheduleAtFixedRate( xTask, (long) lDelayInMilliSec, (long) lPeriodInMilliSec );
} else {
xTimer.schedule( xTask, (long) lDelayInMilliSec, (long) lPeriodInMilliSec );
}
}
public void stop() {
lCurrentIteration = 0;
bIsRunning = false;
if (xTask!=null) { xTask.cancel();}
}
public void retrieve(com.sun.star.xml.sax.XDocumentHandler h, boolean b) { }
class Task extends TimerTask {
public void run() {
xJob.trigger(lCurrentIteration.toString());
lCurrentIteration +=1;
if (lCurrentIteration > lMaxIterations) {
stop();
}
}
}
}
System.out.println( "class not found - compiling end" );
} // of catch (ClassNotFoundException e)
System.out.println( "generating timer property set ... " );
return new ms777Timer_06();
希望这能解决你的问题。