nano_exit

基礎的なことこそ、簡単な例が必要だと思うのです。

PyQt: トップダウンで作るラーメンタイマー

下記サイト様を参考にラーメンタイマーを作成する。
PyQtではじめるGUIプログラミング
非常に分かり易く説明されていて、個人的にかなり気に入っている。
基本的にはボトムアップ(端っこの部品から作っていく)で記述して行くので、トップダウンを意識して話を作っても良いかと思い、やってみた。細かい話は参照サイト様をお願いしたい。

使うmoduleの宣言

import sys
import PyQt5.QtWidgets as QWs

ラーメンタイマーのウィンドウを表示させる部分。

def main():
  app = QWs.QApplication( sys.argv )

  # Control outside looking
  panel = QWs.QWidget()

  mw = QWs.QMainWindow()
  mw.setWindowTitle( "Ramen Timer" )
  mw.setCentralWidget( panel )
  mw.show()
  app.exec_()

if __name__ == "__main__":
  main()

QWidgetのインスタンス(ここではpanelという名前)をmw.setCentralWidgetに食わせているため、panelを作り込んで行くことで、どんどんラーメンタイマーになっていく。
一応、ここまででもスクリプトは動くが、panelを何も弄っていないため、Ramen Timerと書かれたWindowだけが出てくる。
でも一応動くから安心感はあると思う。最終段階まで動くか動かないかわからないのは精神衛生上良くないので。

とりあえずスタートボタンを追加する。
ボタンを制御するクラスを記述。

class ButtonBoxWidget( QWs.QWidget ):
  def __init__( self, parent=None ):
    QWs.QWidget.__init__( self, parent=None ):
    self.setup_ui()

  def setup_ui( self ):
    self.start_button = QWs.QPushButton( "START", parent=self )

    layout = QWs.QGridLayout()
    layout.addWidget( self.start_button, 0, 0 )

    self.setLayout( layout )

__init__の中身はまだ勉強不足で理解出来ていない。
setup_uiはソースを整理して見易くするために導入されている。そのため__init__内にベタ打ちしても動く。可読性を上げる関数の使い方は参考になる。

panel周辺は以下の様に変更。

  panel = QWs.QWidget()
  panel_layout = QWs.QVBoxLayout()

  button_box_widget = ButtonBoxWidget( parent=panel )
  panel_layout.addWidget( button_box_widget )

  panel.setLayout( panel_layout )
  • アイテム配置用のインスタンス(panel_layout; 今回は後で"箱"を縦に並べて配置するのでQVBoxLayoutを使用)を用意して、そこに先ほど作ったButtonBoxWidgetのインスタンスをLayoutのクラス関数addWidgetで乗せる。
  • ButtonBoxWidgetはparent=panelと繋げておく(この辺の仕組みはまだ理解できていない)。
  • panel_layoutを弄り終わったら、setLayoutでpanelにちゃんと乗せておく。

この時点でスクリプトを起動すると、"START"と書かれたボタンだけが出てくる。他のボタン(例えば"STOP")はstart_buttonと同様にButtonBoxWidgetに記述することで作れる。

したがって、あとは

  1. classを作成・編集してアイテムを作る・作り込む
  2. 作ったclassのインスタンスをpanelに繋げて記述
  3. panel_layoutでインスタンスを突っ込んで、panelに乗せる

を繰り返す。
アイテムを一つ作るごとにスクリプトを動かして確認出来るため、理解を深め易いと思う。

GUIの外見はこれで割と直感的に作れると思う。
あとは実際の動く部分だが、それぞれの部品の動きは各クラスなりpython関数で記述出来ると思う(カウントダウンで数字を減らしていくところは、PyQtのconnectの概念が必要ではあるが)。
それぞれの部品を繋げるのは、Widgetのクラス関数connectで信号を関数に受け渡す(もしくは関数を呼ぶ)ことで実現する。

# bellow mw.show()
button_box_widget.start_button.clicked.connect( countdown_widget.start_countdown )
# above app_exec_()

カウントダウンのクラスについてここでは記述していないが、カウントダウンを始めるクラス関数を自分で作っておき、その関数start_countdownに信号を渡すようにしている。カウントダウンのクラスの詳細は参照サイトを見て頂きたい。
clickedはクラスQPushButtonの持つ関数(クラス?)で、ボタンをクリックした時にどんなアクションをするかを記述出来る。
つまり、
"START"ボタンをクリックするとstart_countdownが呼ばれる
と言う流れである。

一つ一つすぐに確認しながら出来るのはスクリプト言語の強みだと思うので、ちょっとずつ出来上がっていくはやっぱり楽しい。