Отображение QToolTip у элементов QScrollArea

Нужно сделать так, чтобы QToolTip показывался рядом с пустым полем QLineEdit.

Интерфейс:

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QGridLayout, QHBoxLayout, QLabel,
    QLineEdit, QMainWindow, QPushButton, QScrollArea,
    QSizePolicy, QWidget)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(554, 363)
        MainWindow.setStyleSheet(u"QWidget {\n"
"   background-color: white;\n"
"   color: black;\n"
"   font: 14pt \"Times New Roman\";\n"
"   font-weight: 400;\n"
"}\n")
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.centralwidget.setStyleSheet(u"")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.label = QLabel(self.centralwidget)
        self.label.setObjectName(u"label")

        self.horizontalLayout.addWidget(self.label)

        self.age = QLineEdit(self.centralwidget)
        self.age.setObjectName(u"age")

        self.horizontalLayout.addWidget(self.age)


        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)

        self.scrollArea = QScrollArea(self.centralwidget)
        self.scrollArea.setObjectName(u"scrollArea")
        self.scrollArea.setMidLineWidth(0)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollArea.setWidgetResizable(True)
        self.scrollAreaWidgetContents = QWidget()
        self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
        self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 522, 261))
        self.scrollAreaWidgetContents.setContextMenuPolicy(Qt.NoContextMenu)
        self.scrollAreaWidgetContents.setStyleSheet(u"")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)

        self.gridLayout.addWidget(self.scrollArea, 1, 0, 1, 1)

        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        self.pushButton.setObjectName(u"pushButton")
        self.resul = QLabel(self.centralwidget)
        self.resul.setObjectName(u"result")
        self.resul.setStyleSheet("border: 1.5px solid black;")
        self.resul.setWordWrap(True)

        self.gridLayout.addWidget(self.pushButton, 2, 0, 1, 1)
        self.gridLayout.addWidget(self.resul)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.label.setText(QCoreApplication.translate("MainWindow", u"\u0412\u043e\u0437\u0440\u0430\u0441\u0442", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))
    # retranslateUi

Исполняемый файл:

import sys
from int import *

class Label(QLabel):
    clicked = Signal()

    def __init__(self):
        super().__init__()

    def mouseReleaseEvent(self, event):
        self.clicked.emit()

class MyWidget(QWidget):

    def __init__(self, res, num):
        super().__init__()

        self.flag = True

        self.label = Label()
        self.label.setText(f'{res}')
        self.label.setWordWrap(True)
        self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label.setStyleSheet(self.stl('none', '10px'))
        self.label.setMinimumSize(QSize(0,27))
        self.label.setObjectName(f'workout_{num}')
        self.label.clicked.connect(self.onClicked)
        self.label.setCursor(QCursor(Qt.PointingHandCursor))

        self.lineEdit = QLineEdit()
        self.lineEdit.setEnabled(False)
        self.lineEdit.setAlignment(Qt.AlignCenter)
        self.lineEdit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.lineEdit.setStyleSheet("QLineEdit {border: 1.5px solid black;"
                                    "border-top-right-radius: 10px;"
                                    "border-bottom-right-radius: 10px;"
                                    "border-left-style:none;}"
                                    )
        self.lineEdit.setObjectName(f'res_{num}')
        self.lineEdit.hide()


        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setStretch(1, 0)
        layout.setSpacing(0)

        layout.addWidget(self.label, 1)
        layout.addWidget(self.lineEdit, 0, alignment=Qt.AlignRight)

    def onClicked(self):
        if self.flag:
            self.label.setStyleSheet(self.stl('#7db1b3', '0'))
            self.lineEdit.setEnabled(True)
            self.lineEdit.show()
            self.lineEdit.setFocus()
        else:
            self.label.setStyleSheet(self.stl('none', '10px'))
            self.lineEdit.hide()
            self.lineEdit.setEnabled(False)

        self.flag = not self.flag

    def stl(self, b, s):
        return "QLabel {" + f"background-color: {b};" \
                            "border: 1.5px solid black;" \
                            "border-top-left-radius: 10px;" \
                            f"border-top-right-radius: {s};" \
                            "border-bottom-left-radius: 10px;" \
                            f"border-bottom-right-radius: {s};" \
                            "font: 14pt 'Times New Roman'};" \
                            "QLabel:hover {border-color: #534F4C;}"

class Test(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Test, self).__init__()
        self.setupUi(self)

        self.printed()
        self.pushButton.clicked.connect(self.cheack2)

    def printed(self):
        layout = QVBoxLayout()
        widget = QWidget()
        for i in range(10):
            layout.addWidget(MyWidget(i, i))
        widget.setLayout(layout)
        self.scrollArea.setWidget(widget)

    def cheack2(self):
        for l in self.scrollArea.findChildren(QLineEdit):
            if l.text() == '' and l.isVisible():
                self.scrollArea.ensureWidgetVisible(l)
                l.setFocus()
                self.showToolTip(self.scrollArea, l , 'Пустое поле')
                break

    @staticmethod
    def showToolTip(group, obj: QLineEdit, text: str) -> None:
        QToolTip.showText(QWidget.mapToGlobal(group, obj.pos()), text, obj, QRect(), 2000)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Test()
    window.show()
    sys.exit(app.exec())

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

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

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

import sys

# установите свои импорты для PySide6                                  # !!! + QtTest

from PyQt5 import QtCore, QtGui, QtWidgets, QtTest                     # +++   QtTest
from PyQt5.Qt import *

# --> vvvvvvvvvvvvv <----> vvvvvvvvvvvvv <----------------------------------
#from mainWindow_ui import Ui_MainWindow
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(554, 363)
        MainWindow.setStyleSheet(u"QWidget {\n"
"   background-color: white;\n"
"   color: black;\n"
"   font: 14pt \"Times New Roman\";\n"
"   font-weight: 400;\n"
"}\n")
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.centralwidget.setStyleSheet(u"")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName(u"gridLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.label = QLabel(self.centralwidget)
        self.label.setObjectName(u"label")
        self.horizontalLayout.addWidget(self.label)

        self.age = QLineEdit(self.centralwidget)
        self.age.setObjectName(u"age")
        self.horizontalLayout.addWidget(self.age)

        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)

        self.scrollArea = QScrollArea(self.centralwidget)
        self.scrollArea.setObjectName(u"scrollArea")
        self.scrollArea.setMidLineWidth(0)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollArea.setWidgetResizable(True)
        self.scrollAreaWidgetContents = QWidget()
        self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
        self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 522, 261))
        self.scrollAreaWidgetContents.setContextMenuPolicy(Qt.NoContextMenu)
        self.scrollAreaWidgetContents.setStyleSheet(u"")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.gridLayout.addWidget(self.scrollArea, 1, 0, 1, 1)

        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
        self.pushButton.setObjectName(u"pushButton")
        self.resul = QLabel(self.centralwidget)
        self.resul.setObjectName(u"result")
        self.resul.setStyleSheet("border: 1.5px solid black;")
        self.resul.setWordWrap(True)
        self.gridLayout.addWidget(self.pushButton, 2, 0, 1, 1)
        self.gridLayout.addWidget(self.resul)

        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.label.setText(QCoreApplication.translate("MainWindow", u"\u0412\u043e\u0437\u0440\u0430\u0441\u0442", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))


class Label(QLabel):
#    clicked = Signal()                                             # PySide6
    clicked = pyqtSignal()                                          # PyQt5

    def __init__(self):
        super().__init__()

    def mouseReleaseEvent(self, event):
        self.clicked.emit()


class MyWidget(QWidget):
    def __init__(self, res, num):
        super().__init__()

        self.flag = True

        self.label = Label()
        self.label.setText(f'{res}')
        self.label.setWordWrap(True)
        self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.label.setStyleSheet(self.stl('none', '10px'))
        self.label.setMinimumSize(QSize(0,27))
        self.label.setObjectName(f'workout_{num}')
        self.label.clicked.connect(self.onClicked)
        self.label.setCursor(QCursor(Qt.PointingHandCursor))

        self.lineEdit = QLineEdit()
        self.lineEdit.setEnabled(False)
        self.lineEdit.setAlignment(Qt.AlignCenter)
        self.lineEdit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.lineEdit.setStyleSheet("QLineEdit {border: 1.5px solid black;"
                                    "border-top-right-radius: 10px;"
                                    "border-bottom-right-radius: 10px;"
                                    "border-left-style:none;}"
                                    )
        self.lineEdit.setObjectName(f'res_{num}')
        self.lineEdit.hide()

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setStretch(1, 0)
        layout.setSpacing(0)

        layout.addWidget(self.label, 1)
        layout.addWidget(self.lineEdit, 0, alignment=Qt.AlignRight)

    def onClicked(self):
        if self.flag:
            self.label.setStyleSheet(self.stl('#7db1b3', '0'))
            self.lineEdit.setEnabled(True)
            self.lineEdit.show()
            self.lineEdit.setFocus()
        else:
            self.label.setStyleSheet(self.stl('none', '10px'))
            self.lineEdit.hide()
            self.lineEdit.setEnabled(False)
        self.flag = not self.flag

    def stl(self, b, s):
        return "QLabel {" + f"background-color: {b};" \
                            "border: 1.5px solid black;" \
                            "border-top-left-radius: 10px;" \
                            f"border-top-right-radius: {s};" \
                            "border-bottom-left-radius: 10px;" \
                            f"border-bottom-right-radius: {s};" \
                            "font: 14pt 'Times New Roman'};" \
                            "QLabel:hover {border-color: #534F4C;}"


class Test(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Test, self).__init__()
        self.setupUi(self)

        self.printed()
        self.pushButton.clicked.connect(self.cheack2)

    def printed(self):
        layout = QVBoxLayout()
        widget = QWidget()
        for i in range(10):
            layout.addWidget(MyWidget(i, i))
        widget.setLayout(layout)
        self.scrollArea.setWidget(widget)

    def cheack2(self):
        lineEdits = self.scrollArea.findChildren(QLineEdit)
        for le in lineEdits:
            if le.text() == '' and le.isVisible():
                self.scrollArea.ensureWidgetVisible(le)
                le.setFocus()
                
                self.showToolTip(
                    self.scrollArea, le , '<h2 style="color: red;">Пустое поле</h2>')
                
# ???           break     

    @staticmethod
    def showToolTip(group, obj: QLineEdit, text: str) -> None:
        QToolTip.showText(
# ----------------------------> vvvvvvvvvvvv <----------------------------------
            QWidget.mapToGlobal(obj.parent(), obj.pos()),                  # !!!
            text, obj, QRect(), 2000
        )

        QtTest.QTest.qWait(2000)                                           # !!! +++


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Test()
    window.show()
    sys.exit(app.exec())

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

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

→ Ссылка