LibreOffice5(71)Javaの例:GUIをPythonにする その4

2017-08-23

旧ブログ

t f B! P L
UnoMenu.javaをPythonにします。LibreOffice5(58)モードレスダイアログの例をPythonに翻訳する:その4の3つのウィンドウ作成方法のうち、 UnoControlDialogを使ったものはメニューバーは表示できず、まず createWindow()でウィンドウを作成する方法についてやります。

前の関連記事:LibreOffice5(70)Javaの例:GUIをPythonにする その3


unomenu_createWindow.py: メニューバーをもつウィンドウの作成


GUI/unomenu_createWindow.py at d45c0f20acefac1cfb260d0402ad16c5d0c45567 · p--q/GUI

def macro():  # オートメーションでは発火しないリスナーがある、閉じるボタンでウィンドウを閉じるとLibreOfficeがクラッシュする。
    ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
    smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
    doc = XSCRIPTCONTEXT.getDocument()  # マクロを起動した時のドキュメントのモデルを取得。   
    docframe = doc.getCurrentController().getFrame()  # モデル→コントローラ→フレーム、でドキュメントのフレームを取得。
    docwindow = docframe.getContainerWindow()  # ドキュメントのウィンドウ(コンテナウィンドウ=ピア)を取得。
    toolkit = docwindow.getToolkit()  # ピアからツールキットを取得。 
    window = createWindow(toolkit, CLOSEABLE+SHOW+MOVEABLE+SIZEABLE, {"PositionX": 100, "PositionY": 100, "Width": 500, "Height": 500, "Type": TOP})  
    window.setVisible(False)  # 描画中のウィンドウは表示しない。
    dummy_frame = addToFrames(ctx, smgr, docframe, window)  # 親フレームとウィンドウを渡す。新しいフレームのコンテナウィンドウにする。
    menubar = smgr.createInstanceWithContext("com.sun.star.awt.MenuBar", ctx)  # メニューバーをインスタンス化。
    menubar.insertItem(1, "~First MenuBar Item", 0, 0)  # ID(1から開始), ラベル、スタイル(0または定数com.sun.star.awt.MenuItemStyleの和)、位置(0から開始)
    menubar.insertItem(2, "~Second MenuBar Item", 0, 1)
    window.setMenuBar(menubar)  # メニューバーをウィンドウに追加。UnoControlDialogに追加しても目に見えない。
    items = ("First Entry", AUTOCHECK),\
            ("First Radio Entry", RADIOCHECK+AUTOCHECK),\
            ("Second Radio Entry", RADIOCHECK+AUTOCHECK),\
            ("Third Radio Entry", RADIOCHECK+AUTOCHECK),\
            (),\
            ("Fifth Entry", AUTOCHECK),\
            ("Fourth Entry", AUTOCHECK),\
            ("Sixth Entry", 0),\
            ("Close Dialog", 0)  # ポップアップメニューの項目。タプルのインデックスが位置に相当。IDはインデックス+1。
    popupmenu = createPopupMenu(ctx, smgr, items)  # ポップメニューを取得。
    popupmenu.enableItem(2, False)  # メニュー項目をIDで指定して、Falseでグレーアウト。
    popupmenu.checkItem(3, True)  # チェックできるメニュー項目をIDで指定して、Trueでチェックを付ける。
    popupmenu.addMenuListener(MenuListener(window))  # ポップアップメニューにリスナを付ける。
    menubar.setPopupMenu(1, popupmenu)  # メニューバーのIDを指定してポップアップメニューを追加。  
    window.setVisible(True)
createWindow()で作成したウィンドウにメニューバーを追加しています。
class MenuListener(unohelper.Base, XMenuListener):
    def __init__(self, window):
        self.window = window
    def itemHighlighted(self, menuevent):
        pass
#     @enableRemoteDebugging
    def itemSelected(self, menuevent):  # PopupMenuの項目がクリックされた時。
        if menuevent.MenuId == 9:  # メニュー項目のIDを取得できる。
            self.window.dispose()  # ウィンドウを閉じる。
    def itemActivated(self, menuevent):
        pass
    def itemDeactivated(self, menuevent):
        pass   
    def disposing(self, eventobject):
        pass  
PopupMenuXMenuListenerをつけるとメニュー項目をクリックした時にitemSelected()が発火します。

メニューバーを追加できるのはXTopWindowインターフェイスをサポートしているウィンドウです。

UnoControlDialogもXTopWindowインターフェイスをサポートしてsetMenuBar()メソッドがあるのですが、UnoControlDialogにはメニューバーを表示させることはできませんでした。

XTopWindowインターフェイスをサポートしているウィンドウ作成のために、WindowDescriptor StructのTypeでcom.sun.star.awt.WindowClassのTopを指定しています。

TOPのときはLibreOffice5(58)モードレスダイアログの例をPythonに翻訳する:その4LibreOffice5(69)Javaの例:GUIをPythonにする その2で使ったSIMPLEと違って、ParentIndexやParent、WindowServiceNameを指定しなくてもウィンドウが作成できました。

しかしXDialogインターフェイスをサポートしていないのでexecute()でモダルウィンドウにはできません。

ノンモダルウィンドウなので、フレーム列に追加しないとウィンドウの閉じるボタンが反応しません。

メニューバー(MenuBar)にはsetPopupMenu()メソッドでポップアップメニュー(PopupMenu)を追加できます。

ポップアップメニューの項目には定数com.sun.star.awt.MenuItemStyleを指定することでチェックボックスやラジオボタンを追加できます。

ラジオボタンは隣り合うものがグループになります。

AUTOCHECKをつけないと選択してもチェックなどが切り替わりません。

逆にAUTOCHECKをつけていればCHECKABLEをつけなくてもチェックボックスが表示されました。
class MenuListener(unohelper.Base, XMenuListener):
    def __init__(self, window):
        self.window = window
    def itemHighlighted(self, menuevent):
        pass
#     @enableRemoteDebugging
    def itemSelected(self, menuevent):  # PopupMenuの項目がクリックされた時。
        if menuevent.MenuId == 9:  # メニュー項目のIDを取得できる。
            self.window.dispose()  # ウィンドウを閉じる。
    def itemActivated(self, menuevent):
        pass
    def itemDeactivated(self, menuevent):
        pass   
    def disposing(self, eventobject):
        pass  
メニューの項目を選択するとitemSelected()が呼ばれます。

引数にMenuEvent Structが渡されるのでそこからメニューの項目のIDを取得できます。

ただしIDはメニューオブジェクト内でしかユニークでないので、複数のメニューオブジェクトが存在して、他のメニューにも同じリスナーをつけていると重複するかもしれません。

なのでコマンドでメニュー項目を判別したほうがいいかもしれません。(OOoBasic/Window/Menu - ...?)。

オートメーションではウィンドウの表示はできますが、XMenuListenerのitemSelected()が発火しません。

またウィンドウの閉じるボタンをクリックするとLibreOfficeがクラッシュします。

オートメーションはあくまでデバッグ用になります。

unomenu_createWindow.pyで使っている汎用関数


関数enableRemoteDebugging()はEclipse: PyDevメモ: LibreOfficeのPythonマクロのデバッグで解説したデバッグコードです。

createWindow()とオートメーションで実行するための部分はLibreOffice5(69)Javaの例:GUIをPythonにする その2で解説しているものと同じです。

createPopupMenu(ctx, smgr, items)
def createPopupMenu(ctx, smgr, items):  # ポップメニューを返す。itemsは項目のラベルとスタイルのタプルのタプル。   
    popupmenu = smgr.createInstanceWithContext("com.sun.star.awt.PopupMenu", ctx)  # ポップアップメニューをインスタンス化。
    for i, item in enumerate(items, start=1):  # 1から始まるiをIDにする。
        if item:  # ラベルとスタイルのタプルが取得できた時。
            popupmenu.insertItem(i, *item, i-1)  # ItemId, Text, ItemSytle, ItemPos。
        else:
            popupmenu.insertSeparator(i)  # ItemPos。セパレーターのときは位置を設定するだけ。    
    return popupmenu
PopupMenuサービスのインスタンスを返します。

引数のctxはコンポーネントコンテクスト、smgrはサービスマネジャー、 itemsはメニュー項目名とスタイルのタプルのタプルになります。

タプルに入っている順番にメニュー項目が追加されます。

追加される順に1から始まるIDが割り当てられます。

区切り線にはIDはありませんが、0から始まる位置番号はあるので、区切り線のIDに該当する番号は欠番にしています。

addToFrames(ctx, smgr, parentframe, windowpeer)
def addToFrames(ctx, smgr, parentframe, windowpeer):  # フレームに追加しないと閉じるボタンが使えない。
    frame = smgr.createInstanceWithContext("com.sun.star.frame.Frame", ctx)  # 新しいフレームを生成。
    frame.initialize(windowpeer)  # フレームにコンテナウィンドウを入れる。    
    parentframe.getFrames().append(frame)  # 新しく作ったフレームを既存のフレームの階層に追加する。 
    return frame  # フレームにリスナーをつけるときのためにフレームを返す。
これはLibreOffice5(69)Javaの例:GUIをPythonにする その2で解説したshowModelessly()とやっていることは同じで、フレーム名を引数のダイアログ名からとっていた部分を省いたものです。

モードレスウィンドウはこの関数でやっているようにフレーム列に追加しないと閉じるボタンが使えません。

参考にしたサイト


OOoBasic/Window/Menu - ...?
Basicでのメニューバーの作成方法の解説。

次の関連記事:LibreOffice5(72)Javaの例:GUIをPythonにする その5

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ