2015/04/30

PyQt5を使う (ウィジェットのカスタマイズ)

今回はウィジェットのカスタマイズです。

カスタマイズするウィジェットを継承したクラスを作り、カスタマイズ部分を実装してみます。

2015/04/28

PyQt5を使う (QDialogを継承する)

今回はQDialogクラスを継承したクラスによるダイアログの表示です。


import sys

from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.QtWidgets import QLabel, QLineEdit, QCheckBox, QPushButton, QHBoxLayout, QVBoxLayout

class FindDialog(QDialog):

    findPrevious = pyqtSignal(str, int)
    findNext = pyqtSignal(str, int)

    def __init__(self, parent=None):
        super(FindDialog, self).__init__(parent)

        self.label = QLabel(self.tr('Find &what'))
        self.lineEdit = QLineEdit()
        self.label.setBuddy(self.lineEdit)

        self.caseCheckBox = QCheckBox(self.tr('Match &case'))
        self.backwordCheckBox = QCheckBox(self.tr('Search &backword'))

        self.findButton= QPushButton(self.tr('&Find'))
        self.findButton.setDefault(True)
        self.findButton.setEnabled(False)

        self.closeButton = QPushButton(self.tr('Close'))

        self.lineEdit.textChanged[str].connect(self.enableFindButton)
        self.findButton.clicked.connect(self.findClicked)
        self.closeButton.clicked.connect(self.close)

        self.topLeftLayout = QHBoxLayout()
        self.topLeftLayout.addWidget(self.label)
        self.topLeftLayout.addWidget(self.lineEdit)

        self.leftLayout = QVBoxLayout()
        self.leftLayout.addLayout(self.topLeftLayout)
        self.leftLayout.addWidget(self.caseCheckBox)
        self.leftLayout.addWidget(self.backwordCheckBox)

        self.rightLayout = QVBoxLayout()
        self.rightLayout.addWidget(self.findButton)
        self.rightLayout.addWidget(self.closeButton)
        self.rightLayout.addStretch()

        self.mainLayout = QHBoxLayout()
        self.mainLayout.addLayout(self.leftLayout)
        self.mainLayout.addLayout(self.rightLayout)
        self.setLayout(self.mainLayout)

        self.setWindowTitle(self.tr('Find'))
        self.setFixedHeight(self.sizeHint().height())

    def findClicked(self):
        text = self.lineEdit.text()
        cs = Qt.CaseSensitive if self.caseCheckBox.isChecked() == True else Qt.CaseInsensitive

        if self.backwordCheckBox.isChecked() == True:
            self.findPrevious.emit(text, cs)
        else:
            self.findNext.emit(text, cs)

    def enableFindButton(self, text):
        self.findButton.setEnabled(len(text) != 0)

def findNext(text, cs):
    print('Find Next ! text={0} cs={1}'.format(text, cs))

def findPrevious(text, cs):
    print('Find Previous ! text={0} cs={1}'.format(text, cs))

if __name__ == '__main__':
    app = QApplication(sys.argv)

    find = FindDialog()
    find.findNext.connect(findNext)
    find.findPrevious.connect(findPrevious)
    find.show()

    sys.exit(app.exec_())


ちょっと長いですが、実行結果はこんな感じになります。



QDialogを継承したクラス(FindDialog)のコンストラクタで各ウィジェットの初期化を行いますが、ウィジェットをレイアウトするためにQHBoxLayoutとQVBoxLayoutを使用します。

QHBoxLayoutは登録されたウィジェットを横に配置するウィジェット、QVBoxLayoutは登録されたウィジェットを縦に配置するウィジェットです。

CloseボタンのclickedシグナルにはQDialogのcloseメソッドを、FindボタンのclickedシグナルにはfindClickedメソッド、テキストボックのtextChangedsシグナルにはenableFindButtonメソッドを接続しています。

そして、実際にFindボタンがクリックされた時の処理するためのfindNextとfindPreviousのインスタンス変数をpyqtSignalで定義します。

Findボタンクリック時、"Search backword"チェックボックの値によって、findNextかfindPreviousに接続されたスロットを実行(emit)するようにしています。

作成したFindDialogクラスはインスタンス化し、findNextとfindPreviousのconnectを行う必要があります。



2015/04/27

PyQt5を使う (ウィジェット間のシグナル連携)

前回、シグナルをスロットに接続するとユーザ操作に対する応答ができると書きました。
今回は異なるウィジェットのスロットにシグナルを接続してウィジェット間で同期をとる方法です。

2015/04/25

PyQt5を使う (シグナルとスロットの接続)

ユーザ操作に対する応答ですが、Qtでは状態の変化を「シグナル」というそうです。

シグナルは関数(Qtでは「スロット」)に結びつけて使用することで処理を実行できるようになります。

2015/04/24

Hello PyQt5

新しい言語を勉強する時は、”Hello World”を出力するのがお約束になっていますが、入門Qt4プログラミング(オライリー・ジャパン)も同様のようです。

import sys

from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QLabel

if __name__ == '__main__':
    app = QApplication(sys.argv)

    label = QLabel('Hello Qt5!')
    label.show()

    sys.exit(app.exec_())


3~4行目でQApplicationとQLabelをインポートしていますが、どうやらQt4とQt5はパッケージの構成が異なるようです。

7行目、QApplicationをインスタンス化します。
ここでは、コマンドライン引数が必要になるため、パラメータとして sys.argv を指定します。

9行目、QLabel をインスタンス化します。
QLabel は、テキストまたはイメージの表示を行うウィジェットです。
Qtではユーザが操作するユーザインターフェース要素のことをウィジェットと言うんだそうです。
(Unixもそうらしいです、勉強になりますね♪)
QLabelをインスタンス化する際のパラメータとして’Hello Qt5!’を指定しています。
これが表示する文字列ですね。

10行目、ここでラベルを表示状態にします。
Qtではウィジェットは常に非表示の状態で生成されるので、インスタンス化が終わったら表示させます。

12行目、制御をQtに渡します。
これによってアプリはイベントループに入り、ユーザからの操作を待つということですね。

ウィジェットは単体でもウィンドウとして機能するようで、今回のようにラベルだけをウィンドウとしてアプリ実行することができます。
なんて便利なんでしょう♪



上のサンプルでは、QLabelのインスタンス化時に’Hello Qt5!’という文字列を指定していますが、HTMLも指定可能だそうです。

    label = QLabel('<h2><i>Hello</i> <span style="color: red;">Qt5!</span></h2>')



画像も出力させるには以下のようになります。

import sys

from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QLabel
from PyQt5.QtGui import QPixmap

if __name__ == '__main__':
    app = QApplication(sys.argv)

    label = QLabel()
    label.setPixmap(QPixmap("[画像ファイルパス]"))
    label.show()

    sys.exit(app.exec_())

QLabelウィジェットを引数なしでインスタンス化し、setPixmapメソッドで画像データを指定することで可能になります。



GUIがお手軽にできていいですね♪


2015/04/23

GUI は何使う?

長いこと tweepy やってたので、ここらへんで休憩して別の事やろうかなと思います。

さて、PythonでGUIというとやはり標準でついている Tkinter なんですが、あまり洗練されていないとの評判です。

2015/04/22

tweepyライブラリを利用する (フィルターストリームを使う)

前回はユーザーストリームを使ってホームタイムラインのストリーミングをやってみました。
今回は、フィルターストリームを使って、リストに登録されているユーザのストリーミングを行います。