Показать QToolTip

Нужно чтобы при потере фокуса рядом с объектом LE_sample_input_01 появлялся ToolTip, в котором написана ошибка.

from PySide6 import QtWidgets, QtCore, QtGui

class QTApp(QtWidgets.QWidget):
    def __init__(self):
        super(QTApp, self).__init__()

        self.LE_sample_input_01 = QtWidgets.QLineEdit()
        self.LE_sample_input_02 = QtWidgets.QLineEdit()
        self.LE_sample_input_01.setPlaceholderText('Возраст')
        self.RadioButton = QtWidgets.QRadioButton('Что-то')
        self.Button = QtWidgets.QPushButton('Тык')
        self.Button.setStyleSheet("QPushButton:pressed {background-color: #b3b3ba;}")

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.LE_sample_input_01)
        layout.addWidget(self.LE_sample_input_02)
        layout.addWidget(self.RadioButton)
        layout.addWidget(self.Button)

        self.LE_sample_input_01.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.FocusOut and QtGui.QFocusEvent.reason(event) == QtCore.Qt.MouseFocusReason:
            if obj is self.LE_sample_input_01:
                try:
                    age = int(self.LE_sample_input_01.text())
                    if age < 18 or age > 80:
                        obj.setFocus()
                        obj.selectAll()
                        QtWidgets.QToolTip.showText(obj.pos(), 'Что-то', obj)
                        return True
                except: pass
        return False

if __name__ == "__main__":
    app = QtWidgets.QApplication()
    qt_app = QTApp()
    qt_app.show()
    app.exec()

Ответы (1 шт):

Автор решения: S. Nick

Попробуйте так:

#from PySide6 import QtWidgets, QtCore, QtGui
from PyQt5 import QtWidgets, QtCore, QtGui


class QTApp(QtWidgets.QWidget):
    def __init__(self):
        super(QTApp, self).__init__()

        self.LE_sample_input_01 = QtWidgets.QLineEdit()
        self.LE_sample_input_02 = QtWidgets.QLineEdit()
        self.LE_sample_input_01.setPlaceholderText('Возраст')
        self.RadioButton = QtWidgets.QRadioButton('Что-то')
        self.Button = QtWidgets.QPushButton('Тык')
        self.Button.setStyleSheet("QPushButton:pressed {background-color: #b3b3ba;}")

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.LE_sample_input_01)
        layout.addWidget(self.LE_sample_input_02)
        layout.addWidget(self.RadioButton)
        layout.addWidget(self.Button)

        self.LE_sample_input_01.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.FocusOut and \
                QtGui.QFocusEvent.reason(event) == QtCore.Qt.MouseFocusReason:
            if obj is self.LE_sample_input_01:
                try:
                    age = int(self.LE_sample_input_01.text())
                    if age < 18 or age > 80:
                        obj.setFocus()
                        obj.selectAll()
                        
#                        QtWidgets.QToolTip.showText(obj.pos(), 'Что-то', obj)
# +++ попробуйте другой интервал времени ------> vvvv <-----------------------------------
                        QtCore.QTimer.singleShot(100, lambda: self.showToolTip(obj)) # +++
                        
                        return True
                except: pass
        return False

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv       
    def showToolTip(self, obj):
        pos = obj.mapToGlobal(obj.pos()) 
        QtWidgets.QToolTip.showText(pos, 'Что-то пошло не так.', obj)
        

if __name__ == "__main__":
    import sys
    
    app = QtWidgets.QApplication(sys.argv)
    qt_app = QTApp()
    qt_app.show()
    sys.exit(app.exec())

введите сюда описание изображения


Update:

У меня есть вопрос, получается так что, если поле потеряет фокус, появится ToolTip, но он не исчезнет пока курсор будет наведёт на элемент на который был перенесён фокус, можно ли как-то это исправить? Т.е чтобы ToolTip убирался через какое-то время, а не после того как убрать курсор с элемента?

Вам надо смелее заглядывать в документацию.

Это похоже на QToolTip::showText(pos, text, w, rect), но с дополнительным параметром msecDisplayTime, который указывает, как долго будет отображаться всплывающая подсказка в миллисекундах.

#from PySide6 import QtWidgets, QtCore, QtGui
from PyQt5 import QtWidgets, QtCore, QtGui


class QTApp(QtWidgets.QWidget):
    def __init__(self):
        super(QTApp, self).__init__()

        self.LE_sample_input_01 = QtWidgets.QLineEdit()
        self.LE_sample_input_02 = QtWidgets.QLineEdit()
        self.LE_sample_input_01.setPlaceholderText('Возраст')
        self.RadioButton = QtWidgets.QRadioButton('Что-то')
        self.Button = QtWidgets.QPushButton('Тык')
        self.Button.setStyleSheet("QPushButton:pressed {background-color: #b3b3ba;}")

        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.LE_sample_input_01)
        layout.addWidget(self.LE_sample_input_02)
        layout.addWidget(self.RadioButton)
        layout.addWidget(self.Button)

        self.LE_sample_input_01.installEventFilter(self)

        QtWidgets.QToolTip.setFont(QtGui.QFont('DejaVuSans', 12))

    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.FocusOut and \
                QtGui.QFocusEvent.reason(event) == QtCore.Qt.MouseFocusReason:
            if obj is self.LE_sample_input_01:
                try:
                    age = int(self.LE_sample_input_01.text())
                    if age < 18 or age > 80:
                        obj.setFocus()
                        obj.selectAll()
                        QtCore.QTimer.singleShot(
                            500, lambda: self.showToolTip(obj)) 
                        return True
                except: pass
        return False

    def showToolTip(self, obj):
# ----------> vvvv <--------------------------------------------------
        pos = self.mapToGlobal(obj.pos()) + QtCore.QPoint(0, 12)
        QtWidgets.QToolTip.showText(
            pos, 
            'Что-то пошло не так.', 
            obj,
            QtCore.QRect(),                              # +++
            2000                                         # <---- # +++
        )
        

if __name__ == "__main__":
    import sys
    
    app = QtWidgets.QApplication(sys.argv)
    qt_app = QTApp()
    qt_app.show()
    sys.exit(app.exec())

введите сюда описание изображения

→ Ссылка