LibreOffice5(73)Javaの例:GUIをPythonにする その6

2017-08-24

旧ブログ

t f B! P L
UnoControlDialog上のコンテクストメニュー表示させる例unomenu2.javaをPythonにします。ついでにポップアップメニューを入れ子にしてみました。

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


unomenu2.py: ダイアログウィンドウでコンテクストメニューを使う


GUI/unomenu2.py at f2200497b573eaec0ab208ba75393917d3029768 · p--q/GUI

GUI/unomenu2.py at develop · p--q/GUI · GitHub
(2018.2.17追記。menuCreator()関数の区切り線のItemPosが間違っていたので修正しました。)

(2018.2.16追記。リスナーをすべて除去するように作り直しました。GUI/unomenu2_3.py at develop · p--q/GUILibreOffice5(139)リスナーのメソッドの発火ログを取得するの方法でリスナーを除去するコードを有効にしてあるのでリスナーが発火するとこのマクロがあるフォルダにログファイルが出力されます。実際に発火すのはダイアログが閉じるだけです。ポップアップメニューに追加したMenuListenerのdisposing()はモダルダイアログを閉じるときでも発火しないのでダイアログをdispose()する前に削除しています(45行目と46行目)。)


ダイアログウィンドウ上で右クリックするとコンテクストメニューを表示します。
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。
 doc = XSCRIPTCONTEXT.getDocument()  # マクロを起動した時のドキュメントのモデルを取得。   
 docframe = doc.getCurrentController().getFrame()  # モデル→コントローラ→フレーム、でドキュメントのフレームを取得。
 docwindow = docframe.getContainerWindow()  # ドキュメントのウィンドウ(コンテナウィンドウ=ピア)を取得。
 toolkit = docwindow.getToolkit()  # ピアからツールキットを取得。 
 dialog, addControl = dialogCreator(ctx, smgr, {"PositionX": 102, "PositionY": 41, "Width": 200, "Height": 140, "Title": "Menu-Dialog", "Name": "Dialog1", "Step": 1, "TabIndex": 0, "Moveable": True}) 
 createMenu = menuCreator(ctx, smgr)
 menulistener = MenuListener(dialog)  # ポップアップメニューにつけるメニューリスナーを取得。
 items = ("First Entry", CHECKABLE+AUTOCHECK, {"checkItem": True}),\
   ("First Radio Entry", RADIOCHECK+AUTOCHECK, {"enableItem": False}),\
   ("Second Radio Entry", RADIOCHECK+AUTOCHECK),\
   ("Third Radio Entry", RADIOCHECK+AUTOCHECK, {"checkItem": True}),\
   (),\
   ("Fifth Entry", CHECKABLE+AUTOCHECK),\
   ("Fourth Entry", CHECKABLE+AUTOCHECK, {"checkItem": True}),\
   ("Sixth Entry", 0),\
   ("~Close", 0, {"setCommand": "close"})
 popupmenu =  createMenu("PopupMenu", items, {"addMenuListener": menulistener})  # 右クリックでまず呼び出すポップアップメニュー。  
 items = ("First Entry", CHECKABLE+AUTOCHECK, {"checkItem": True}),\
   ("Second Entry", 0)
 subpopupmenu =  createMenu("PopupMenu", items, {"addMenuListener": menulistener})  # 入れ子にするポップアップメニュー。
 popupmenu.setPopupMenu (8, subpopupmenu)  # ポップアップメニューを入れ子にする。 
 addControl("FixedText", {"Name": "Headerlabel", "PositionX": 6, "PositionY": 6, "Width": 200, "Height": 8, "Label": "This code-sample demonstrates the creation of a popup-menu."})
 addControl("FixedText", {"PositionX": 50, "PositionY": 50, "Width": 100, "Height": 8, "Label": "Right-click here"}, {"addMouseListener": MouseListener(ctx, smgr, popupmenu)})
 dialog.createPeer(toolkit, docwindow)  # ダイアログを描画。親ウィンドウを渡す。ノンモダルダイアログのときはNone(デスクトップ)ではフリーズする。
 # ノンモダルダイアログにするとき。
#  menulistener.frame = showModelessly(ctx, smgr, docframe, dialog)  # メニューで閉じるためにフレームをメニューリスナーに渡す。  
 # モダルダイアログにする。フレームに追加するとエラーになる。
 dialog.execute()  
 dialog.dispose()
ポップアップメニューをMouseListenerに渡して、リスナーのメソッドが発火した時にそれを表示させます。

ポップアップメニューにポップアップメニューを付けるとポップアップメニューが入れ子になります。
class MouseListener(unohelper.Base, XMouseListener):  # Editコントロールではうまく動かない。 
 def __init__(self, ctx, smgr, popupmenu):
  self.popupmenu = popupmenu
#  @enableRemoteDebugging
 def mousePressed(self, mouseevent):  # マウスがクリックされた時。
  control, dummy_controlmodel, name = eventSource(mouseevent)
  if name == "FixedText1":  # コントロール名で限定。
   if mouseevent.PopupTrigger:  # 右クリックのとき
    pos = Rectangle(mouseevent.X, mouseevent.Y, 0, 0)  # ポップアップメニューを表示させる起点。
    self.popupmenu.execute(control.getPeer(), pos, EXECUTE_DEFAULT)  # ポップアップメニューを表示させる。引数は親ピア、位置、方向。
 def mouseReleased(self, mouseevent):
  pass
 def mouseEntered(self, mouseevent):
  pass
 def mouseExited(self, mouseevent):
  pass
 def disposing(self, eventobject):
  pass
マウスがクリックしたときに呼ばれるmousePressed()メソッドの引数のMouseEvent StructのPopupTriggerはコンテクストメニューが呼ばれたとするとき(今回は右クリック)にTrueとなります。

execute()でポップアップメニューが表示されます。

execute()の引数でポップアップメニューを表示させる方向も指定できます。
class MenuListener(unohelper.Base, XMenuListener):
 def __init__(self, dialog):
  self.dialog = dialog
  self.frame = None  # ノンモダルダイアログで使用。
 def itemHighlighted(self, menuevent):
  pass
#  @enableRemoteDebugging
 def itemSelected(self, menuevent):  # PopupMenuの項目がクリックされた時。
  cmd = menuevent.Source.getCommand(menuevent.MenuId)
  if cmd == "close":
   if self.frame is None:  # フレームがないときはモダルダイアログ。
    self.dialog.endExecute()  # ウィンドウを閉じる。モダルダイアログではこれだけで閉じる。 モードレスダイアログは閉じない。
   else:  # フレームがあるときはノンモダルダイアログ。
    self.frame.close(True)  # フレームを閉じる。self.dialog.dispose()でも閉じる。モダルダイアログではdispose()ではドキュメントまでも閉じてしまう。
 def itemActivated(self, menuevent):
  pass
 def itemDeactivated(self, menuevent):
  pass   
 def disposing(self, eventobject):
  pass
メニューから呼ばれたコマンドがcloseのときはウィンドウを閉じます。

endExecute()で閉じることができるのはモダルダイアログだけです。

モードレスダイアログにしているときはdispose()でもダイアログウィンドウを閉じることができましたが、モダルかノンモダル(モードレス)かの判別もしたいのでモードレスダイアログにするときはこのメニューリスナーにモードレスダイアログのフレームを渡しています。

フレームにはXCloseableがあるのでclose()でフレームを閉じないといけません(Closing Documents - Apache OpenOffice Wiki) 。

close()の引数をTrueにすべきかFalseにすべきはLibreOffice5(55)Javaの例:GUIをPythonにする その1で学習しました。

今回はあとでまたclose()を呼び出す機会がないのでTrueにしています。

LibreOffice: XCloseable Interface Referenceにdispose()とclose()の違いが書いてありました。

dispose()は有無を言わさず閉じるのですが、close()は他のオブジェクトに閉じてよいのか許可を問い合わせます(LibreOffice5(55)Javaの例:GUIをPythonにする その1も参照)。

モダルダイアログをdispose()するとドキュメントまで閉じてしまいました。

unomenu2.pyでは新たな汎用関数はでてきません。

参考にしたサイト


Closing Documents - Apache OpenOffice Wiki
ドキュメントの閉じ方の解説。close()が使えるときはclose()で閉じないといけないようです。

LibreOffice: XCloseable Interface Reference
dispose()とclose()の違い。

次の関連記事:LibreOffice5(74)PathSubstitutionサービスで既定値を取得する

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ