LibreOffice(4)PyCharmからLibreOfficeを動かす(オートメーション)

2014-01-03

旧ブログ

t f B! P L

前の関連記事:LibreOffice(3)PyCharmで作ったマクロをLibreOfficeから実行する


PyCharmから実行してもXSCRIPTCONTEXTをLibreOfficeから実行したときのように中身が入るように設定して、PyCharmから実行したPythonマクロでLibreOfficeが動くようにします。これをオートメーションといいます(LibreOffice(5)PythonでLibreOfficeが動く仕組み:UNO参照)。

XSCRIPTCONTEXTにLibreOfficeの中身をいれるunopy.pyを作る


PyCharmでプロジェクトのところで右クリック→New→Python File。

ファイル名をunopyにして「OK」します。

できたunopy.pyに以下を入れます。
#!     # unopy.py
import uno
import unohelper
from com.sun.star.script.provider import XScriptContext
class ScriptContext(unohelper.Base, XScriptContext):
    def __init__(self, ctx):
        self.ctx = ctx
    def getComponentContext(self):
        return self.ctx
    def getDesktop(self):
        return self.ctx.getServiceManager().createInstanceWithContext("com.sun.star.frame.Desktop", self.ctx)
    def getDocument(self):
        return self.getDesktop().getCurrentComponent()
def connect():
    ctx = None
    try:
        localctx = uno.getComponentContext()
        resolver = localctx.getServiceManager().createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localctx)
        ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
        if ctx:
            return ScriptContext(ctx)
    except:
        pass
    return None
このunopy.pyがXSCRIPTCONTEXTにLibreOfficeの中身を入れてくれます。

19行目がLibreOfficeとの通信方法の設定です。socket接続を使っています。

14行目のconnect関数でLibreOfficeのStarOffice.ComponentContextを受け取ってctxに代入しています。

そのctxを5行目で定義したScriptContextクラスに渡して、XSCRIPTCONTEXTのメソッドと同様にgetComponentContext、getDesktop、getDocumentを定義しています。

(2014.3.16追記。unopy.pyは上記の作り方ですとこのプロジェクトのみで有効です。他のプロジェクトからも汎用的に使えるようにuno.pyと同じC:\Program Files (x86)\LibreOffice 4\programに移動させました。でもこの場所においておくとLibreOfficeを上書きインストールしたときに消えてしまいますので、また作り直さないといけません。)

(2015.5.1追記。unopy.pyはpythonフォルダに置いて、各マクロファイルはそのサブフォルダのプロジェクトフォルダに置くとunopy.pyが共通に使えて、上書きインストールでも消去されずに済みます。linuxBean14.04(6)LibreOffice4.3.7とPyCharmの設定)

PyCharmで実行したときにunopy.pyで作ったXSCRIPTCONTEXTを受け取れるようにする


こんどはtest.pyにPyCharmで実行したときはunopy.pyで作ったXSCRIPTCONTEXTを受け取るコードを追加します。
def HelloWorld_Writer():
    doc = XSCRIPTCONTEXT.getDocument()
    doc.getText().setString("Hello World!")
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    HelloWorld_Writer()
4行目以降が追加部分です。

LibreOffice以外から呼ばれた場合変数__name__が__main__となることを利用して、PyCharmからtest.pyを実行したときのみ4行目以降が実行されるようになっています。

import unopyでunopy.pyを読み込んで、XSCRIPTCONTEXT = unopy.connect()でXSCRIPTCONTEXTの中身を入れています。

(H26.3.22追記。変数名XSCRIPTCONTEXTはLibreOfficeからマクロを呼び出したときにScripting Frameworkで与えられる固有名ですので、全部大文字でないといけません。XScriptContextなどとした場合はPyCharmからは動くがLibreOfficeから実行すると「global name 'XScriptContext' is not defined」といわれて動きません。)

あとはLibreOfficeと呼び出したのと同様のコマンドを実行すればよいわけです。

LibreOfficeからマクロを実行したときと違って、def HelloWorld_Writer():は関数定義しているだけになるので最後の11行目でHelloWorld_Writer()として呼び出して実行しています。

このようにLibreOfficeのPythonマクロの関数の後ろに、上記のコードの4行目から10行目を追加して最後にLibreOfficeのPythonマクロの関数を呼び出せばよいわけです。

LibreOfficeを通信可能状態にして起動する


あとはLibreOfficeをPyCharm(正確にはunopy.py)と通信可能な状態にして起動してtest.pyをPyCharmから実行するだけです。

(2015.1.12追記。バッチファイルで起動するとどうしてもコマンドウィンドウが開いてしまいます。ショートカットの「リンク先」に下記のオプションを追加したほうがスマートです。)

すごく長いオプションなのでバッチファイルにします。
"C:\Program Files (x86)\LibreOffice 4\program\soffice.exe" "-accept=socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"
メモ帳にこれをいれて拡張子をbatにして保存します。

ファイル名はLibreOffice_socket.batにしました。

これをダブルクリックするとLibreOfficeが起動します。


「文書ドキュメント」をクリックしてLibreOffice Writerを起動します。

そしてPyCharmでtest.pyをRunするとLibreOffice Writerから実行したときと同じ結果になるはずです。


2014.3.30追記。ツール→オプション→LibreOffice→メモリー、システム起動時にLibreOfficeを読み込む、にチェックしているときはLibreOffice_socket.bat起動前にシステムトレイからLibreOfficeのクイック起動を右クリックしてこれも終了しておかないといけません。)



もう一つの通信方法:pipe接続


LibreOfficeとの通信方法としては上でやったsocket接続以外にpipe接続があります。

unopy.pyの19行目を以下に変更します。
        ctx = resolver.resolve( "uno:pipe,name=pypipe;urp;StarOffice.ComponentContext")
LibreOfficeは以下のオプションで起動します。
"C:\Program Files (x86)\LibreOffice 4\program\soffice.exe"  "-accept=pipe,name=pypipe;urp;StarOffice.ServiceManager"
この方法でもうまくいきました。

参考にしたサイト


A. Python-UNO - N->N->N
Python-UNOについて詳しく解説されています。ここからコードを引用させていただきました。

XScriptContext インターフェース - N->N->N
XSCRIPTCONTEXTのメソッドの解説。

お気楽 Python プログラミング入門:第5回オブジェクト指向の基礎知識
Pythonのクラスの解説。

Python入門 Pythonの継承
Pythonでは関数の引数のようにして親クラスを継承します。

基本構文 - Python入門から応用までの学習サイト
「__name__」とは?「__main__」とは?

A. Automation - N->N->N
LibreOfficeの起動オプションの設定の解説。

OOoPython/IDE - ...?
LibreOfficeとEclipseやNetBeansとの連携について解説されています。

次の関連記事:LibreOffice(5)PythonでLibreOfficeが動く仕組み:UNO

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ