前の関連記事:LibreOffice5(81)Javaの例:GUIをPythonにする その7
imagecontrolsample_sizeable.py: ウィンドウサイズに合わせてコントロールを調整する
GUI/imagecontrolsample_sizeable.py at 0524812f4b72cc07dada90ebd2b2df6c5a8116b5 · p--q/GUI
(Windows10ではBrowseボタンは未対応です。Windows10対応版はこの投稿の一番下でやっています。)
前回の再度に作成したサイズ変更可能なウィンドウのサイズを変更すると、それに合わせてコントロールの配置が変わります。
上の画像はウィンドサイズを変更させた後の状態です。
ウィンドウの大きさに伴って変化するのは一番上にある固定文字の幅、画像を表示しているイメージコントロールの幅と高さ、パスを表示しているEditコントロールの幅、です。
それぞれのコントロールの座標もウィンドウの大きさに合わせて変更しています。
ウィンドウサイズが変更されると、XWindowListenerのwindowResized()メソッドが呼ばれるので新たなウィンドウの幅と高さを元にそれぞれのコントロールの大きさと座標を算出しています。
なので、最初にウィンドウを描画するときにコントロールを作成しているmacro()の計算と、ウィンドウリスナーのwindowResized()でコントロールの座標と大きさを計算している式は同じになっています。
コピペすればよいので問題ないと思っていましたが、コントロールを追加したいときはいっぱい書き直さないといけないことに気がついたので、この方法は次から採用しないことにしました。
imagecontrolsample_sizeable2.py: ScaleModeを切り替えるラジオボタンをつける
GUI/imagecontrolsample_sizeable2.py at 0524812f4b72cc07dada90ebd2b2df6c5a8116b5 · p--q/GUI
(Windows10ではBrowseボタンは未対応です。)
左下にUnoControlImageControlModelのScaleModeプロパティを切り替えるUnoControlRadioButtonをつけました。
定数ImageScaleModeのNONE(サイズ調整しない)、ISOTROPIC(縦横比を維持して全表示)、ANISOTROPIC(縦横比を維持せずに全表示)を切り替えます。
Noneではよくわからないので、No Scalingと表示しています。
デフォルトではこれまでと同様にISOTROPICにしています。
No Scalingを選択するとオリジナルの画像サイズのまま表示されて、枠からはみ出たところは切り捨てられます。
スクロールバーをつけて切り捨てる部分をずらせないかと考えましたが、画像を枠の中心に持ってくる以外の配置はできないようです。
なので、No Scalingを選択したときは画像が全表示されるようにウィンドウサイズを調整するようにしました。
ただしウィンドウサイズがディスプレイサイズより大きくならないように制限をかけています。
ANISOTROPICを選択すると縦横比を維持せずに全表示されます。
縦横比を維持しないので画像が歪んでいます。
imagecontrolsample_sizeable.pyの時と違ってウィンドウサイズの変更したときに呼ばれるウィンドウリスナーのwindowResized()メソッドのコントロールの位置と大きさの再計算には変更前のウィンドウの大きさからの差を使って計算しています。
windowResized()メソッドの引数のWindowEvent Structでは変更後のウィンドウサイズしかわからないので、どれぐらい大きさが変化したかを知るには変更前の値を保存しておかないといけません。
コントロールの位置と大きさの変化量をウィンドウの大きさの変化量と同じにしているので、これでどの要素にウィンドウの変化分を適用するのかを指定するだけの処理で済みます。
setPosSize()の5つ目の引数のFlagesに、定数PosSizeを指定することで変更する要素だけ指定できるので、リスナーで値を変更するには便利です。
ウィンドウの大きさの変化量だけでコントロールの位置と大きさを決めているので、ウィンドウを小さくし過ぎて負になってしまうと、コントロールの表示がおかしくなってしまいます。
なのでいずれのコントロールの大きさが1以下にならないように、最低のウィンドウ幅と高さを設定しました。
ウィンドウを小さくしてもコントロールコンテナをこの設定した最低値より小さくならないようにしたら、コントロールの表示がおかしくならなくなりました。
グループ内のどのラジオボタンが選択されたのかリスナーで判断する方法
ラジオボタンはUnoControlRadioButtonサービスのインスタンスで作成したコントロールが一つの項目になっています。
TabIndexプロパティの値が並んでいるもの(不連続値でもよい)がひとグループのラジオボックスと判断されていずれかの一つだけ選択できるようになります。
しかしimagecontrolsample_sizeable2.pyで作成したコントロールはUnoControlDialogElementサービスがないので、TabIndexプロパティが設定できません。
TabIndexプロパティの値を設定しなくても、コントロールコンテナに追加する順番が連続していればひとグループと判断されました。
グループを区切りたいときはUnoControlRadioButton以外のコントロールを区切りとして挿入します。
Option Button - Apache OpenOffice Wiki
デベロッパーガイドの例ではUnoControlRadioButtonModelのStateプロパティが1か0かで選択されているか、いないかを判定しています。
しかしXItemListenerのitemStateChanged()メソッドの引数で返ってくるItemEvent Structで、どのラジオボタンが選択されたのかを判明する方法に悩みました。
どのラジオボタンを選択しても、HighlightedとItemIdは0、Selectedは1、が返ってきます。
ということで、どのラジオボタンが選択されているかは、Sourceからコントロールモデルを取得して、そのLabelプロパティで判定しています。
Labelが同一のラジオボタンはないはずなので、これで問題ないはずです。
ラジオボタンのラベルを変更するたびにリスナーも書き換えるのは面倒なので、リスナーのメソッド(setControl())でラジオボタンコントロールを取得して、ラベルを取得するようにしています。
ウィンドウサイズがディスプレイサイズを超えないように制限する
ディスプレイサイズより大きい画像を表示しているときにNo Scalingを選択するとウィンドウを閉じるボタンなどがディスプレイ外に表示されて不便なので、最大ウィンドウサイズを制限することにしました。
ウィンドウの最大化ボタンをクリックしたときのウィンドウサイズを上限にしようとしましたが、これはうまくいきませんでした。
ウィンドウの最大化はIsMaximizedアトリビュートをTrueにするとできるので、そこでそのウィンドウサイズを取得したあとにIsMaximizedアトリビュートをFalseに戻せばよい、と思ったのですが、実際にウィンドウサイズが変化するのはすべてのコードが実行されたあとなので、IsMaximeizedがFlaseとしてしまうと、その値しか取得できませんでした。
仕方ないのでツールキットのgetWorkArea()メソッドでディスプレイサイズを取得して、そこから、適当に決め打ちしたランチャーやタスクバーの幅を差し引いた値をウィンドウサイズの最大値にしました。
imagecontrolsample_sizeable3.py: 画像サイズを表示する
GUI/imagecontrolsample_sizeable3.py at 0524812f4b72cc07dada90ebd2b2df6c5a8116b5 · p--q/GUI
(Windows10ではBrowseボタンは未対応です。)
画像サイズとイメージコントロールのサイズを表示するようにしました。
画像ビューアとして使えるように、サンプルであることを表す上の文字列も削りました。
UnoControlRadioButtonModelのVerticalAlignはデフォルトではMIDDLEになっているのに対して、UnoControlFixedTextModelのVerticalAlignはデフォルトではTOPになっているため、画像サイズを表示しているUnoControlFixedTextModelではわざわざVerticalAlignをMIDDLEに設定しています。
GUI/imagecontrolsample_sizeable3_forWin.py at f0b82ae08009e1b0699f0d96745062152f9880ad · p--q/GUI
これはBrowseボタンをクリックするたびにFilePickerサービスをインスタンス化しているので、Windows10でもファイル選択ダイアログが開きます。
参考にしたサイト
Option Button - Apache OpenOffice Wiki
デベロッパーガイドのラジオボタンコントロールの解説。
0 件のコメント:
コメントを投稿