LibreOffice Calcのセル内関数をPythonで書く

プログラミング

LibreOffice Calcのセル内関数をPythonで書く

概要

Calcのセルから使える関数(ユーザー定義関数)がPythonで書けたら便利ですよね。
Pythonの豊富な機能が使えるので、Basicよりも便利な部分があります。。
また、Pythonでマクロを書くとき書きやすいけどすでにあるBasicの機能が使えないなんて。
同じような機能をPythonで書くのは面倒だな。なんてことがありますよね。
たとえば、MsgBxo関数なんかは、よく使うのにPythonにはありません。
PythonからBasicの関数を呼び出せば問題は解決です。
逆に、BasicからPythonの関数を呼び出すこともできます。
そして、Basicの関数を作るとそれはセルから呼び出して使うことができます。
そんな、PythonとBasicの相互変換の方法を紹介します。

環境

現在は、2024年10月29日時点で、LibreOfficeのバージョンは24.8を使用しています。

ScriptForge

ドキュメント: ScriptForgeへのドキュメント
ScriptForgeは、LibreOfficeのマクロをPythonで書くためのライブラリです。
Pythonのマクロは、ScriptForgeが無くても書けますが使うと格段に楽に書くことができます。
使わずに書くと、何やら意味の分からないコードを長々と書かないとプログラミングできませんが
あるとかなりコードを短く書くことができますのでぜひ使ってみてください。
基本、ScriptForgeで書いてどうしても無理な場合だけほかの手段を使うという方針で良いかと思います。

PythonからBasicの関数を呼び出す

# coding: utf-8
1: from __future__ import unicode_literals
2: from scriptforge import CreateScriptService
3:
4: def disp_msgbox():
5:     bas = CreateScriptService("Basic")
6:     bas.MsgBox("Hello, world!")
7:     bas.Dispose()

 

1行目は、文字コードを指定しています。
2行目は、ScriptForgeのCreateScriptServiceをインポートしています。
これでScriptforgeを使う準備が出来ました。

それでは、本来PythonマクロではMsgBox関数は使え無いのですが、BasicのMsgBox関数を使ってPythonでMsgBoxを
表示する関数をつくってみましょう。

5行目で、CreateScriptServiceを使ってBasicのサービスを作成しています。
6行目で、ScriptForgeの’Basic’サービスからMsgBox関数を呼び出しています。
7行目で、関数が終了したのでサービスを後始末します。

基本的にこの流れで、PythonからBasicの関数を呼び出すことができます。

BasicからPythonの関数を呼び出す

BasicでもScriptForge自体は使えるのですが、Pythonの関数を呼び出す専用のサービスはありません。
と言うわけで別の方法で呼び出すことが必要です。

ドキュメント: BasicからPythonスクリプトの呼び出し

Pythonコード


     # coding: utf-8
 1:  from __future__ import unicode_literals
 2:  from scriptforge import CreateScriptService
 3:
 4:  def py_add(a, b):
 5:      return a + b
 6:
 7:  def py_inc(a):
 8:      return a + 1
 9:
10:  g_exportedScripts = (py_add, py_inc,)

 

こんなPythonのマクロがあったとします。

10行目で、g_exportedScriptsは、他のスクリプトから呼び出すしたり直接呼び出したりできる関数を指定しているはずという事になっています。
関数名をタプルで指定します。(カッコ内にカンマ区切りで羅列するという事)
ただ、試したところ無くても動作するようです。

Basicコード


 1:    REM  *****  BASIC  *****
 2:
 3:    Option Explicit
 4:
 5:    Public Function GetPythonScript(macro As String, _
 6:        Optional location As String) As com.sun.star.script.provider.Xscript
 7:        ''' Grab Python script object before execution
 8:        ' Arguments:
 9:        '    macro   : as "library/module.py$macro" or "module.py$macro"
10:        '    location: as "document", "share", "user" or ENUM(eration)
11:        ' Result:
12:        '    located com.sun.star.script.provider.XScript UNO service'''
13:        If IsMissing(location) Then location = "user"
14:        Dim mspf As Object ' com.sun.star.script.provider.MasterScriptProviderFactory
15:        Dim sp As Object ' com.sun.star.script.provider.XScriptProvider compatible
16:        Dim uri As String
17:        If location="document" Then
18:            sp = ThisComponent.getScriptProvider()
19:        Else
20:            mspf = CreateUnoService("com.sun.star.script.provider.MasterScriptProviderFactory")
21:            sp = mspf.createScriptProvider("")
22:        End If
23:        uri = "vnd.sun.star.script:"& macro &"?language=Python&location="& location
24:        GetPythonScript = sp.getScript(uri)
25:    End Function ' GetPythonScript
26:
27:    Private scr As Object ' com.sun.star.script.provider.XScript
28:
29:    Public Function PyAdd(a As Integer, b As Integer) As Integer
30:        scr = GetPythonScript("my_module.py$py_add","user")
31:        PyAdd = scr.invoke(Array(a, b), Array(), Array())
32:    End Function ' Script

 

GetPythonScript関数を作って、これを使ってPythonの関数を取得しています。

GetPythonScript()について説明します。
第一引数:macroには、Pythonのスクリプトのファイル名と関数名を指定します。
第二引数:locationには、Pythonのスクリプトの場所を指定します。
場所と言うか種類と言うか、”document”, “share”, “user”のいずれかを指定します。
“document”は、ドキュメント内への埋め込みスクリプトです。
“share”は、PCでの共有スクリプトです。
“user”は、ユーザー個人のスクリプトです。
そして、Pythonのスクリプトを保持するオブジェクトを返します。

13行目で、locationが指定されていない場合は、”user”を指定します。
17行目で、locationが”document”の場合は、ThisComponent.getScriptProvider()を使ってスクリプトプロバイダを取得します。
ThisComponent.getScriptProvider()は、ドキュメント内のスクリプトプロバイダを取得します。
ですので、ドキュメント埋め込みスクリプト以外に使うと起動時にドキュメントが存在しないためエラーになります。
20-21行目で、それ以外の場合は、MasterScriptProviderFactoryを使ってスクリプトプロバイダを取得します。
23行目で、PythonのスクリプトのURIを作成します。
24行目で、スクリプトプロバイダからPythonのスクリプトを取得します。

ここからGetPythonScrit()の使い方を説明します。
27行目で、Pythonのスクリプトを保持するオブジェクトを保持する変数scrを宣言します。
30行目で、先ほど定義したGetPythonScript関数を使ってPythonのスクリプトを取得します。
31行目で、Pythonのスクリプトを実行します。

scr.invoke()について、補足します。
Pythonの関数に必要な引数は、Array()で指定します。
この場合、py_add関数には、2つの引数が必要ですので、Array(a, b)としています。
第二引数と第三引数は、空の配列を指定します。
本来、第2引数と第3引数は”出力引数”(戻り値引数ともいうらしい)と言って引数自体が値を変更して戻り値として使う引数を指定する値らしいです。
検証してないので、詳しくはドキュメントを参照してください。

これで、Calcのセルに


    =PyAdd(1, 2)

とか


    =PyAdd(b1, b2)

と入力すると、Pythonの関数が呼び出されて、結果が返ってくるはずです。

再計算

セル内で使える関数を作って何度も修正していると、ちっとも修正が反映されません(値が変更されない)。
そんな時は、
「データ」->「計算」->「無条件の再計算」
で再計算されて表示が変更されます。
面倒であればショートカットキー
“Ctrl+Shift+F9”
でも再計算されます。

まとめ

PythonとBasicの相互変換の方法を紹介しました。
PythonからBasicの関数を呼び出す方法と、BasicからPythonの関数を呼び出す方法です。
PythonからBasicの関数を呼び出す方法は、ScriptForgeを使って簡単に呼び出すことができます。
BasicからPythonの関数を呼び出す方法は、少し面倒ですが、Pythonの関数を呼び出すことができます。

また、今回はCalcの事例として説明しましたが相互変換はWriterやImpressでも使うことができます。
便利に使ってみてください。

Commnts