LibreOffice5(33)モードレスダイアログの例をPythonに翻訳する:その1

前の関連記事:LibreOffice5(32)イベント駆動する拡張機能のJavaの例:AsyncJob.oxt その4


モードレスダイアログを表示させるOOoBasic/Dialog/Example10 - ...?のBasicの例をPythonに訳して動かしてみます。既存のコンテナウィンドウからツールキットを取得し新たなウィンドウを作成しそのウィンドウをフレームのコンテナウィンドウにしてそのフレームをフレーム階層に追加しています。仕組みを理解するにはLibreOffice(32)デベロッパーガイド4:コンポーネントフレームワークで学習したフレーム・コントローラ・モデル・パラダイム(FCM)の知識が必要です。

単純なモードレスダイアログの例:modelessdialog-1.odt


中身のないウィンドウを表示させるものです。

表示させているウィンドウは新たに作成したフレームのコンテナウィンドウになります。

そのコンテナウィンドウに表示させているものが7行目で指定しているdialogというコンポーネントサービスということになります。
import uno
from com.sun.star.awt.WindowClass import TOP as WC_TOP
from com.sun.star.awt.WindowAttribute import MOVEABLE as WA_MOVEABLE, CLOSEABLE as WA_CLOSEABLE
def createnewwindow(toolkit, parent, nX, nY, nWidth, nHeight): # ツールキットからwindowを作成する関数。
    d = uno.createUnoStruct("com.sun.star.awt.WindowDescriptor")
    d.Type = WC_TOP  # WindowClass: ウィンドウのタイプ。
    d.WindowServiceName = "dialog"  # WindowServiceName: コンポーネントサービスの名前。
    d.ParentIndex = -1  # 親ウィンドウのインデックス。
    d.Bounds = createRect(nX, nY, nWidth, nHeight)  # ウィンドウの位置と大きさ。
    d.Parent = parent  # 親ウィンドウ。
    d.WindowAttributes = WA_MOVEABLE + WA_CLOSEABLE  # ウィンドウの属性。移動可能。閉じることができる。
    return toolkit.createWindow(d)
def createRect(x, y, width, height):  # ウィンドウの位置と大きさを指定するRectangle Structを返す関数。
    aRect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
    aRect.X = x  # x軸座標
    aRect.Y = y  # y軸座標
    aRect.Width = width  # 幅
    aRect.Height = height  # 高さ
    return aRect
def modelessdialog1():  # ドキュメントのサブフレームを返すマクロmodelessdialog1。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    smgr = ctx.getServiceManager()
    doc = XSCRIPTCONTEXT.getDocument()  # モデルを取得。(オフィスドキュメントはXmodelインターフェイスの実装している)
    parent_frame = doc.getCurrentController().getFrame()  # モデルからコントローラを取得してさらにそこからフレームを取得。
    peer = parent_frame.getContainerWindow()  # フレームからコンテナウィンドウを取得。
    toolkit = peer.getToolkit()  # コンテナウィンドウを描画しているツールキットを取得。
    window = createnewwindow(toolkit,peer,150,150,200,200)  # ツールキットを使って新たなウィンドウを描画。
    frame = smgr.createInstanceWithContext("com.sun.star.frame.Frame", ctx)  # 新たなフレームを作成。
    frame.initialize(window)  # 新たなフレームにコンテナウィンドウを与えてフレームを初期化。
    parent_frame.getFrames().append(frame)  # 新たなフレームをフレームの階層に追加する。
    window.setVisible(True)  # ウィンドウを見えるようにする。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    modelessdialog1()
g_exportedScripts = modelessdialog1, #マクロセレクターに限定表示させる関数をタプルで指定。
23行目のドキュメントの取得からオブジェクトの取得が始まっていますのでWriterやCalcのドキュメントを開いた状態で実行する必要があります。

スタートセンターに対して実行してもモデル(ドキュメント)を取得できないのでエラーになります。


このようにモードレスなダイアログが表示されます。

モードレスなので表示したままドキュメントの操作もできます。

Frames - Apache OpenOffice WikiのFrame containing a component and a sub-frameの図のようにドキュメントのサブフレームになっているのでドキュメントの後ろに回ることはできませんし、ドキュメントを閉じるとダイアログも閉じられます。

LibreOffice(4)PyCharmからLibreOfficeを動かす(オートメーション)でやったように23行目で取得しているドキュメントはデスクトップから得ており、そのデスクトップはコンポーネントコンテクストのコンテクストからインスタンス化したものです。

デスクトップはLibreOffice(15)デベロッパーガイド3 コンポーネントコンテクストででてきたシングルトン(DesktopサービスはtheDesktopシングルトンに該当)なのでLibreOffice(32)デベロッパーガイド4:コンポーネントフレームワークのフレームワークAPIの図に従うと次のような流れでオブジェクトを取得していることになります。

コンポーネントコンテクスト(全ての始まり)→デスクトップの取得(シングルトン)(unopy.pyで処理)→モデルdocの取得(23行目)(マクロモードではXSCRIPTCONTEXTから取得)→コントローラの取得(24行目)→フレームparent_frameの取得(24行目)→コンテナウィンドウpeerの取得(25行目)→ツールキットtoolkitの取得(26行目)。

これで新たに作成するウィンドウの材料が揃ったことになります。

27行目でまずツールキットから親ウィンドウを指定してWindowServiceNameがdialogである新たなウィンドウwindowを作成しています。

親ウィンドウの指定はツールキットが描画するときに使うためだけに必要(不要?)なようで、フレームの操作はしてくれないのでこの新たに作成したウィンドウをフレームに結びつける必要があります。

28行目でコンポーネントコンテクストからフレームframeを作成しています。

29行目でframeをwindowで初期化してwindowをframeのコンテナウィンドウにしました。

30行目でparent_frameからフレーム階層を取得してframeをその階層に追加しています。

append()でフレーム階層に追加すると自動的にsetCreator()が実行されるようです。

31行目でwindowを見えるようにしています。

modelessdialog-1.odtではXFrameインターフェイスのsetName()メソッド(ではなくXTitleインターフェイスのsetTitle()メソッド、でウィンドウタイトルを変更していますがOOo3.x以降では無効になっているようでこの方法ではウィンドウタイトルの変更はできません。(OOoBasic/Window/TaskCreator - ...?

Structの書き方が私にはわかりにくいので書き直したのと、汎用化のため関数の引数を増やしたのが以下です。
import uno
from com.sun.star.awt import WindowDescriptor
from com.sun.star.awt import Rectangle
from com.sun.star.awt.WindowClass import TOP as WC_TOP
from com.sun.star.awt.WindowAttribute import MOVEABLE as WA_MOVEABLE, CLOSEABLE as WA_CLOSEABLE
def createWindow(toolkit, parent, type, service, attr, nX, nY, nWidth, nHeight): # ツールキットでwindowを作成して返す関数。
    d = WindowDescriptor(Type=type, WindowServiceName=service, ParentIndex=-1, Bounds=createRect(nX, nY, nWidth, nHeight), Parent=parent, WindowAttributes=attr)
    return toolkit.createWindow(d)
def createRect(x, y, width, height):  # ウィンドウの位置と大きさを指定するRectangle Structを返す関数。
    return Rectangle(X=x, Y=y, Width=width, Height=height)  # X座標,Y座標、幅、高さ
def modelessDialog1():  # サブフレームのダイアログを返すマクロmodelessDialog1。
    ctx = XSCRIPTCONTEXT.getComponentContext()
    smgr = ctx.getServiceManager()
    doc = XSCRIPTCONTEXT.getDocument()  # 現在のモデルを取得。(オフィスドキュメントはXmodelインターフェイスの実装している)
    parentFrame = doc.getCurrentController().getFrame()  # モデルからコントローラを取得してさらにそこからフレームを取得。
    peer = parentFrame.getContainerWindow()  # フレームからコンテナウィンドウを取得。
    toolkit = peer.getToolkit()  # コンテナウィンドウを描画しているツールキットを取得。
    window = createWindow(toolkit, peer, WC_TOP, "dialog", WA_MOVEABLE+WA_CLOSEABLE, 150, 150, 200, 200)  # ツールキットを使って新たなウィンドウを描画。
    frame = smgr.createInstanceWithContext("com.sun.star.frame.Frame", ctx)  # 新たなフレームを作成。
    frame.initialize(window)  # 新たなフレームにコンテナウィンドウを与えてフレームを初期化。
    parentFrame.getFrames().append(frame)  # 新たなフレームをフレームの階層に追加する。
    window.setVisible(True)  # ウィンドウを見えるようにする。
if __name__ == "__main__":
    import unopy
    XSCRIPTCONTEXT = unopy.connect()
    if not XSCRIPTCONTEXT:
        print("Failed to connect.")
        import sys
        sys.exit(0)
    modelessDialog1()
g_exportedScripts = modelessDialog1, #マクロセレクターに限定表示させる関数をタプルで指定。

参考にしたサイト


OOoBasic/Dialog/Example10 - ...?
このBasicで書かれた単純なモードレスダイアログの例:modelessdialog-1.odtをPythonにさせて頂きました。

Frames - Apache OpenOffice Wiki
フレームとウィンドウの関係。

OOoBasic/Window/TaskCreator - ...?
OOo3.x以降は今回のやり方ではウィンドウタイトルの変更はできないようです。

次の関連記事:LibreOffice5(34)LibreOffice5.2のバンドルPythonで利用可能なモジュール一覧

PR

0 件のコメント:

コメントを投稿