PySide チュートリアル - helloworld から ユニットテストまで
ここ 2 ヶ月ほど PySide でお仕事してました。もともと PyQt で動いてたアプリケーションだったのですが、けっこう仕様変更が大きかったこともあり、どうせなので PySide で作り直してみることにしました。両フレームワークの差異はこのページにまとまっています (id:doloopwhile さんが翻訳されています)。大きくは、
- モジュール名が PyQt から PySide に
- PyQt の API は QString や QVariants 等 Qt が提供する型と、unicode 等 Python のデータ型の両方をサポートしていましたが、PySide では Python のデータ型のみをサポート
- 画像等のリソースファイルをバイナリに変換したりするツール類の名称がそれぞれ変更
-
- pyuic4 -> pyside-uic
- pyrcc4 -> pyside-rcc4
- pylupdate4 -> pyside-lupdate
PySide への変更はそんなに問題ではありませんが、まだ開発中ということもあり、pyside-rcc4 にバグがあったり、signal-slot が遅いということもあるようです。この辺りは今後に期待です。
ということで自分の復習 & メモと、PySide がちょっとでも普及すればいいなということで、PySide のチュートリアルを作ってみました。helloworld ということで、ボタンをおしたらテキストボックスに "Hello world" と表示するだけのなんの面白味もないウィジェットと、そのユニットテストを作ってみます。ソースは bitbucket に公開しました。
- 環境を整える
- インストールするもの
-
- Python
- Python for Windows extensions (Windows ユーザのみ)
- PySide
- 推奨
-
- virtualenv - py2exe でフリージング (実行ファイル形式に変換) する際に余計なライブラリが含まれるのを防ぐため
- ウィジェットを表示してみる
Python インタプリタから以下のように打つと、ダイアログを表示することができます。import sys from PySide import QtGui app = QtGui.QApplication(sys.argv) dialog = QtGui.QDialog() dialog.exec_()
- UI を作る
今回作る helloworld アプリケーションはテキストボックスとボタンのみのウィジェットです。 サンプルコードの setup_ui の部分で UI を設定しています。 Qt デザイナと pyside-uic を使う方法もありますが、私は使ったことがないです。。。UI を作っていくポイントを抜粋すると、- 各ウィジェット (QWidget 及びサブクラス) に、レイアウト (QLayout のサブクラス) を設定する
- QVBoxLayout: 縦に配列していく
- QHBoxLayout: 横に配列していく
- QGridLayout: グリッド状に配列していく
- 他にも QFormLayout や QStackedLayout 等があります
- 各レイアウトに子供のウィジェットを追加していく
- ウィジェットをネストさせることで、より複雑な UI も表現できます
- 型を明示する
- settar が呼び出された後に signal を送出することができる (Python の property で書いて、setattr 時に emit しちゃってもいいけど・・・)
- 各ウィジェット (QWidget 及びサブクラス) に、レイアウト (QLayout のサブクラス) を設定する
- ユニットテストを書く
UI ができたら、ユニットテストを書きます (テストファースト :-)。Qt には QtTest というテスト用のフレームワークが用意されています。PySide では、このページにも記載されているように、Python の unittest モジュールを使ってユニットテストします。Qt はテストも signal-slot ベースです。ウィジェットにある signal が創出され、slot が処理した後に、ウィジェットがどうなっているか。QTest にいくつかの基本的なイベントを発生させるメソッドが用意されています。サンプルコードではボタンをクリックした際のテキストボックスの状態をテストしています。まだ signal-slot を実装していないので、テストは失敗するはず。 - イベント (signal-slot) を実装する
ユニットテストを通過できるように signal-slot を実装していきます。signal-slot の書き方は何種類かあります。サンプルコードの setup_events の箇所でイベントをセットアップしています。ここに connect をたくさん書いてもいいですが、子ウィジェットのイベントを再帰的にコネクトする connectSlotsByName を指定するのが好きです。コード量が少なくなるのでこの書き方を多用しています (イベントハンドラの追加をするたびに connect とか書きたくない)。
connectSlotsByName を利用すると、slot メソッドをdef on_<object name>_<signal name>(<signal parameters>)
という風に書けるようになります。 この object name は、各子ウィジェットに対し setObjectname で指定してあげる必要があります。サンプルコードでは、base_layout, lineedit, button すべてにセットしていますが、今回の要件を満たすには button ウィジェットだけセットすればいいです。これでサンプルコードのようにon_button_clicked
で button の clicked イベントの slot を作成できます。
以上、なんの面白くもないチュートリアルですが、 PySide での開発の流れが少しでも見えたら良いかなーと。
コメント
コメントを投稿