PySide での show メソッドと geometry の挙動


PySide を使って Linux/Windows で動作するアプリケーションを作成しています。最近、QMainWindow の “geometry” プロパティの挙動が Linux と Windows とでは異なるためにいろいろと戸惑ったので、実際に調べてみました。

はじめに

私がやりたかったのは、

メインウインドウを最大化、最小化、フルスクリーン化した後、ウインドウの現在のサイズをコード上で知る

という事です。QWidget.showMaximized/Minimized/FullScreen メソッドを実行することで、表示されるウインドウサイズを変化させる事はできます。(リファレンスでは、showFullScreen() は X Window ではうまく動かない可能性がある旨記述がありますが、私の利用範囲では今のところ不都合ありません。) しかし、以下で述べるように、コードから現在の表示サイズを知るのは、Windows ではうまくいきますが、Linux ではうまくいきませんでした。

調査方法

QMainWindow に対して、show, showMaximized, showMinimized, showFullScreen, showNormal, setGeometry の各メソッドを実行して、”geometry” プロパティがどのように変化するのか表示するプログラムを作成しました。
イベントループに入ってからメソッドを実行しないとウインドウが表示された状態の値を確認できないため、QTimer で 100msec の遅延を発生させてから実行しています。(ウインドウが表示されるため、実行時に多少画面がちらつきます。)

結果

1920×1080 のスクリーンサイズを持つ同一 PC (Windows をホスト、Linux をゲストとした VirtualBox 環境) にて、上記 checkShow.py を Windows7, Xubunutu13.04, Ubunutu13.04 で実行した結果を以下にあげます。各段階での “geometry” プロパティの値を一覧にしています。(実際の表示の冗長な部分は削って有ります。)
※QRect の値は、最初の2つのパラメータが位置(左上の座標)、次の2つが大きさ(横x縦)です。

Windows の場合

Xubuntu/Ubuntu の場合

Xubuntu と Ubuntu では結果は同じでした。

まとめ

上記の結果から、”geometry” プロパティに関して以下の事がわかりました。

  • Windows / Linux 共に、show() の実行前は、仮の値として (0, 0, 640, 480) が入っている(VGA サイズということかと思われます)。
  • show() を実行すると、両者ともサイズは 200×100 に変化する。ただし、表示位置は OS によって異なる。Linux では左上隅に、Windows ではやや右下にシフトした位置になる。
  • Windows では、showMaximized/FullScreen/Normal の実行後、”geometry” は実際に表示されたウインドウのサイズに設定されるが、Linux ではこれらのメソッドは “geometry” を変化させない。(表示そのものは、最大化/フルサイズ/通常化します。つまり、表示されている状態と “geometry” の値が一致しません。)
  • Windows でも (Linux も) showMinimized() は、”geometry” を変化させない。おそらく、ウインドウをただ見えなくしているだけという事だと思われる。
  • もちろん、setGeometry() は、Windows / Linux 共に “geometry” を変化させる。

この結果から、Windows であれば、実際にウインドウが表示されていれば現在のウインドウサイズを “geometry” プロパティから知ることができますが、Linux の場合には “geometry” と現在のウインドウサイズが一致していない可能性があることがわかります。Linux では、自前で大きさを計算して setGeometry() で設定しないと両者を一致させられないようです。

[関連サイト]
junf/checkshow

[関連記事]

[参考にしたサイト]

VirtualBox での漢字キーのリピート不具合への対処 – Ubuntu –


VirtualBox ゲストの Ubuntu において漢字キーがオートリピートしてしまう不具合の対処法を、以前記事にしました。実は、私は Xubuntu を常用していて、標準的な設定方法は Ubuntu でも Xubuntu でも同じと思って記事を書いたのですが、その後、Ubuntu をインストールしたところ該当する設定項目が見当たらないことに気づきました。そこで、改めて Ubuntu での対処方法について記述します。

Ubuntu においては、セッション開始時のアプリケーション設定はターミナルにて以下のコマンドを実行します。

すると以下のように「自動起動するアプリケーションの設定」画面が開きますので、「追加」ボタンを押し、“xset -r 49″を設定します。
ubuntu-set
ubuntu

以上で、ログイン後に上記コマンドが実行され、漢字キーリピート不具合が Ubuntu でも解消されます。

今回は追加記事として書きました。もう少し詳細に知りたい方は、以前の記事も参照してください。

[関連記事]
VirtualBox での漢字キーリピート不具合の対処 | DeVlog – 銀の翼で翔べ –

PySide でズームイン/ズームアウトを実現する


今回は、PySide を使って画像をズームイン/ズームアウトしてみます。このやり方で、画像を拡大/縮小しながら表示するエフェクトが得られます。この記事を読む前に、PySide で画像をスライドさせる | DeVlog – 銀の翼で翔べ – を読んでいただくとより理解しやすいと思います。

今回の記事も Python3.3 で検証しています。

アプリケーションの骨格を作る

まず、いつものようにアプリケーションの骨格を作っておきます。メインウインドウ(window)内に、画像(hoge.jpg)を表示するラベル(label)を表示します。setGeometry のパラメータを必要に応じて調整してください。

実行すると左上角に画像が表示されます。
base

どのようにズームを実現するのか

QLabel には “scaledContents” というプロパティがあります。これを True に設定しておくと、中に格納されたイメージはラベルの大きさと同じになるように拡大/縮小されて(ラベルいっぱいに)表示されます。この特性を使えば、画像そのものを拡大/縮小する操作をしなくても、ラベルの拡大/縮小だけでズームが実現できます。

以下のようにズームアニメーションを取得するメソッドを書けます。target として QLabel オブジェクトを与え、mag1, mag2 に最初と最後のズーム倍率(0 〜 1)を与えます。

setScaledContents(True) で “scaledContents” を True にし、QLabel の “size” プロパティをアニメーション化することでズームを実現します。QSize オブジェクト (mapsize) には ‘*’ 演算が定義(オーバーロード)されているので、倍率を掛け算するだけで新しい QSize オブジェクトが得られます。Python でも演算子のオーバーロードが使えるんですね。

アニメーションを実行するには、アニメーションオブジェクトの start メソッドを実行します。

画像中央を基準にズームするには

先ほどの例では、左上角が固定されてズームされています。画像中央を中心として拡大/縮小していくようなエフェクトについても考えてみます。

画像中央を中心とする場合は、画像が左上のままでははみ出てしまいますので、まず準備として、画像を中央に配置しておきます。
以下のような、親オブジェクト(parent)の中央に、幅 width, 高さ height の画像を配置する場合の “pos” (画像の左上角) を計算するメソッドを作り、

このメソッドを使って画像をウインドウ中央に配置します。

center

それでは、中央固定のズームについて、あらためて考えてみます。左上固定の場合というのは、”pos” が固定しているという事です。”pos” はターゲットの左上角の座標ですから当然といえば当然です。逆に言うと、中央固定の場合、ズームと共に “pos” が変化するという事です。
zoom

つまり、画像のズームと同時に “pos” も変化するアニメーションを作れば良いのです。”pos” を変化させる(画像をスライドさせる)アニメーションについては、すでに PySide で画像をスライドさせる | DeVlog – 銀の翼で翔べ – で解説していますのでそちらも参照してください。

では、最初に “pos” を pos1 から pos2 に変化させるアニメーションを取得するメソッドを定義します。

次に、ターゲットをズームした時の “pos” の位置を計算するメソッドを作っておきます。

そして、ターゲット中央を固定してズームするアニメーションを取得するメソッドを作成します。QParallelAnimationGroup を使うことで、zoom と move を同時に実行します。(QSequentialAnimationGroup を使った例として、PySide で画像をフェードイン/フェードアウト | DeVlog – 銀の翼で翔べ – も参照して下さい。)

このメソッドで返されるアニメーションオブジェクトの start() メソッドを実行すると、このページの最初に示したようなエフェクトが得られます。
なお、完全なコードをこちらに用意しましたので、hoge.jpg を用意して実行してみてください。

[関連サイト]
junf/PySideSamples · GitHub

[関連記事]

  1. PySide で画像をフルスクリーン表示する | DeVlog – 銀の翼で翔べ –
  2. PySide で画像をスライドさせる | DeVlog – 銀の翼で翔べ –
  3. PySide で画像をフェードイン/フェードアウト | DeVlog – 銀の翼で翔べ –