LibreOffice(36)マクロの記録をPythonに翻訳2:反復部分を関数にする

2014-04-03

旧ブログ

t f B! P L

前の関連記事:LibreOffice(35)マクロの記録をPythonに翻訳1:リストとタプル


The OpenOffice.org recorder and UNO dispatch callsではLibreOffice Basicで関数を作ってUNOディスパッチコールを整理しています。Pythonでも同じようにして反復している部分を関数にします。

マクロの記録の結果をPythonで関数にまとめる


まずLibreOffice(33)デベロッパーガイド5:ディスパッチフレームワークで作ったマクロの記録の結果を再掲します。
sub Main
dim document   as object
dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "例文"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())
dispatcher.executeDispatch(document, ".uno:InsertPara", "", 0, Array())
dim args3(0) as new com.sun.star.beans.PropertyValue
args3(0).Name = "Text"
args3(0).Value = "新しい段落に"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args3())
dim args4(0) as new com.sun.star.beans.PropertyValue
args4(0).Name = "Bold"
args4(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args4())
dim args5(0) as new com.sun.star.beans.PropertyValue
args5(0).Name = "Text"
args5(0).Value = "太字の"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args5())
dim args6(0) as new com.sun.star.beans.PropertyValue
args6(0).Name = "Bold"
args6(0).Value = false
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args6())
dim args7(0) as new com.sun.star.beans.PropertyValue
args7(0).Name = "Text"
args7(0).Value = "単語を含める"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args7())
end sub
LibreOffice Basicのコマンド以外の部分は全部削除しました。

これをThe OpenOffice.org recorder and UNO dispatch callsを参考にPythonで関数にまとめてみます。
#Tidied_UNO_dispatch_calls.py
from com.sun.star.beans import PropertyValue
def dispatch_writer_exp(): #マクロで呼び出す関数。
    fn_dispatch("InsertText", ["Text", "例文"])
    fn_dispatch("InsertPara")
    fn_dispatch("InsertText", ["Text", "新しい段落に"])
    fn_dispatch("Bold", ["Bold", True])
    fn_dispatch("InsertText", ["Text", "太字の"])
    fn_dispatch("Bold", ["Bold", False])
    fn_dispatch("InsertText", ["Text", "単語を含める"])
def fn_dispatch(command, m_args=[]): #オプション引数がないときは空のリストを使う。
    frame = XSCRIPTCONTEXT.getDesktop().getCurrentFrame()
    ctx = XSCRIPTCONTEXT.getComponentContext()
    dispatcher = ctx.getServiceManager().createInstanceWithContext("com.sun.star.frame.DispatchHelper",ctx)
    if m_args: #オプション引数があるとき
        n_args = len(m_args)//2
        args = [PropertyValue() for i in range(n_args)] #要素の型がPropertyValueの要素数n_argsのリストargsを生成。
        for i in range(n_args):
            args[i].Name = m_args[i*2] #要素番号が偶数の要素をm_argsから得る。
            args[i].Value = m_args[i*2+1] #要素番号が奇数の要素をm_argsから得る。
        args = tuple(args) #リストをタプルに変換。
    else:
        args = tuple() #空のタプルを生成。
    dispatcher.executeDispatch(frame, ".uno:" + command, "", 0, args)
g_exportedScripts = dispatch_writer_exp, #マクロセレクターに表示させる関数をタプルで指定。
関数fn_dispatch()でURLコマンドとオプション引数を受け取ってディスパッチコマンドを実行しています。
def fn_dispatch(command, m_args=[]):
オプション引数はリストm_argsで受け取ります。

5行目のInsertParaはオプション引数がないためデフォルトの引数値を使ってfn_dispatch()を定義されている引数より少ない個数の引数で呼び出せる関数にしています。

オプション引数のリストm_argsは[Name, Value]の組み合わせの繰り返しなので19行目で偶数の要素番号からNameを、20行目で奇数の要素番号からValueを取り出しています。
        n_args = len(m_args)//2
これでリストm_argsの要素数を2で除算するのですが、Pythonの除算演算子"/"は常に浮動小数点を結果として返すため、int型に変換しないと18行目のレンジの引数に使えません。(3.1.1. 数)

そこで"/"に代わり"//"を使って整数の結果を返すようにしています。

"//"は小数点以下を切り捨てて、int型を返します。
g_exportedScripts = dispatch_writer_exp,
25行目のg_exportedScriptsはマクロセレクターに表示される関数を限定する変数です。(実行するスクリプト一覧に表示する関数名

タプルとして関数名をg_exportedScriptsに代入しないといけないので25行目の最後の","は必須です。

オプション引数はfn_dispatch()で受け取ってからは変更することはないのでリストではなくて、タプルで受け取るようにしても動くのですが、PyCharmがゴチャゴチャなんかいってくるのでやめました。

オートメーションではちょっとカクカクして動く


LibreOffice(5)PythonでLibreOfficeが動く仕組み:UNOでオートメーションは遅くなる、と書いたのですが、Tidied_UNO_dispatch_calls.pyでは如実に遅さを実感できます。

オートメーションで実行すると順番にコマンドURLが実行されているのだなあ、とわかる程度の遅さを感じます。

LibreOffice側でマクロとして実行すると一瞬にして全部表示されますので違いがよくわかります。

以下にオートメーション部分も含めたコードを書いておきます。
#Tidied_UNO_dispatch_calls.py
import uno #オートメーションでのみ必要。
from com.sun.star.beans import PropertyValue
def dispatch_writer_exp():
    fn_dispatch("InsertText", ["Text", "例文"])
    fn_dispatch("InsertPara")
    fn_dispatch("InsertText", ["Text", "新しい段落に"])
    fn_dispatch("Bold", ["Bold", True])
    fn_dispatch("InsertText", ["Text", "太字の"])
    fn_dispatch("Bold", ["Bold", False])
    fn_dispatch("InsertText", ["Text", "単語を含める"])
def fn_dispatch(command, m_args=[]):
    frame = XSCRIPTCONTEXT.getDesktop().getCurrentFrame()
    ctx = XSCRIPTCONTEXT.getComponentContext()
    dispatcher = ctx.getServiceManager().createInstanceWithContext("com.sun.star.frame.DispatchHelper",ctx)
    if m_args:
        n_args = len(m_args)//2
        args = [PropertyValue() for i in range(n_args)]
        for i in range(n_args):
            args[i].Name = m_args[i*2]
            args[i].Value = m_args[i*2+1]
        args = tuple(args)
    else:
        args = tuple()
    dispatcher.executeDispatch(frame, ".uno:" + command, "", 0, args)
g_exportedScripts = dispatch_writer_exp,
#以下はオートメーションでのみ必要。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    dispatch_writer_exp()

参考にしたサイト


The OpenOffice.org recorder and UNO dispatch calls - Apache OpenOffice Wiki
OpenOffice..orgでの「マクロの記録」の例。

Python 標準ライブラリ — Python 3.3.3 ドキュメント
Python3.3.3の解説。

Python チュートリアル — Python 3.3.3 ドキュメント
Python3.3.3のチュートリアル。

OOoPython/OverView - ...?
PythonでのUNOの型の扱いなどについて日本語で例もつけて解説されています。

次の関連記事:LibreOffice(37)マクロの記録をPythonに翻訳3:クラスを使う

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ