PyQtではじめるGUIプログラミング

212,524 views

Published on

2011-08-27に開催されたPyCon JP 2011のセッションで使用したスライドです。
サンプルプログラムのソースコードは http://alpa.homeip.net/files/PyConJP2011-SampleCodes.zip からDL可能です。
スライド内のURLをコピペすると文字コードの関係なのか何故か正しいURLとしてペーストできないので、注意してください。

Published in: Technology
4 Comments
205 Likes
Statistics
Notes
  • introduction of pyqt.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • MacOS X上ででPyQtの環境を作られた方がおられるようです。

    http://www.ninxit.com/blog/2011/08/29/pyqt-macos/

    参考にしてみてください。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 発表時のUSTREAMの録画が http://www.ustream.tv/recorded/16898833 で見れます。スライドに書いてないことなどを一部しゃべっていたりしていますので、こちらも合わせて見てもらえると、内容のさらなる理解につながるかと思います。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • サンプルプログラムのソースコードは

    http://alpa.homeip.net/files/PyConJP2011-SampleCodes.zip

    からDL可能です。スライド内のURLをコピペすると文字コードの関係なのか何故か正しいURLとしてペーストできないので、注意してください。
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
212,524
On SlideShare
0
From Embeds
0
Number of Embeds
115,308
Actions
Shares
0
Downloads
0
Comments
4
Likes
205
Embeds 0
No embeds

No notes for slide

PyQtではじめるGUIプログラミング

  1. 1. PyQtではじめるGUIプログラミング 2011-08-27 Python Conference JP 2011 Ransui Iso Strategic Technology Group / X-Listing Co, Ltd. Copyright (c) 2011 Ransui Iso, All rights reserved.
  2. 2. おまえ誰よ? Ransui Iso (磯 蘭水) Work at X-Listing Co, Ltd. http://www.xlisting.co.jp/Pythonは1998年から使っています。E-Commerceエンジンやサーチエンジンの開発、Zopeを用いたWebサイト開発、その他色々を経て、今はネット広告配信システムについての研究開発をしています。最近はCommon Lispでシステム開発をしていますが、Pythonもヘビーに使っています。 http://www.facebook.com/ransui @ransui Copyright (c) 2011 Ransui Iso, All rights reserved.
  3. 3. 今日お話する内容● QtとPyQtについて● 開発環境を整える● HelloWorld● QApplication と Event Loop● SIGNALとSLOT● GUIアプリケーション開発の基礎● 便利ツール : assistant, designer● Graphics, Multimedia, Web関連機能● さらに先へ行くために Copyright (c) 2011 Ransui Iso, All rights reserved.
  4. 4. 対象とするレベル● Pythonプログラミングの経験 – 午前中のセッション「Pythonチュートリアル」 – 書籍「はじめてのPython」 – Python公式ドキュメント「Pythonチュートリアル」 以上のいずれかをクリアしている方● GUIプログラミング経験 – 基本的にGUIプログラミング経験が無い方を想定 – tkinter, wxPython, PyGtk等の経験者の方はPyQt独特の 方法を学ぶ機会になるかと思いますが、多分ドキュメント読 めば独学できる内容 Copyright (c) 2011 Ransui Iso, All rights reserved.
  5. 5. その他注意点など● ハンズオンではありません – セッション時間内での演習時間等は予定していません – このスライドは自習時の参考にもなるように作っています● 当日はご参加ありがとうございました – サンプルコードは以下にあります。 – http://alpa.homeip.net/files/PyConJP2011­SampleCodes.zip● 質問はfacebook上で – twitterはあまり使っていないので、facebookのメッセージと かでコンタクトしてくれると反応するかもです。 Copyright (c) 2011 Ransui Iso, All rights reserved.
  6. 6. QtとPyQtについて Introduction of Qt and PyQt Copyright (c) 2011 Ransui Iso, All rights reserved.
  7. 7. Qtについて● クロスプラットフォームのC++総合ライブラリ – 最初期はGUIツールキットとして作られていたが、すぐにC++の総 合ライブラリに成長した – Windows, MacOSX, X11を主要として複数のプラットフォームに 対応している● ライセンス形態 – LGPL 2.1 + Commercial のデュアルライセンス● 読み方 – 「きゅーと」と読むらしい – 「きゅーてぃー」でもおおよそ通じると思われる Copyright (c) 2011 Ransui Iso, All rights reserved.
  8. 8. Qtを使っているもの● KDE● Google Earth● Picasa Client● VLC Media Player● Guitar Pro● Mathmatica● Skype Copyright (c) 2011 Ransui Iso, All rights reserved.
  9. 9. Qtのモジュール群● 総合ライブラリと呼ぶに相応しい充実度 ● QtCore ● QtScriptTools ● QtGui ● QtSql ● QtMultimedia ● QtSvg ● QtNetwork ● QtWebKit ● QtOpenGL ● QtXml ● QtOpenVG ● QtXmlPatterns ● QtScript ● Phonon ものすごく多機能で、提供されるコンポーネント量も膨大ですが、モジュール分 割の粒度と命名規則がスマートなので、使いたい機能を比較的楽に探し出せる Copyright (c) 2011 Ransui Iso, All rights reserved.
  10. 10. C++プログラミングの現実 C++闇の軍団が怖いので自粛します Copyright (c) 2011 Ransui Iso, All rights reserved.
  11. 11. 言語バインディング● まぁ色々と大変なのでもっと気軽に使いたい – いわゆるLL系言語を含んだ沢山の言語バインディングが あります Ada C# D Haskell Harbor Java CommonLisp Lua Ocaml Pascal Perl PHP Python R Ruby Scheme Tcl これで全部ではないはずです。 Copyright (c) 2011 Ransui Iso, All rights reserved.
  12. 12. PyQt● QtライブラリのPythonバインディング – Riverbank Computingという会社が作っている – 最新のQtバージョンへの対応はそれなりに速い – 主要なモジュールはほぼ全てサポートしている – SIPというC++とPythonを繋ぐ独自の仕組みで構築● ライセンス形態 – GPLv2 or GPLv3 (LGPLではないので注意) – Commercial License 有り ● PySideという別のバインディングもあります ● ライセンスはLGPLv2.1で使いやすいかも! Copyright (c) 2011 Ransui Iso, All rights reserved.
  13. 13. 開発環境の整備Install Python, PyQt and tools into your machine Copyright (c) 2011 Ransui Iso, All rights reserved.
  14. 14. インストールにあたって● Windowsへの導入について説明します – LinuxやMacOSを使っている人は自力で出来るでしょ? ● ほとんどのディストリのパッケージに登録されているはずなの でコマンド一発でインストールのはず● バージョンについて – Python Version 3.2.x for Windows ● PyQtを使う場合はPython3系が圧倒的に便利 – PyQt Version 4.8.5 for Windows ● PyQtをインストールすると自動的にQtも入る Copyright (c) 2011 Ransui Iso, All rights reserved.
  15. 15. Pythonのインストール● MSIパッケージでインストール – http://www.python.org/download – 多分これが一番楽 – x86とx86-64は別パッケージなので注意 – インストール位置とかはデフォルトのままが混乱が少な くてよい Copyright (c) 2011 Ransui Iso, All rights reserved.
  16. 16. 環境の確認 Ctrl-Z + Enter で終了できます Copyright (c) 2011 Ransui Iso, All rights reserved.
  17. 17. PyQtのインストール● Riverbankからインストーラを入手 – http://www.riverbankcomputing.co.uk/software/py qt – Python本体をデフォルトでインストールしていれば何 も変更ぜずにインストールしてしまえば良い。 Copyright (c) 2011 Ransui Iso, All rights reserved.
  18. 18. PyQtの動作確認PyQt Examples and Demos Copyright (c) 2011 Ransui Iso, All rights reserved.
  19. 19. エディタ・IDE● PyScripter : お勧めします – http://code.google.com/p/pyscripter – これもWindowsのインストーラがDLできる – デフォルトのオプションでインストールする – Pythonプログラミングするのに十分な機能を持ったIDE Copyright (c) 2011 Ransui Iso, All rights reserved.
  20. 20. Off-lineドキュメント● 別でDLする必要有り – http://qt.nokia.com/downloads – QtSDK Ver 1.1.2のWindows版Online installerをDL – Customインストールを選択 – 以下のようにドキュメントだけを選択してインストール 必要なコンポーネントのみが DLされインストールされる Copyright (c) 2011 Ransui Iso, All rights reserved.
  21. 21. Assistantの設定● ドキュメントブラウザにデータを設定する – Assistantを起動する メニューバーから 1:【編集(E)】→【設定】でダイアログを開く 2:【ドキュメント】タブを選択する 3:【追加】ボタンを押す 4: C:QtSDKDocumentationの中にある .qchファイルを全部選択して【開く】 ボタンを押す Copyright (c) 2011 Ransui Iso, All rights reserved.
  22. 22. やっと環境ができました● いよいよPyQtプログラミングの解説です – 今まで説明してきたインストール方法で環境が構築され ていることが前提です – カスタムインストールした環境ではそのまま動かない例 があるかもしれませんが、自助努力で頑張ってください – セッション中にデモすることがありますが、環境はKDE です。ちょっと見た目とか違いますが、全く同じコード がWindows環境でも動作しますので安心してください。 Copyright (c) 2011 Ransui Iso, All rights reserved.
  23. 23. HelloWorldWrite and run your first PyQt Application Copyright (c) 2011 Ransui Iso, All rights reserved.
  24. 24. とりあえず始めはこれ● PyScripterに以下のソースを書きこむ import sys import sys import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore import PyQt4.QtGui as QtGui import PyQt4.QtGui as QtGui def main(): def main():     app = QtGui.QApplication(sys.argv)     app = QtGui.QApplication(sys.argv)     main_window = QtGui.QMainWindow()     main_window = QtGui.QMainWindow()     hello_button = QtGui.QPushButton("波浪ワールド")     hello_button = QtGui.QPushButton("波浪ワールド")     main_window.setCentralWidget(hello_button)     main_window.setCentralWidget(hello_button)     main_window.show()     main_window.show()     app.exec_()     app.exec_() if __name__ == __main__: if __name__ == __main__:     main()     main() ファイル名とかはまだ付けなくても大丈夫 Copyright (c) 2011 Ransui Iso, All rights reserved.
  25. 25. 実行してみる● PyScripterから実行してみる – スクリプト実行ボタンを押す – メニューの[実行(R)]→[実行(R)]を選択する プログラムに間違いが無ければ、 左のように巨大なボタンが1個だ け配置されたウィンドウが表示さ れる。 ボタンはクリックできるけれど も、押してもなにも起こらない Copyright (c) 2011 Ransui Iso, All rights reserved.
  26. 26. 出てきたQtのコンポーネント● QApplication – QtのGUIプログラム全体をコントロールする – コマンドライン引数を要求するので sys.argv を渡す● QMainWindow – メインウィンドウを表現する● QPushButton – 基本的なボタンコンポーネント Copyright (c) 2011 Ransui Iso, All rights reserved.
  27. 27. setCentralWidget()● QMainWindowのレイアウトに関係している – MainWindowには、メニューバーやツールバーを配置す ることが多いが、QMainWindowは予めこれらをどこに 配置するかが考慮されている HelloWorldの例では CentralWidgetしか設定していな いので、他の領域は潰されて見え なくなっている Copyright (c) 2011 Ransui Iso, All rights reserved.
  28. 28. exec_() メソッド● イベントループを開始するメソッド ● GUIシステムはイベントドリブン方 Application 式で動いている ● Qtは下位のレイヤーが発するイベン トを拾ってアプリケーションに通知 Qt する必要がある Eventの取得 処理呼び出し X11 / Windows 結果の通知 OS / Device Driver ● この繰り返しをイベントループと呼 ぶ。イベントループが止まるとGUIKeyboard Mouse Monitor Audio 全体も止まってしまう Copyright (c) 2011 Ransui Iso, All rights reserved.
  29. 29. SIGNALとSLOTConnect control flow between widget and logic Copyright (c) 2011 Ransui Iso, All rights reserved.
  30. 30. イベントに応答するボタン● 前のソースに追加する import sys import sys import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore import PyQt4.QtGui as QtGui import PyQt4.QtGui as QtGui def on_click(): def on_click():     print("Hello World")     print("Hello World") def main(): def main():     app = QtGui.QApplication(sys.argv)     app = QtGui.QApplication(sys.argv)     main_window = QtGui.QMainWindow()     main_window = QtGui.QMainWindow()     hello_button = QtGui.QPushButton("波浪ワールド")     hello_button = QtGui.QPushButton("波浪ワールド") hello_button.clicked.connect(on_click) hello_button.clicked.connect(on_click)     main_window.setCentralWidget(hello_button)     main_window.setCentralWidget(hello_button)     main_window.show()     main_window.show()     app.exec_()     app.exec_() if __name__ == __main__: if __name__ == __main__:     main()     main() Copyright (c) 2011 Ransui Iso, All rights reserved.
  31. 31. SIGNAL● イベント処理のインタフェース – connect()を使って処理ルーチンと接続する QMouseEvent QPushButton button on_click() clicked position globalPosition pressed releasedマウスのボタン操作に関する 内部状態に応じて適切な 処理ハンドラは普通のイベントがEvent Loopから SIGNALがアクティブになる Python関数で良い送られてくる – アプリケーションはイベントの詳細を知らずとも 「何が起こったか」だけを見れば良い Copyright (c) 2011 Ransui Iso, All rights reserved.
  32. 32. 状態を伴ったSIGNAL● QCheckBoxで見てみる def print_state(state): def print_state(state):     if state == 0:     if state == 0:         print("Unchecked")         print("Unchecked")     else:     else:         print("Checked")         print("Checked") def main(): def main():     app = QtGui.QApplication(sys.argv)     app = QtGui.QApplication(sys.argv)     main_window = QtGui.QMainWindow()     main_window = QtGui.QMainWindow()     check_box = QtGui.QCheckBox("Check box")     check_box = QtGui.QCheckBox("Check box") check_box.stateChanged.connect(print_state) check_box.stateChanged.connect(print_state)     main_window.setCentralWidget(check_box)     main_window.setCentralWidget(check_box)     main_window.show()     main_window.show()     app.exec_()     app.exec_() ソースコードは抜粋です Copyright (c) 2011 Ransui Iso, All rights reserved.
  33. 33. SIGNAL付随の状態を受け取る● 引数部分を指定された型で取得できる QCheckBox stateChanged(int) print_state(state) clicked(void) pressed(void) released(void) – QCheckBox の stateChanged の場合は、チェックさ れている場合は1、されていない場合は0がint型で引数 としてconnectしているハンドラに渡される Copyright (c) 2011 Ransui Iso, All rights reserved.
  34. 34. コンポーネント同士を直結する● SIGNALとSLOTを接続する – SLOTはSIGNALの受け口関数 QPushButton QCheckBox clicked stateChanged print_state() pressed pressed released toggle releasedbutton.clicked.connect(check_box.toggle) button.clicked.connect(check_box.toggle)check_box.stateChanged.connect(print_state) check_box.stateChanged.connect(print_state)SLOTも普通の関数のようにconnectのターゲットに指定できる。ただしSIGNALとSLOTを直結する場合は受け渡す値のC++型が一致している必要があるので注意する。型の調べ方は後で説明する Copyright (c) 2011 Ransui Iso, All rights reserved.
  35. 35. わざわざconnectする理由● 疎結合にしておくことによるご利益 – 相互作用のトリガが明示されるので理解しやすい – コンポーネント間の相互作用がロジックに埋もれない – インタフェースが同じなら簡単に差し替え可能 – 必要なSIGNALのみに処理をconnectすれば良い – 1つのSIGNALに複数のハンドラを設定できる – SIGNALとハンドラの接続は実行時に設定&解除可能● Qtは徹底して疎結合モデル – 大規模なシステムを設計する時の極めて強力な1つの手 法として大いに参考にできる Copyright (c) 2011 Ransui Iso, All rights reserved.
  36. 36. ラーメンタイマーA tiny example for design and develop GUI application Copyright (c) 2011 Ransui Iso, All rights reserved.
  37. 37. ラーメンタイマー伝説● 2chのスレッド – 「Linux使ってこりゃ普及するわけないと思ったとき」 873:login:Penguin:2009/01/24(土) 23:53:21 ID:AI280zEEdownup 873:login:Penguin:2009/01/24(土) 23:53:21 ID:AI280zEEdownup だいたいLinuxなんてラーメンタイマーさえ作れないだろ。 だいたいLinuxなんてラーメンタイマーさえ作れないだろ。 開発環境が整っているとかソフトが豊富で安定してて楽チンとか 開発環境が整っているとかソフトが豊富で安定してて楽チンとか 宣伝する割にはさ。 宣伝する割にはさ。 それ考えるとWindowsってよく出来てるんじゃない? それ考えるとWindowsってよく出来てるんじゃない? 素人でもラーメンタイマーくらいすぐ作れるし。 素人でもラーメンタイマーくらいすぐ作れるし。● Uncyclopediaの「Linux」の記事 主な利用者 主な利用者 エセSE エセSE 低レベルなサーバー管理者 低レベルなサーバー管理者 ただのオタク ただのオタク ニコニコ動画で3Dデスクトップの動画を見たリア厨 ニコニコ動画で3Dデスクトップの動画を見たリア厨 偉そうに語るくせに、ラーメンタイマー1つまともに作ることもできないエセ開発者 偉そうに語るくせに、ラーメンタイマー1つまともに作ることもできないエセ開発者 Copyright (c) 2011 Ransui Iso, All rights reserved.
  38. 38. 練習題材としてはなかなか良い● 実装例:RamenTimer.py – 3分間カウントダウンするだけの単純なもの 2chのスレッドではQtは反則ということになっていたようだが PyQtセッションなので躊躇なく使うことにする Copyright (c) 2011 Ransui Iso, All rights reserved.
  39. 39. まずは構想&デザイン● いきなりコードを書き始めると100%死にます – GUIコンポーネント(Widget)の配置 ● スケッチを書いてみる ● 機能に注目してUIの領域を分割してみる – プログラムを構成するコンポーネントの階層関係 ● UI上の領域と機能の両方を考慮しながらクラスの構成を考える – コンポーネント間の相互作用 ● SIGNAL, SLOT, クラスメソッドがどのように連携するかを整理する – 「設計」ではなく「デザイン」という観点が大切 ● なかなか言葉で表現しにくい ● デザイン中は対象がどんどん変化するので「形式」に拘るのは非効率 Copyright (c) 2011 Ransui Iso, All rights reserved.
  40. 40. コンセプトを決める● コンセプトは成果物の基本方針 – GUIは「見た目」という強烈な刺激があるので「思いつき」が発生しやす く、開発中にあらぬ方向へ進み出す危険性が高い – 自分が「なにをしたいのか」「何を作っているのか」を確認するために適 時振り返るためにもコンセプトは重要 – 「ココが重要」「これは譲れない」という事項を列挙しただけの簡単なも のでも十分に機能する● ラーメンタイマーの場合 – タイマーなので数字は「見やすく」「でっかく」表示したい – 1/100秒単位で表示するとカッコイイかも – カウントダウン中に一時停止やカウンタ値リセットがあると便利 – 見ただけで操作が分かるようにしたい – とりあえずは3分固定でOK – ... 等々 ... Copyright (c) 2011 Ransui Iso, All rights reserved.
  41. 41. GUIレイアウト● コンセプトに基づいてスケッチしてみる – 実際に行うときは「紙と鉛筆」を推奨 ● PC上でパワポとか使って検討するのは本当に時間の無駄 ● 「イケテル!」と確信できた時点で清書すればいい – 機能単位に「まとまっている」所を探してみる カウントダウンを実行して表 示する部分 操作を行う部分 Copyright (c) 2011 Ransui Iso, All rights reserved.
  42. 42. コンポーネントの選定と配置 ● コンポーネントを積み重ねて構成する – この段階で利用するコンポーネントの当たりをつけるQWidget:QVBoxLayoutQLCDNumberとQTimerを配置する QLCDNumber QLCDNumber QPushButton QPushButton QPushButton QPushButton QWidget:QGridLayout QPushButtonを格子状に QPushButton QPushButton 配置する QPushButton QPushButton QWidget:QVBoxLayout QMainWindowのCentralWidgetに指定する 上に乗る2つのレイヤーを縦方向に整列して配置する Copyright (c) 2011 Ransui Iso, All rights reserved.
  43. 43. コンポーネントの階層構造● コンポーネントの親子関係等を図で整理する QMainWindow QWidget attribute QTimer main_window CountDownWidget timer CentralWidget QVBoxLayout QLCDNumber QWidget instance addWidget lcd_number panel countdown_widget QVBoxLayout addWidget QPushButton addWidget start_button QWidget QPushButton ButtonBoxWidget stop_button QGridLayout QPushButton instance reset_button button_box_widget QPushButton quit_button Copyright (c) 2011 Ransui Iso, All rights reserved.
  44. 44. コンポーネントの相互作用● これも図を書いて整理しておくと良い start_button timer start_countdown start clicked timeout stop stop_button stop_countdown clicked do_countdown reset_button reset_count lcd_number clicked display update_display quit_button update clicked CountDownWidget app ButtonBoxWidget quit Copyright (c) 2011 Ransui Iso, All rights reserved.
  45. 45. 新出コンポーネントのまとめ● どれも基本的なものでよく使います – QWidget ● UIを構成する全てのコンポーネントのスーパークラス ● 今回はパーツを束ねるコンテナ(トレイ)として使用 – QLCDNumber ● 液晶風の数値表示ウィジェット – QTimer ● 一定時間毎に指定された処理を呼び出す – QGridLayout, QVBoxLayout ● GUIパーツを整列させるためのレイアウトマネージャ Copyright (c) 2011 Ransui Iso, All rights reserved.
  46. 46. ButtonBoxWidgetの実装● まずは方針を確認する – こんな感じに作る予定だったはず addWidget QPushButton start_button QWidget QPushButton ButtonBoxWidget stop_button QGridLayout QPushButton reset_button QPushButton quit_button Copyright (c) 2011 Ransui Iso, All rights reserved.
  47. 47. ButtonBoxWidgetのコード● 素直にコードに落とす class ButtonBoxWidget(QtGui.QWidget): class ButtonBoxWidget(QtGui.QWidget):     def __init__(self, parent=None):     def __init__(self, parent=None):         QtGui.QWidget.__init__(self, parent=parent)         QtGui.QWidget.__init__(self, parent=parent)         self.setup_ui()         self.setup_ui()     def setup_ui(self):     def setup_ui(self):         self.start_button = QtGui.QPushButton("STRAT", parent=self)         self.start_button = QtGui.QPushButton("STRAT", parent=self)         self.stop_button = QtGui.QPushButton("STOP", parent=self)         self.stop_button = QtGui.QPushButton("STOP", parent=self)         self.reset_button = QtGui.QPushButton("RESET", parent=self)         self.reset_button = QtGui.QPushButton("RESET", parent=self)         self.quit_button = QtGui.QPushButton("QUIT", parent=self)         self.quit_button = QtGui.QPushButton("QUIT", parent=self)         layout = QtGui.QGridLayout()         layout = QtGui.QGridLayout()         layout.addWidget(self.start_button, 0, 0)         layout.addWidget(self.start_button, 0, 0)         layout.addWidget(self.stop_button, 0, 1)         layout.addWidget(self.stop_button, 0, 1)         layout.addWidget(self.reset_button, 1, 0)         layout.addWidget(self.reset_button, 1, 0)         layout.addWidget(self.quit_button, 1, 1)         layout.addWidget(self.quit_button, 1, 1)         self.setLayout(layout)         self.setLayout(layout) Copyright (c) 2011 Ransui Iso, All rights reserved.
  48. 48. CountDownWidgetの実装● 方針を確認する – こちらは処理メソッドを実装しないといけない QWidget attribute QTimer CountDownWidget timer QVBoxLayout QLCDNumber addWidget lcd_number timer start_countdown start timeout stop stop_countdown do_countdown reset_count lcd_number display update_display update Copyright (c) 2011 Ransui Iso, All rights reserved.
  49. 49. CountDownWidget:UIコード● サイズが自動伸長されるようにしてある class CountDownWidget(QtGui.QWidget): class CountDownWidget(QtGui.QWidget):     def __init__(self, parent=None):     def __init__(self, parent=None):         QtGui.QWidget.__init__(self, parent=parent)         QtGui.QWidget.__init__(self, parent=parent)         self.interval = 10         self.interval = 10         self.setup_ui()         self.setup_ui()     def setup_ui(self):     def setup_ui(self):         self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)         self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)         self.timer = QtCore.QTimer(parent=self)         self.timer = QtCore.QTimer(parent=self)         self.timer.setInterval(self.interval)         self.timer.setInterval(self.interval)         Self.timer.timeout.connect(self.do_countdown)         Self.timer.timeout.connect(self.do_countdown)         self.lcd_number = QtGui.QLCDNumber(parent=self)         self.lcd_number = QtGui.QLCDNumber(parent=self)         self.lcd_number.setSizePolicy(QtGui.QSizePolicy.Expanding,         self.lcd_number.setSizePolicy(QtGui.QSizePolicy.Expanding,                                       QtGui.QSizePolicy.Expanding)                                       QtGui.QSizePolicy.Expanding)         self.lcd_number.setFrameStyle(QtGui.QFrame.NoFrame)         self.lcd_number.setFrameStyle(QtGui.QFrame.NoFrame)         self.lcd_number.setSegmentStyle(QtGui.QLCDNumber.Flat)         self.lcd_number.setSegmentStyle(QtGui.QLCDNumber.Flat)         self.lcd_number.setDigitCount(6)              self.lcd_number.setDigitCount(6)              layout = QtGui.QVBoxLayout()         layout = QtGui.QVBoxLayout()         layout.addWidget(self.lcd_number)         layout.addWidget(self.lcd_number)         self.setLayout(layout)         self.setLayout(layout)         self.reset_count()         self.reset_count() Copyright (c) 2011 Ransui Iso, All rights reserved.
  50. 50. CountDownWidget:処理部分● 以下のようになる     def update_display(self):     def update_display(self):         self.lcd_number.display("%6.2f" % (self.count / 100))         self.lcd_number.display("%6.2f" % (self.count / 100))         self.lcd_number.update()         self.lcd_number.update()     def do_countdown(self):     def do_countdown(self):         self.count ­= 1         self.count ­= 1         self.update_display()         self.update_display()         if self.count <= 0:         if self.count <= 0:             self.stop_countdown()             self.stop_countdown()     def start_countdown(self):     def start_countdown(self):         if self.count > 0:         if self.count > 0:             self.timer.start()             self.timer.start()     def stop_countdown(self):     def stop_countdown(self):         self.timer.stop()         self.timer.stop()     def reset_count(self):     def reset_count(self):         self.count = 18000         self.count = 18000         self.update_display()         self.update_display() Copyright (c) 2011 Ransui Iso, All rights reserved.
  51. 51. MainWindowとかの構成● 方針の確認 QMainWindow QWidget main_window CountDownWidget QVBoxLayout CentralWidget instance QWidget addWidget panel countdown_widget QVBoxLayout QWidget ButtonBoxWidget QGridLayout instance button_box_widget Copyright (c) 2011 Ransui Iso, All rights reserved.
  52. 52. 全体の構成コード● main関数として実装してみる def main(): def main():     app = QtGui.QApplication(sys.argv)     app = QtGui.QApplication(sys.argv)     panel = QtGui.QWidget()     panel = QtGui.QWidget()     countdown_widget = CountDownWidget(parent=panel)     countdown_widget = CountDownWidget(parent=panel)     button_box_widget = ButtonBoxWidget(parent=panel)     button_box_widget = ButtonBoxWidget(parent=panel)     panel_layout = QtGui.QVBoxLayout()     panel_layout = QtGui.QVBoxLayout()     panel_layout.addWidget(countdown_widget)     panel_layout.addWidget(countdown_widget)     panel_layout.addWidget(button_box_widget)     panel_layout.addWidget(button_box_widget)     panel.setLayout(panel_layout)     panel.setLayout(panel_layout)     panel.setFixedSize(320, 200)     panel.setFixedSize(320, 200)     main_window = QtGui.QMainWindow()     main_window = QtGui.QMainWindow()     main_window.setWindowTitle("Ramen Timer")     main_window.setWindowTitle("Ramen Timer")     main_window.setCentralWidget(panel)     main_window.setCentralWidget(panel)     main_window.show()     main_window.show() Copyright (c) 2011 Ransui Iso, All rights reserved.
  53. 53. SIGNALの接続● main関数内で行う def main(): def main():     app = QtGui.QApplication(sys.argv)     app = QtGui.QApplication(sys.argv)     ... 中略 ...     ... 中略 ... button_box_widget.start_button.clicked.connect( button_box_widget.start_button.clicked.connect( countdown_widget.start_countdown) countdown_widget.start_countdown) button_box_widget.stop_button.clicked.connect( button_box_widget.stop_button.clicked.connect( countdown_widget.stop_countdown) countdown_widget.stop_countdown) button_box_widget.reset_button.clicked.connect( button_box_widget.reset_button.clicked.connect( countdown_widget.reset_count) countdown_widget.reset_count) button_box_widget.quit_button.clicked.connect( button_box_widget.quit_button.clicked.connect( app.quit)   app.quit)                 app.exec_()     app.exec_() Copyright (c) 2011 Ransui Iso, All rights reserved.
  54. 54. ラーメンタイマー完成● 実際に動かしてみる● デザインワークは超大切● よりよいラーメンタイマーを目指して – ラーメン出来上がりまで画面注視とかどんだけ – 5分のラーメンもあるんですけど – 2杯同時に作るときお湯入れるの時間差あるんですが – ワシは「麺硬め」だが奴は「普通」が好みらしい – 後入れスープやってる間に麺が伸びちゃうのはNG 明日のSprintのネタとしてやってみても楽しいかと Copyright (c) 2011 Ransui Iso, All rights reserved.
  55. 55. 開発ツールIntroduce some tools for Qt programming Copyright (c) 2011 Ransui Iso, All rights reserved.
  56. 56. assistant● Qtのドキュメントビュアー – Webでも参照できるが専用ビュアーは色々と便利 – これを使いこなせるようになれば脱初心者 – 基本英語だけどがんばって! Copyright (c) 2011 Ransui Iso, All rights reserved.
  57. 57. designer● GUIレイアウト作成ツール – このツールから入門したくなるという誘引力は強烈 Copyright (c) 2011 Ransui Iso, All rights reserved.
  58. 58. designerの暗黒面 注意・警告 一見初心者に優しげなこのツールは実は 上級者向け。QtのGUI構成の基本が分 かっていない時点で使うと自動生成され るコードに振り回される等の「害あって も益無し」状態になる可能性が高い まずは基本をしっかりマスターしてから 「手間を減らす」ツールとして使うこと を推奨 Copyright (c) 2011 Ransui Iso, All rights reserved.
  59. 59. GraphicsHow to draw graphics on widget Copyright (c) 2011 Ransui Iso, All rights reserved.
  60. 60. Graphicsの取り扱い● 実装例:アナログ時計 QtにはOpenGLサポート等の高度なグラフィックス 処理機能があるが、今回は最も基本的な機能を使って 作ってみる Copyright (c) 2011 Ransui Iso, All rights reserved.
  61. 61. コンポーネント構成● 操作する部分が無いのでシンプル QMainWindow QWidget attribute QTimer main_window ClockWidget timer instance CentralWidget QPixmap clock_widget offscreen setup_ui timer offscreen start timeout draw_scales drawing 20 times/sec QPaintEvent draw_needles redraw_clock use paintEvent ClockWidget Copyright (c) 2011 Ransui Iso, All rights reserved.
  62. 62. Graphics描画機能● QPainterというコンポーネントを使う painter = QtGui.QPainter() painter = QtGui.QPainter() 描画対象を指定 painter.begin(self.pixmap) painter.begin(self.pixmap) 描画方法の設定 painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setPen(QtGui.QPen(QtCore.Qt.white, 4) painter.setPen(QtGui.QPen(QtCore.Qt.white, 4) 描画処理 painter.drawLine(10, 10, 100, 100) painter.drawLine(10, 10, 100, 100) painter.drawPixmap(30, 10, foo_pixmap) painter.drawPixmap(30, 10, foo_pixmap) 描画終了 painter.end() painter.end() Copyright (c) 2011 Ransui Iso, All rights reserved.
  63. 63. Tiny Media PlayerHow to playback sound and video data with Qt Copyright (c) 2011 Ransui Iso, All rights reserved.
  64. 64. メディアデータの再生● 超単純なメディアプレーヤー – Phononというメディア再生フレームワークを使う Copyright (c) 2011 Ransui Iso, All rights reserved.
  65. 65. コンポーネント構成● 1個のwidgetに全部載せる構成にしている QMainWindow QWidget Phonon.VideoPlayer main_window VideoPlayerWidget player QVBoxLayout instance addWidget CentralWidget instance QHBoxLayout video_player_widget QPushButton play_pause_button addWidget Phonon.SeekSlider slider Layoutの上に直接Layoutを追加することができる ● これをうまく使うと相当複雑なレイアウトも実現できる Copyright (c) 2011 Ransui Iso, All rights reserved.
  66. 66. Web BrowserQt has WebKit based browser component Copyright (c) 2011 Ransui Iso, All rights reserved.
  67. 67. QWebKitを使ってみる● 簡易ブラウザなら簡単に作成可能 ● 自作アプリの一部にHTMLVewer として組み込む ● HTMLパーサとして利用(DOMに アクセスできる) ● ユーザのアクション(リンクク リック等)を全てHookできるの で挙動のカスタマイズはやり放 題 ● 本当にHTML+CSS+Javascript レンダリングの機能しかないの で、それなりに使えるブラウザ にするためには結構コードを書 かなくちゃいけない Copyright (c) 2011 Ransui Iso, All rights reserved.
  68. 68. GUIはdesignerを使ってみた● レイアウトの階層構造を意識しながら作る 今回はQMainWindowにメニューバーとステータスバー も追加している Copyright (c) 2011 Ransui Iso, All rights reserved.
  69. 69. Pythonモジュールの生成● pyuic4 コマンドを使う – designerは .ui というXMLファイルを吐き出す – pyuic4 ­­help でオプションを確認できる – 基本は以下のように使う ● pyuic4 ­o foo_ui.py foo.ui – 出力されるモジュールファイルは手で編集しない – 利用の例はソースコードを参照 ● この例では TinyBrowser.py がメインで MainWindowUI.py が pyuic4 で生成されたGUIコンポーネントのモジュール ● designerを使う場合は、GUIとLogicはモジュール単位で分割され ることになる Copyright (c) 2011 Ransui Iso, All rights reserved.
  70. 70. 次のステップへRecommended resources and informations about Qt Copyright (c) 2011 Ransui Iso, All rights reserved.
  71. 71. Qtプログラミングの情報源● Qt/PyQtはドキュメントが超充実 – ふんだんに用意されているプログラミング例はC++で書 かれているが、Pythonプログラミングの練習にもなる ので、どんどん移植してみよう● 書籍 – 日本語で読めるものは少ない! – OREILLY「入門 Qt4 プログラミング」 ● すごく高度な技が載っているわけではない が、基本的なGUIコンポーネントをまんべん なく取り扱っている。Qtドキュメントとの 併読がお勧め Copyright (c) 2011 Ransui Iso, All rights reserved.
  72. 72. Thank you for listening Happy Hacking with PyQt Copyright (c) 2011 Ransui Iso, All rights reserved.

×