LibreOffice Calc で マクロを使う標準的な方法をおさらい

年末年始でいきおいで作ってしまった ExcelLikeUno というライブラリは「LibreOffice Calc のマクロを Python で書こうとすると UNO API を直接扱わないと大変なので、Excel の VBA マクロのように簡単に書けるようにしよう」というのが趣旨です。
が、そもそも、 LibreOffice Calc というか LibreOffice のマクロを何で書けばいいのか? ってのを自分のためのおさらいしておきます。

つまりは、勢いで作ったものだから、LibreOffice の標準機能とダブって作っても仕方ない、ということに今更ながら気づいた…というところです。

LibreOffice のマクロドキュメント

[The LibreOffice Help Window](https://help.libreoffice.org/latest/en-US/text/shared/05/new_help.html) の下の「Macros and Scripting」にあります。

なぜかうちの環境ではマクロエディタでコード補完が効かないので(何かバグっている?)、じゃあ Python で作るかと思い立ったのですが、実際はコード補完が効くようです。このあたりはよくわかりません。

LibreOffice Basic

いわゆる文法が Basic なマクロです。
「ツール」→「マクロ」→「マクロの記録」で保存されるのは、この LibreOffice Basic です。
UI から操作できて記録できるので、これが一番参考になります。Excel VBA と似た感じで作れます。

コード補完は [Basic IDE](https://help.libreoffice.org/25.8/ja/text/shared/optionen/BasicIDE.html) によって提供されている…筈なのですが、うちの Windows 環境では動きません。ちなみに Ubuntu 版では「Basic IDE」のメニューがありません。

ちなみに、A1 セルを選択して、”masuda” と入力すると次のようなコードが出力されます。

REM  *****  BASIC  *****

sub Main
	rem ----------------------------------------------------------------------
	rem define variables
	dim document   as object
	dim dispatcher as object
	rem ----------------------------------------------------------------------
	rem get access to the document
	document   = ThisComponent.CurrentController.Frame
	dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
	
	rem ----------------------------------------------------------------------
	dim args1(0) as new com.sun.star.beans.PropertyValue
	args1(0).Name = "ToPoint"
	args1(0).Value = "$A$1"
	
	dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())
	
	rem ----------------------------------------------------------------------
	dim args2(0) as new com.sun.star.beans.PropertyValue
	args2(0).Name = "StringName"
	args2(0).Value = "masuda"
	
	dispatcher.executeDispatch(document, ".uno:EnterString", "", 0, args2())
	
	rem ----------------------------------------------------------------------
	dispatcher.executeDispatch(document, ".uno:JumpToNextCell", "", 0, Array())

end sub

これ、今だから分かるのですが、初心者にとっては相当きついです。というか、無理です。
ただし、Excel VBA と同じように、とりあえず記録をしておいて中身は何も見ないで動かしている、人にはいいかもしれません。完全にピンポイントの動かし方になります。

ちなみに Excel でやるとこんなコードになります。

Sub Macro1()
'
' Macro1 Macro
'

'
    Range("A1").Select
    ActiveCell.FormulaR1C1 = "masuda"
    Range("A2").Select
End Sub

これだと参考にして、何かに拡張できそうですよね。Excel VBA が広まったのは、この手軽さと入門のしやすさがあったので、ここぐらいまでは敷居を下げて欲しいところです。

VBA 互換モード

LibreOffice Basic の中に「VBA 互換モード」というのがあります。
[Support for VBA Macros](https://help.libreoffice.org/latest/en-US/text/sbasic/shared/vbasupport.html?DbPAR=BASIC)

どこまで互換性があるかというと、先の Excel VBA のコードをそのまま貼り付けて動かせる、というレベルです。

option vbasupport 1

Sub Macro1()
'
' Macro1 Macro
'
    Range("A1").Select
    ActiveCell.FormulaR1C1 = "masuda"
    Range("A2").Select
End Sub

もう、Excel VBA から移植する場合にはこれで十分ですね、ってレベルです。
先頭に `option vbasupport 1` を入れてしまえば大抵のものが動きます。

ただし、最大の難点は BASIC で書かないといけないことと、Excel VBA の文法を引きずってしまうところです。何か修正するときに BASIC は、まあいいとして、LibreOffice Calc なのに、何故 Excel VBA で書かなくてはいけないのか? という違和感が将来的に残ります。

ScriptForge ライブラリを使う

実は ScriptForge って OSS のライブラリかと思っていたのですが、LibreOffice に標準で付属しているライブラリなんですね。
[ScriptForge Libraries](https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/lib_ScriptForge.html?DbPAR=BASIC)

先の LibreOffice Basic で書いていたややこしいコードも ScriptForge ライブラリを使うと、かなりシンプルに書けます。

実際のところは

  • LibreOffice Basic で標準的なセルを扱う操作
  • セルの移動や、コピー&ペーストなどは、ScriptForge ライブラリを使う

という使い分けになります。

セル A1 に “masuda” と入力するだけならば、次のコード

sub Main
    dim oSheet as object
    oSheet = ThisComponent.Sheets.getByIndex(0)
    dim oCell as object
    oCell = oSheet.getCellByPosition(0, 0) ' A1 セル
    oCell.String = "masuda"
end sub

を、ScriptForge ライブラリを使うと次のように書けます。

sub main
    GlobalScope.BasicLibraries.loadLibrary("ScriptForge")

    Dim oDoc As Object
    Set oDoc = CreateScriptService("Document", ThisComponent)
	oDoc.SetValue("A1","masuda")
end sub

ScriptForge ライブラリの場合、どちらかというと UI 操作を抽象化しているので、セルの値を直接操作する場合は、LibreOffice Basic の方がシンプルに書けます。

これも慣れるといいんでしょうが、新たに LibreOffice Basic と ScriptForge ライブラリの両方を覚えないといけないのが難点です。
ただし、LibreOffice Calc だけじゃなくて Writer などの機能の網羅しているので、LibreOffice 全体のマクロを作る場合には便利かもしれません。

Python でも ScriptForge ライブラリは使える

ExcelLikeUno ライブラリを作ってから、最近気づいたのですが、Python からでも ScriptForge ライブラリは使えます。なので、基本的に Python でマクロでも UI 操作はScriptForge ライブラリを使うのが標準なのでしょう。

from scriptforge import CreateScriptService
doc = CreateScriptService("Calc")

def macro1():
    doc.SetValue("A1", "masuda")

Calc の内部から動かすマクロでも XSCRIPTCONTEXT 経由と ScriptForge ライブラリを組み合わせて使うとかなりのところまでいけます。

で、ExcelLikeUno ライブラリはどうするか?

LibreOffice Calc のマクロを作ろうとしたときに難点が

  • LibreOffice Basic でコード補完が使えない
  • UNO API を直接使うのが大変
  • Excel VBA 互換モードは、将来的にも Excel VBA の文法を引きずることになる
  • ScriptForge ライブラリは便利だが、コード補完が使えない
  • UNO API の構造と ScriptForge ライブラリの構造を覚えないといけない

というところだったので、私としては “コード補完が使えない” ところが一番のストレスです。まあ、LibreOffice Basic の IDE はうちの環境だけかもしれないのですが、少なくとも Ubuntu 版では Basic IDE のメニューがないので、コード補完は使えません。

あと、今更 Basic でやるのもちょっと不便です。Web API に連携しようとか、外部データベースにアクセスしようとかした場合には、Python のほうが便利です。というか LibreOffice Basic で外部 Web API を呼び出せるのかわかりません。

そうなると、

  • Python で書く
  • LibreOffice Calc を操作するときにコード補完が有効になる
  • Excel VBA っぽく、直感的に簡単な操作がよい(マニュアルを熟読とかしたくない)

というパターンが自分には残るわけで、ScriptForge ライブラリでちょっと使いづらい部分を ExcelLikeUno ライブラリに移植する、ってのがよさそうです。完全移植をやろうとすると大変なので、ダイアログの表示とかは ScriptForge ライブラリに任せた方がよさそう。

参考先

カテゴリー: 開発, LibreOffice パーマリンク