How to do it in Libreoffice-Calc?
OnTime for less than 1 second without becoming Unresponsive
This is the solution:
Declare PtrSafe Function SetTimer Lib "user32" (ByVal hWnd As LongPtr, _
ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
Declare PtrSafe Function KillTimer Lib "user32" (ByVal hWnd As LongPtr, _
ByVal nIDEvent As LongPtr) As Long
Public TimerID As Long
Sub StartTimer()
' Run TimerEvent every 100/1000s of a second
TimerID = SetTimer(0, 0, 100, AddressOf TimerEvent)
End Sub
Sub StopTimer()
KillTimer 0, TimerID
End Sub
Sub TimerEvent()
On Error Resume Next
Cells(1, 1).Value = Cells(1, 1).Value + 1
End Sub
It would be great if everything worked under different OS
Here is a python macro that calls a Basic routine every 10th of a second. For illustration, it stops itself after 20 seconds.
import threading
def do_call():
desktop = XSCRIPTCONTEXT.getDesktop()
ctx = XSCRIPTCONTEXT.getComponentContext()
smgr = ctx.ServiceManager
oMasterScriptProviderFactory = smgr.createInstanceWithContext(
"com.sun.star.script.provider.MasterScriptProviderFactory", ctx)
oScriptProvider = oMasterScriptProviderFactory.createScriptProvider("")
oScript = oScriptProvider.getScript(
"vnd.sun.star.script:Standard.Calc1.IncrementValue?"
"language=Basic&location=application")
oScript.invoke((), (), ())
class BasicScriptCaller:
def __init__(self):
self.timer = None
def call_basic_script(self):
do_call()
self.timer = threading.Timer(0.1, self.call_basic_script)
self.timer.start()
def stop_basic_script(self):
if self.timer is not None:
self.timer.cancel()
def start(self):
self.call_basic_script()
threading.Timer(20, self.stop_basic_script).start()
def start():
caller = BasicScriptCaller()
caller.start()
g_exportedScripts = (start,)
This routine increments cell A1, making something that looks like a timer.
Sub IncrementValue
oSheet = ThisComponent.getSheets().getByIndex(0)
oCell = oSheet.getCellByPosition(0, 0)
iOldVal = oCell.getValue()
oCell.setValue(iOldVal + 1)
End Sub
To turn off, the thread could stop itself if a cell, say B1, has a non-zero value. Then you could make a button or checkbox to automatically set B1 to 1 instead of 0. Also, stop if the document is no longer open.
Update
Here are the code changes you requested in the comment. It runs until cell B1 has a value. Also, it allows start()
to optionally accept the button event parameter.
class BasicScriptCaller:
def __init__(self):
self.timer = None
def stop_condition(self):
"""Return true if the condition to stop is met."""
oSheet = XSCRIPTCONTEXT.getDocument().getSheets().getByIndex(0)
oCell = oSheet.getCellByPosition(1, 0) # B1
return bool(oCell.getString()) and oCell.getString().strip()
def next_call(self):
do_call()
if not self.stop_condition():
self.timer = threading.Timer(0.1, self.next_call)
self.timer.start()
def start(button_evt=None):
caller = BasicScriptCaller()
caller.next_call()
g_exportedScripts = (start,)