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

OOoBasic/Dialog/Example10 - ...?のmodelessdialog-2.odtに入っているBasicマクロを今度はUnoControlDialogサービスを使ってPythonにします。まずこれまで学習したダイアログの作成方法と比較します。

前の関連記事:LibreOffice5(57)モードレスダイアログの例をPythonに翻訳する:その3


ダイアログウィンドウを作成する3種類の方法


まずはLibreOffice5(56)モードレスダイアログの例をPythonに翻訳する:その2でPythonにしたものを振り返ります。
(2017.7.14追記。オートメーションでモダルダイアログをフレームに追加するとLibreOfficeがクラッシュするのでLibreOffice5(59)モードレスダイアログの例をPythonに翻訳する:その5でフレームに追加する部分の位置を変更しました。)
(2017.7.17追記。モデルの属性になるUnoControlDialogElementサービスはUnoControlDialogModelサービスのcreateInstance()メソッドでコントロールをインスタンス化しないといけないことに対応しました。修正の容易さの問題でmodelessdialog2macro_unocontroldialog.pyのみ対応しています。)

modelessdialog2macro_createWindow.py

これはオリジナルのmodelessdialog-2.odtにあるBasicマクロでやっているように、ダイアログの作成にツールキットのcreateWindow()メソッドでまずウィンドウを作成してそれをフレームのコンテナウィンドウにして、コントロールを載せたコントロールコンテナをフレームのコンポーネントウィンドウにしたものです。

modelessdialog2macro_taskcreator.py

2番目の方法はTaskCreatorサービスを使ってコンテナウィンドウ付きフレームを作成してそのコンテナウィンドウをダイアログにする方法です。

この方法では最初の方法をと違ってダイアログウィンドウのタイトルを変更できるようになりましたが、コンテナウィンドウにexecute()メソッドがないためにモダルウィンドウにはできずモードレス(ノンモダル)なダイアログにしかできませんでした。

modelessdialog2macro_unocontroldialog.py

3つ目の方法が今回やるUnoControlDialogサービスを使ってダイアログを作成する方法です。

これは最初の2つの方法でコントロールを載せるために利用していたUnoControlContainerサービスに代わってUnoControlDialogサービスを利用するものです。

UnoControlDialogサービスはUnoControlContainerサービスが備えているXWindowインターフェイスに加えて、XTopWindowインテーフェイスももっているためUnoControlDialogサービスのインスタンスはそのままコンテナウィンドウにできます。

各コントロールもまたXWindowインターフェイスをもっているので、試しにEditコントロールをコンポーネントウィンドウにしてみましたが、ダイアログが正しく表示されずLibreOfficeがフリーズしてしまいました。

ということで最初の2つの方法と違ってフレームのコンポーネントウィンドウには何もいれないことにしました。

2番目のTaskCreatorでコンテナウィンドウを取得する方法以外はダイアログのexecute()メソッドを実行することでモダルダイアログにできます。

私には3番目の方法が一番使いやすいと思いました。

ダイアログにかかわる各オブジェクトの関連図: MVCパラダイム


LibreOffice(32)デベロッパーガイド4:コンポーネントフレームワークの時と同様にして、ダイアログにかかわる各オブジェクトの関連図を書いてみました。

ツールキットを介してウィンドウやコントロールが描画されていることがわかります。

Toolkitより左側にあるUnoControlDialogは次に述べるようにMVCパラダイムになっていて、Javaの例のUnoDialogSampleではUnoControlDialogModelに各コントロールのモデルを追加してからUnoControlDialogにsetModel()しています。

そのやり方だとUnoControlDialogModelから各コントロールのモデルにgetByName()でアクセスできます。

しかし次の章で述べているようにピクセル単位でコントロールの大きさを指定しようと思うとコントロールのモデルではなく、コントロールそのものにsetPosSize()で位置と大きさを指定しないといけないので、UnoControlDialogModelにコントロールのモデルを追加する方法は採用しないようにします。

なので、UnoControlDialogModelから各コントロールのモデルにgetByName()ではアクセスできないので図では灰色の矢印にしています。

 図では矢印を引いていないですが、UnoControlDialogのピアもXTopWindowを備えているのでFrameのコンテナウィンドウになれます。

Programming Dialogs and Dialog Controls - Apache OpenOffice WikiにもダイアログのMVCについて解説されています。

ビューは画面上の描画に反映され、コントローラはキーボードやマウスの入力を受け付けますが、これらは機種固有の対応が必要なのでツールキットに託しています。

本来MVCパラダイムではモデルに対してコントローラやビューは1対多の対応が可能なはずですが、ダイアログのMVCではツールキットが介在してそれぞれ1対1の対応になっています。

MVCパラダイムではモデル、ビュー、コントローラはLibreOffice5(52)Javaの例:ConfigExamplesをPythonにする その5の図にあるようにそれぞれ三角関係になっているはずです。

ダイアログのモデルはコントロール(「コントロール」と「コントローラ」は全く違うものなので注意。)のプロパティを担っています。

例えばUnoControlEditのsetModel()メソッドの引数にUnoControlEditModelを与えるとあとはツールキットがビューに変更を通知してビューにモデルのプロパティを反映してくれます。

逆にEditコントロールで内容を変更したときはツールキットがコントローラとしてモデルのプロパティを変更してくれます。

Editコントロールの変更やButtonコントロールのクリックを察知して処理したいときはUnoControlEditやUnoControlButtonにリスナーを付けます。

UnoControlEditやUnoControlButtonがビューに相当することになります。

コントロールの位置と大きさはモデルではなくビューのsetPosSize()メソッドで設定しないとピクセルにならない


LibreOffice 5.3 SDK - Developer's Guide ExamplesのGraphical User InterfacesのUnoDialogSampleの例では、UnoControlDialogをビューとコントローラ、UnoControlDialogModelをモデルと見立てたモデル-ビュー-コントローラ(MVC)パラダイムとして書かれています。

位置と大きさの情報はモデルがもつべきプロパティなのでUnoControlDialogModelUnoControlModelUnoControlDialogElementと継承しているPositionX、PositionY、Width、Heightに値を設定しています。

UnoDialogSampleではこのUnoControlDialogElementの属性に位置と大きさを設定しているのでその通りにしてみたらすべての大きさがちぐはぐでした。

OpenOffice.org では、プラットフォームへの非依存性を確保する観点から、ダイアログ内での位置とサイズを示す際に、Map AppFont (ma) という内部単位を使用しています。ma 単位では、オペレーティングシステムに設定されたシステムフォントの平均サイズを基準に、その高さの 8 分の 1 および幅の 4 分の 1 を、各方向の 1 単位と定めています。OpenOffice.org はこのような ma 単位を利用することで、システム設定の異なる環境下においても、ダイアログの表示が同じになるようにしています。
プロパティー - Apache OpenOffice Wiki

なんとコントロールのモデルの座標と大きさの設定の単位はMap AppFontという独自の単位になっていることを知りました。

しかもこの単位は横と縦の単位当たりのピクセル数が異なるものです。

だいたい手動で測定してみたらlinuxBean14.04では横1ma=1.7px、縦1ma=2.4pxとなっていました。

これではpxに換算しながらレイアウトするのはかなり面倒です。

で、modelessdialog-2.odtのソースを見直してみると位置と大きさだけはモデルのメソッドではなくビューのsetPosSize()メソッドで設定していました。

modelessdialog2macro_createWindow.pyでは72行目に該当します。

翻訳しながらどうして位置と大きさだけPOSSIZEというフラグ(x座標、y座標、幅、大きさ、のどの値を変更しているかのフラグ)をつけてビューに設定しているのだろうと思いましたが、ピクセルの単位で位置と大きさを設定するためなのでした。

ということでUnoDialogSampleの例のようにまずすべてのコントロールのモデルをUnoControlDialogModelなりUnoControlContainerModelに追加してからUnoControlDialogとかUnoControlContainerのモデルにセットする方法はいまいちとわかりました。

なので、各コントロールごとにモデルをセットしてそのコントロールにピクセル単位で位置と大きさを設定してから、UnoControlDialogに追加する方法に変えました。
(2017.7.24追記。やっぱりma単位も使っていくことにしました。LibreOffice5(58)モードレスダイアログの例をPythonに翻訳する:その4参照。)

参考にしたサイト


OOoBasic/Dialog/Example10 - ...?
modelessdialog-2.odtのBasicの例をPythonにしました。

Programming Dialogs and Dialog Controls - Apache OpenOffice Wiki
ダイアログのMVCの解説。しかし位置と大きさをモデルのプロパティで設定すると縦横日が異なる独特のma単位になってしまいます。

プロパティー - Apache OpenOffice Wiki
Map AppFont (ma) という内部単位の解説。縦横の単位あたりのピクセルが異なるのでやっかいです。

次の関連記事:LibreOffice5(59)モードレスダイアログの例をPythonに翻訳する:その5

PR

0 件のコメント:

コメントを投稿