Libre Calc Macro : 指定時刻実行(Auto Sheet Closer)

Libre Calc

Libre Calcには指定時刻にマクロを実行させる機能はないので、指定時刻にシートやマクロを停止するようなことができません。(と思っているだけであるかもしれません)
指定時刻実行の代わりになるマクロを検討してみました。

■ 実現方式

Libre Calcには、ドキュメントイベント(メニュー:ツール→カスタマイズで設定可)機能があります。
この機能を使って、文書を開いたときにマクロを実行できるよう設定できます。
目論見としては、文書を開いた時点で終了時間を監視するマクロを起動し、時間が来たらシートを閉じるようにしたいと思います。

■ テストマクロ

以下のようなテスト用のマクロとシートを用意しました。

〇 シート

AUTO OFF時間の設定と、AUTO_OFF禁止を設けてあります。
マクロは、AUTO OFF時間に達したら、文書をクローズするようになっています。
AUTO_OFF禁止を0にして保管すると、次回文書を開いたときにAUTO OFFを監視します。
その際にAUTO_OFF禁止を0に書き換え、次回以降はAUTO OFFしないようにしています。
文書を開く際にマクロを実行するので、バグった時の事故防止です。

〇 マクロ

少し長いですが、以下のような関数を用意しています。
task_start()
終了時間監視関数です。呼び出すと終了時間まで戻りません。
task_stop()
終了時間監視中に実行すると、強制停止します。
event_open_doc()
「文書を開いたとき」に実行するイベントマクロです。task_start()を呼び出します。
event_preclose_doc()
「文書が閉じられる直前」に実行するイベントマクロです。task_stop()を呼び出します。

'
'	コンフィグ
'
public const cnf_sheet_setting = "Setting"
public const cnf_row_auto_off	= 1		' 電源OFF時間設定 行
public const cnf_col_auto_off	= 1		' 電源OFF時間設定 カラム
public const cnf_row_off_enable	= 2		' 電源OFF時間有効、無効フラグ行
public const cnf_col_off_enable	= 1		' 電源OFF時間有効、無効フラグ列


'
'	外部変数
'
Private s_req_shutdown as Boolean			' 終了要求

'
'	purpose	:	entry to do something untile sheet close
'	returns	:	0	...	timeup.
'			:	1	...	stop requirement has come.
'
function task_start() as integer
	Dim	n as date
	Dim endtm as date
	Dim sheet as object
	
	
	n = Now()

	'
	'	終了時間の計算
	'
	sheet = ThisComponent.Sheets.getbyname(cnf_sheet_setting)
	endtm = TimeValue(sheet.getCellByPosition(cnf_col_auto_off, cnf_row_auto_off).String) + date(Year(n), Month(n), Day(n))
	'
	'	すでに終了時刻をすぎていたら、次の日に設定
	'
	if (endtm <= n) then
		endtm = dateadd("d", +1,  endtm)
	end if

	'
	'	タスク終了まで抜けない
	'
	task_start = 1
	s_req_shutdown = False
	do while (s_req_shutdown = False)
		if (endtm <= Now()) then
			'
			'	電源OFF時間終了
			'
			task_start = 0
			exit do
		end if		
			
		'
		' タスクのYield
		'
		call DoEvents()	
		call Wait(cnf_task_yield)
 	loop
end function

'
'	purpose	:	entry to stop task.
'
function task_stop() as integer
	s_req_shutdown = True
	task_stop = 0
end function

'
'	purpose	:	entry to do event action of open document.
'
function event_open_doc()
	Dim cell as object
	
	cell = ThisComponent.Sheets.getbyname(cnf_sheet_setting).getCellByPosition(cnf_col_off_enable, cnf_row_off_enable)
	if (cell.Value <> 0) then
		exit function
	else
		cell.Value = 1
		ThisComponent.store()
	end if
	
	if (task_start() = 0) then
		MsgBox("Time up")
		ThisComponent.Close(True)
	else
		MsgBox("CloseDocument")
	end if
end function

'
'	purpose	:	entry do event action of previous close docment.
'
function event_preclose_doc()
	call task_stop()
end function

■ テスト結果

まずは、指定時刻に自動でシートを閉じることはできました。
また、マクロ実行でtask_stop()を実行しても正常動作しました。
普通にLibre Officeの操作も可能です。
残念なことに、以下の問題も見つかりました。
色々と試しては見ましたが、回避方法はありませんでした。
現時点では、おそらく回避方法はないので、アプリの運用で回避するしかないかと思っています。

  1. 終了時刻監視中に、アプリや文書のクローズを行うと異常終了扱いとなる
    文書を閉じる際に終了時刻監視を中止するようにフラグを立てているのですが、この時点でBasicが停止しているようです。終了時刻監視が終了しません。
    この場合、Libreは文書が正常終了してもマクロが動作しているので、Libreタスクが残っていたり、次回起動時に異常として扱われます。
  2. 1.の回避のため、クローズイベントをキャンセルするなどの方法はとれない
    文書を人的にクローズさせなければ、現象は発生しないのでクローズイベントをキャンセルできないか探ってみましたが、どうも手がなさそうです。

少し中途半端な対応ですが、正常にクローズできるボタンなどを用意するなどし、クローズ(WindowsのX)を押さないようにする運用を行うしかなさそうです。(残念・・・)

■ サンプルプログラム

上記で使用したサンプルプログラムです。
自己責任での御使用をお願いいたします。

タイトルとURLをコピーしました