Thor's Columns
PyQtでお手軽GUI開発♪―――は可能だったか? 第5回 レイアウト編

PyQtでお手軽GUI開発♪―――は可能だったか? 第5回 レイアウト編

 さてPyQtでGUIを作る場合にはQtDesignerが基本的な役割を果たします。

 ところがこのツール、触ってみればわりと直感的に使える部分も多いのですが、たとえばDelphiとかを使ってきた人にとっては分かりにくいところも結構あります。

 ということで、今回はデザイナーの使い方についてです。


レイアウトの基本

 QtDesignerを起動すればばーんとメインフォームができて、ウィジェットボックスからウィジェットをドラッグドロップすればフォーム上に配置することができます。また置いたウィジェットの位置やサイズを変更することも簡単にできます。

 ここの部分は非常に直観的で、固定サイズのウインドウのデザインをするのならこれだけで十分でしょう。

 しかし可変サイズのウインドウを作ろうと思ったら、いきなりはたと困ってしまったわけです。


 一つが、ウィジェットをウインドウの全面に張りたいと思った場合です。

 ウィジェットを単に置いた場合、ウインドウのサイズを変えてもウィジェットの大きさは変わりません。しかしたとえばテキストウィジェットなんかの場合、ウインドウサイズを変えたら自動的にウィジェットのサイズも変わってほしいわけです。

 そんな場合DelphiではAlignというプロパティがコントロールにあって、それにalClientという値を設定すれば親のクライアント領域一杯にコントロールが広がってくれて、親のサイズを変更すればそれに追従します。

 というわけでQtにもそんなのがあるだろうと思っていろいろ探し回ったわけですが―――おかげでずいぶん時間を無駄にしました。

 そうです。Qtにはそんなものはなかったのです。


 で、分かったことはQtではそういった場合の基本概念が違っていたということでした。

 Delphiなどでは前述のように子が親に自分で張り付いていたわけですが、Qtの場合は親が子の大きさを管理していたのです。


 たとえばデザイナーの上に以下のようにウィジェットを二つ置いたとします。



 この状態でメインウインドウをクリックすると、ツールバーの以下のボタンがアクティブになります。



 そこで縦線三つのアイコンをクリックすると……



 このようにウインドウがメインウインドウに張り付いて、リサイズすればそれに追従するようになります。

 Qtの場合可変サイズのレイアウトを行うには、このLayout機能を使っていくことになります。


レイアウトの種類

 このレイアウトにはツールボタンにもあるように、まず大きく分けて4種類あります。

 そのうち、水平に並べる垂直に並べる格子状に並べるというのはそのままなので説明も不要ですが、フォームレイアウトというのはなんでしょうか?

 これは実はラベルと何かをセットにしてレイアウトしたい場合に使います。

 例えば以下のようにラベルとラインエディットやチェックボックスなどをおおざっぱに並べておいて、フォームレイアウトにすれば……



このようになってくれます。



 また格子状のレイアウトは以下のように一つのブロックを二つ分に使ったりもできます。



 しかしこの特徴を使って何かやろうとすると意外に言うことを聞いてくれなかったりするので、複雑なレイアウトをするときにはむしろ、水平分割や垂直分割のフレームなどを入れ子にしたほうがいいように思います。

 なんかパズルみたいな感じです。


レイアウトの微調整

 このままではまだおおざっぱな配置ですが、以下のように更に細かくレイアウトの調整ができます。


◆レイアウトのプロパティ

 レイアウトを設定すると親ウィジェットのプロパティにLayoutという項目が現れるので、その値を設定します。

 Layoutプロパティのlayout**Marginはレイアウトの各方向の外側のマージンを、layoutSpacingはレイアウト内に含まれるウィジェット間のスペースを定義します。


◆レイアウトのストレッチ

 layoutStretchというプロパティで各ウィジェットのサイズの比率を指定できます。すなわち分割の比率は黄金比でないと嫌だというような人は、これに1000,1618とかいった値を設定してください♡




◆スペーサー

 サイズが可変のウィジェットをレイアウト内に並べると、上記のように適宜サイズが変更されますが、サイズが決まったウィジェットを並べると、以下の例のように間抜けになります。



 こういった場合、スペーサーを使うと図のように端に詰めて置くことができます。




◆スプリッタ

 いろんなツールの場合各ウィジェットのサイズをユーザーに設定させたいことの方がむしろ多いでしょう。すなわちスプリッタ―――ウィジェットの境目をマウスで移動できるよう機能をつけたいことは多々あります。

 そんな場合には次のようにします。


 まずレイアウト未設定の親コンテナ内に、スプリッタで分けたいウィジェットを追加します。それから分けたいウィジェットを複数選択(CTRL+クリック)すると、下記のようにツールバーのボタンがアクティブになります。



 この状態で水平にスプリッタの中に並べるというのを選択すると、このように二つのウィジェットがつながります。



 これですでに二つのウィジェットはスプリッタで分けられていますが、さらにそれをウインドウ全体にレイアウトするのももちろん可能です。

 実行してみるとウィジェットのサイズが変更できるのが分かります。




◆レイアウトの制限事項

 なおレイアウトのプロパティには以下のような制限があります。

 ウィジェットの挿入や削除をする場合レイアウトがない方が操作しやすいのですが、こういうことがあるので細かい調整は最後にやった方がいいでしょう。

QWidgetのプロパティ

 さらに個々のウィジェットに関しても設定できる様々なプロパティがあります。こういう見かけに関する部分は基本的にQWidgetで定義されているので、以下はそのプロパティについてです。

geometoryウィジェットの位置と大きさ。
sizePolicyウインドウがリサイズされたときのウィジェットサイズ変更方針(詳細は後述
minimumSize
maximumSize
ウィジェットの最小、最大の大きさ。これを一致させれば固定サイズのウィジェットになる。
sizeIncrement
basesize
sizeIncrement多分段階的にサイズ変更をするためのもののようでbasesizeはその基準サイズのようだが、Windowsでは効果がないとのことなので定かでない。
paletteウィジェットを構成する各パーツの色。autoFillBackgroundをOnにしていないと色がつかない物があるので注意。
font描画されるテキストのフォント。
cursorウィジェット上のマウスカーソル形状。
mouseTrackingOffだとmouseMoveEventのときボタンを押していないとイベントが来ない。で、これはデフォルトはOffです。
focusPolicyウィジェットにフォーカスが来る際の方針(詳細は後述
contextMenuPolicyコンテキストメニューの出し方の方針(詳しくは後ほど
windowTitleウインドウのタイトル。
windowIconウインドウのアイコン。
windowOpacityウインドウの透過率。
toolTipマウスカーソルを持ってくるとポップアップするツールチップのテキスト。
statusTipマウスカーソルを持ってくるとステータスバーに表示される説明。
wahtThisShift+F1とかのHelpで表示されるテキスト。ツールチップなどよりは詳しく書いておくと親切かもしれません(詳細はQWhatsThis
accesibleName
accesibleDescription
QAccessibleInterface(スクリーンリーダや点字ディスプレイなど)関連のパラメータ(なので普通はあまり気にしなくていいでしょう)
autoFillBackgroundこれをOnにしておかないとpaletteで設定しても色がつかないウィジェットがある。
stylesheetウィジェットのスタイルシート。
locale普通は日本でいいでしょう。
windowsFilePathこれにファイルパスをセットしておくと、windowTitleがブランクのときはその名前が使われる。
imputMethodHintsたくさんあるがあまり気にする必要はない(Note: フラグは単なるヒントなんでインプリメント時に無視しても構わないよ―――だそうです)
windowsModalityダイアログとして使う場合にモーダルウインドウになるかどうか、のようです。

◆sizePolicy

 このプロパティはサイズ変更がどういった方針で行われるかの基準です。

Fixedサイズ固定。
Minimumウィジェット最小サイズ以下には小さくならない。
Maximumウィジェット最大サイズ以上には大きくならない。
PreferredsizeHint()以内でウィジェットを拡大可能。
Expanding可能な限りウィジェットを大きく表示する。
MinimumExpandingsizeHint()を最小にしてウィジェットを拡大する。
Ignored表示されない。
ストレッチウィジェットが複数並んだときのサイズの比率。これはlayoutStretchでやったのと同じような結果になりますが、レイアウトの方が優先されるようです

フォーカスとタブオーダーそれにBuddy

 さてQWidgetのfocusPolicyですが、これはウィジェットに入力フォーカスが来る際の方針で、以下のような意味があります。

NoFocusフォーカスは来ない。
TabFocusタブキーでフォーカスが来る。
ClickFocusマウスクリックでフォーカスが来る。
StrongFocusタブでもマウスでもフォーカスが来る。
wheelFocusタブでもマウスでも、更にマウスホイールでもフォーカスが来る。

◆タブオーダーの編集

 このタブキーやマウスホイールで次々に入力フォーカスが変わる仕組みは便利ですが、その順序(タブオーダー)を指定する機能がQtDesignerにはあります。

 例えば以下のようなちょっとした入力フォームがあったとして、タブの入力順序が項目Aを指定後、値を入れて、続いて項目Bを入れて、オプションを選び、最後にボタンを押すという流れにしたいとします。



 そうした場合に編集メニューのタブ順を編集というコマンドを選択すると以下のような数値が現れるので、オーダーを指定したい順番に押していくと順番が設定できます(OK、キャンセルは自動的に最後に来るようです)




◆Buddyの編集

 またこの手の入力フォームには、ALT+何かのキーでショートカットできる機能もよくあります。それを設定するのがBuddyの編集という機能です。

 これを設定するには各入力項目に対応するラベルが必要です。

 そしてそのラベルに、メニューでよくやるように&をつけた文字を含めます(メニューの場合は&の次の文字でその項目が選択できるようになります)



 続いてラベルからそれに対応するウィジェットにドラッグすると、図のように矢印が出ます(設定後は左のように青くなります)



 そうやって全て設定後実行すると、例ではALT+Vと押せば値のスピンボックスにフォーカスが移動します。

 また設定時には“値(&V)”と表示されていたのが、今では“値(V)”となっていることにも注意してください。




ということで……

 QtDesignerでのレイアウトの基本は大体こんなもんではないかと思いますが、特にこういった可変サイズのGUIを作った場合、ウインドウの位置やサイズを保存できないとツールとしては非常に使いづらい物になります。

 というわけで次回はその状態保存についてです。


2017-04-09