質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

setFocusをするとカーソルが増える。 Python3.7 Pyqt5 QlineEdit

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 279

WMS

score 35

Python3.7 Pyqt5で作成したlineEditが4つあります。
マウスでクリックした際、4番目の lineEdit にフォーカスを移動させ、
4番目の lineEdit にクリックされた lineEditのオブジェクト名を表示する
というものを以前教えて頂いたサンプルを元に作成しました。

4番目の lineEdit にクリックされたオブジェクト名は表示できるのですが、
クリックされた lineEdit にカーソルが残ってしまいます。
最終的には画面にカーソルが4つ表示されてしまします。

クリックされた lineEdit にカーソルが表示されないようにするにはどうしたらよいでしょうか。
回避策をご教授お願い致します。

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.lineEdit1 = QLineEdit("", self)
        self.lineEdit1.setObjectName("lineEdit1")
        self.lineEdit2 = QLineEdit("", self)
        self.lineEdit2.setObjectName("lineEdit2")
        self.lineEdit3 = QLineEdit("", self)
        self.lineEdit3.setObjectName("lineEdit3")
        self.lineEdit4 = QLineEdit("", self)
        self.lineEdit4.setObjectName("lineEdit4")

        vbox = QVBoxLayout()
        vbox.addWidget(self.lineEdit1)
        vbox.addWidget(self.lineEdit2)
        vbox.addWidget(self.lineEdit3)
        vbox.addWidget(self.lineEdit4)

        central_widget = QWidget(self)
        central_widget.setLayout(vbox)
        self.setCentralWidget(central_widget)

        # イベントをフィルタ (監視) するウィジェットを設定する。
        self.lineEdit1.installEventFilter(self)
        self.lineEdit2.installEventFilter(self)
        self.lineEdit3.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.FocusIn:
            # フォーカスが移るイベントが発生した場合、
            # イベントが発生したオブジェクトの名前をラベルに設定する。
            self.lineEdit4.setText(obj.objectName())
            self.lineEdit4.setFocus()

        return super().eventFilter(obj, event)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ぱっと見だとフォーカスがlineEdit1~3にフォーカスを移そうとしている最中にlineEdit4にフォーカスを設定するのが強引すぎるかなと思います。

タイマー処理を使ってeventFilterが終わった後にあらためてlineEdit4にフォーカスを設定すればよいのではないかと思います。

    def eventFilter(self, obj, event):
        if event.type() == QEvent.FocusIn:
            # フォーカスが移るイベントが発生した場合、
            # イベントが発生したオブジェクトの名前をラベルに設定する。
            self.lineEdit4.setText(obj.objectName())
            QTimer.singleShot(0, self.lineEdit4.setFocus)

        return super().eventFilter(obj, event)

QTimer.singleShot(0, self.lineEdit4.setFocus)
を書くことで「eventFilterが終わった後」になるのかが理解できずにいます。

タイマーも「ボタンを押した」、「テキストボックスの内容が変化した」などのイベントの一種です。
eventFilterも「あるテキストボックスにフォーカスが移った」というイベントを契機に呼び出されています。

発生したイベント処理はイベントキューにキューイングされ、app.exec_()の中で順番に処理されています。
何かの関数を実行している最中にいきなり実行されるわけではないんですね。

で、QTimer.singleShot(0, self.lineEdit4.setFocus)ですが経過時間が0なので即座にタイマーイベントが発生します。で、そのイベントは前述のイベントキューに入ります。ただ、今は「あるテキストボックスにフォーカスが移った」を処理中でその瞬間には処理されません。「あるテキストボックスにフォーカスが移った」イベント処理が終わった後にイベントキューにタイマーイベントがあるのでそれが処理されます。

また、QTimerを使わないと「eventFilterが終わった後」の処理を書くことはできないのでしょうか。

わかりません。私の知っている知識ではQTimerだけです。前に説明した通り、何かイベントを発生させて、そのイベント処理としてself.lineEdit4.setFocus()を実行できれば同じことはできるとは思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/12/03 19:33

    nomuken 様
    ご回答ありがとうございます。
    ご教授頂いたコードで試しましたところ意図した動作をしてくれましたが、
    私が書いた self.lineEdit4.setFocus() と同じ位置に QTimer.singleShot(0, self.lineEdit4.setFocus)
    を書くことで「eventFilterが終わった後」になるのかが理解できずにいます。
    また、QTimerを使わないと「eventFilterが終わった後」の処理を書くことはできないのでしょうか。

    キャンセル

  • 2019/12/04 10:18

    nomuken 様
    ご丁寧な説明ありがとうございます。
    「フォーカスが移った」というイベントの中でタイマーイベントが発生、
    この影響で 「フォーカスが移った」というイベントが終わり、
    新たにタイマーイベントにてフォーカスが移った。
    という解釈になったのですが、この解釈で合っているでしょうか。

    キャンセル

  • 2019/12/04 19:17

    > この解釈で合っているでしょうか。
    はい。

    キャンセル

  • 2019/12/05 13:19

    nomuken 様
    ありがとうございます。
    やっと理解ができました。色々とご説明頂きましてありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる