年末年始でいきおいで作ってしまった 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 ライブラリに任せた方がよさそう。
参考先
- [The LibreOffice Help Window](https://help.libreoffice.org/latest/en-US/text/shared/05/new_help.html)
- [moonmile/ExcelLikeUno: LibreOffice の Python マクロを Excel VBA ライクに操作](https://github.com/moonmile/ExcelLikeUno)
