[PR]今日のニュースは
「Infoseek モバイル」


Python+Qt=PyQt

 QtはC++用のGUIツールキットです。ということで、各ウィジェット(GUI部品) のデータ構造にもC++ベースのオブジェクト指向の方法論が大々的に導入されています。 簡単に言うと、Qtは、 各ウィジェットをクラスとして定義したC++のクラスライブラリというわけです。 PyQtは数少ないQtのスクリプト言語バインディングですが、 Pythonがオブジェクト指向のスクリプト言語、QtがC++のクラスライブラリ、 というわけで、親和性は非常によいです。 また、本来のQtアプリケーションはビルドするときにメタオブジェクトコンパイラ (moc)などを使うためにソースプログラムを分割する必要があり、 ソースプログラムの管理がどうしても煩雑になってしまうわけですが、 PyQtを使えばスクリプトを書けばすぐ実行できるためとても楽になっています。

 PyQtの現在のバージョンは3.2.4で、着実に進化の道を歩み続けています。 PyQt 3.2.4はPython 1.5〜2.2.1とQt 1.42〜3.0.4に対応しています。 こちらが現在の総本山です。 PyQtはQtと全く同じ方法で日本語の文字も扱うことができます。


PyQtのインストール

 PyQtをインストールするには、当然といえば当然ですが、 Python処理系とQtのライブラリを先に別途インストールしておく必要があります。 で、それとは別に、「sip」というツールもインストールしておかないといけません。 これは、ムッチャいい加減な言い方をすると、 Qtのクラス定義をPythonのスクリプトに自動変換するような(みたいなことをする) ツールで、上のPyQtと同じ場所からダウンロードできます。
 ここでは、 Linux 2.2.14(Official RedHat Linux 6.1J)上での、 次のバージョンの組み合わせでインストールを行ったので、その手順をご紹介します。
PythonQtsipPyQt
1.6α22.1.10.120.12
2.0β12.1.12.02.0
2.1.12.3.12.52.5
2.1.13.0.13.03.0
2.2.13.0.43.2.43.2.4

sip(2.5〜3.2.4)のインストール手順

  1. ソースアーカイブを展開します。
    % tar xozf sip-3.2.4.tar.gz
    % cd sip-3.2.4
    
  2. configureスクリプトを動かします。このとき、下のように Qtのトップディレクトリ(環境変数QTDIRが指定されていたら、そのディレクトリ) とPythonの実行形式のパスをスイッチで指定します。 ただし、環境変数QTDIRがセットされている場合は、 そのパスが--with-qt-dirの代わりになるのでこのオプションは省略できます。 また--with-pythonを省略した場合には、単に「python」 と打ったときに使われるPythonの処理系が対象になります。
    % sh configure --with-qt-dir=/usr/local/qt \
      --with-python=/usr/local/bin/python
    
    sip-2.0の場合は、 Pythonのヘッダファイルのディレクトリ(python.hがあるディレクトリ) をスイッチで指定します。
    % sh configure --with-qt-dir=/usr/local/qt \
      --with-python-includes=/usr/local/include/python2.0
    
  3. makeとmake installでコンパイル・インストールします。
    % make
    % su root
    # make install
    

PyQt(2.5〜3.2.4)のインストール

  1. ソースアーカイブを展開します。
    % tar xozf PyQt-3.2.4.tar.gz
    % cd PyQt-3.2.4
    
  2. configureスクリプトを動かします。このとき、下のように Qtのトップディレクトリ、Pythonの実行形式のパスを指定します。 これもsipのときと同様、環境設定次第で省略できます。
    % sh configure --with-qt-dir=/usr/local/qt \
      --with-python=/usr/local/bin/python
    
    PyQt-2.0ではもっと長くなります。
    % sh configure --with-qt-dir=/usr/local/qt \
      --with-python-includes=/usr/local/include/python2.0 \
      --with-python-modules=/usr/local/lib/python2.0 \
      --with-sip-includes=/usr/local/include/sip \
      --with-sip-libraries=/usr/local/lib
    
  3. makeとmake installでコンパイル・インストールします。
    % make
    % su root
    # make install
    
  4. これでインストールは完了です。 examplesディレクトリのスクリプトを実行してみて、 QtのGUIが出てくれば大成功です。
    % cd /the/path/of/PyQt-3.0/examples
    % ./tut2.py &
    

    インストールの途中でエラーになってしまう場合は、 インストールを実行するユーザの環境変数LD_LIBRARY_PATHが Qtの共有ライブラリlibqt.so.*に通っていることを確認します。 これが通っていないのが、最もよくあるエラー原因でしょう。 私も何度かはまりましたー(とほほほほ)。
    実は、PyQt 2.5を「make install」しようとすると、 「libsip.so.6.0.0: undefined symbol: translate_QApplication...」 というエラーで止まってしまいました。 しかし、通常ユーザーに戻ってPythonインタープリタから「import qt」 とすると普通に動いたので、よしとしませうか…(おーい)


Hello, PyQt World

 PyQtもPython/Tkinterと同様、 ウィンドウ全体をクラス定義する方法としない方法がありますが、 PyQtではほぼ必ずクラス定義する方法になるでしょう。 最初だけ、クラスを使わない方法で、 おなじみ「Hello, World」です。

# PyQtの決まり文句はこれ。
import sys
from qt import *

a = QApplication(sys.argv)
w = QWidget()
w.resize(200, 80)

la = QLabel('Hello, World.', w)
cmda = QPushButton('OK', w)
la.resize(100, 20)
la.move(50, 10)
# ↓PyQt 0.12の場合
#la.setFont(QFont('Helvetica', 14, QFont.Weight.Normal))
# ↓PyQt 2.0〜の場合
la.setFont(QFont('Helvetica', 14, QFont.Normal))
cmda.resize(40, 20)
cmda.move(130, 40)

QObject.connect(cmda, SIGNAL('clicked()'), a, SLOT('quit()'))

a.setMainWidget(w)
w.show()
a.exec_loop()
# end.

 基本的な書き方はC++の本来のQtにとてもよく似ています。 C++のポインタ演算子 -> の代わりに . を使うため、見た目には Java言語のプログラムみたいにも見えますね。

スクリーンショット

ちょっとメモ(1) - 載せる処理は?
C++でQtを使ったらおなじみですが、Qtでは、 ウィジェットを作るときのコンストラクタで自分を載せる親ウィジェットを引数で指定 (Qtのクラスには大抵複数のコンストラクタがありますが大抵最後の引数です) するのですが、その後「載せる」というアクションを書く必要はなく、 一番土台になるウィジェット(=ウィンドウ)が出ると自動的に全部のウィジェットが表示されます。


さっそくクラス

 QtはGUIイベントの処理にシグナルとスロットという独特の機構を使います。 このため、これ以上先に進もうとするとクラスを定義するしかなくなります。 というわけで、今度は上の例を「HelloWidget」というクラスにしたサンプルです。 今度はボタンを押すと終了する代わりに「Hello, World」と書き出します。

import sys
from qt import *

# QWidgetを継承します。
class HelloWidget(QWidget):

  # いわゆるスロットですが、まったく普通のメソッドとして
  # 定義すればOKです。特別なキーワードは不要です。
  def hello(self):
    print 'Hello, World.'

  # コンストラクタ。仮引数の形はこれで固定です
  def __init__(self, *args):
    # この apply は定石ということで使い回しOK
    apply(QWidget.__init__, (self,)+args)
    self.resize(200, 80)

    la = QLabel(self)
    la.setText('Hello, World.')
    cmda = QPushButton(self)
    cmda.setText('Push Me!')
    la.resize(100, 20)
    la.move(50, 10)
    # ↓PyQt 0.12の場合
    #la.setFont(QFont('Helvetica', 14, QFont.Weight.Normal))
    # ↓PyQt 2.0〜の場合
    la.setFont(QFont('Helvetica', 14, QFont.Normal))
    cmda.resize(60, 20)
    cmda.move(130, 40)

    # スロットに特別な宣言は不要です。単にメソッドの名前を
    # 指定するだけでシグナル/スロット機構に登録されます。
    self.connect(cmda, SIGNAL("clicked()"), self.hello)

# アプリケーションを初期化
a = QApplication(sys.argv)
# 定義したクラスのインスタンスをつくり、あとは決まりきった処理です
w = HelloWidget()
a.setMainWidget(w)
w.show()
a.exec_loop()
# end.

 上の例のように、Qtの標準クラスQWidgetを継承した独自のクラスを 1つ作り、それをQApplicationのメインウィジェットとする形が最も一般的でしょう。 ナニをもって一般的と呼ぶかというのは、 ちょうどJavaのAWT/Swingアプリケーションがこのような構造をとるので、 PyQtでも同じような書き方をするのがより多くの方に理解しやすいと思われると思ったからです。 実際このコード例を見ると、なんだか本当にJava言語のプログラムみたいですね。 おおっと、PythonもQtもJavaより先に生まれていますから、この言い方はよくないですね。 まあ、あまり堅いことを言うと、例のWindowsがMacに似ているのか、 MacがWindowsに似ているのか、というような不毛な議論になってしまいますから、 堅苦しいのは抜きにしましょう。

セクションのサブメニューに戻る
(first uploaded 2000/04/09 last updated 2002/05/21)