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を行う必要があります。