Изменение цвета текста и фона вкладки в QToolBox

В моей программе на PyQt5 используется QToolBox. В программе есть необходимость отслеживать заполнение обязательных полей (QLineEdit). Эти поля находятся в разных вкладках блока QToolBox. И при выявлении незаполненного поля должна подсвечиваться та вкладка, где содержится незаполненное поле (таких вкладок может быть несколько). Проход по всем полям я осуществляю циклом и, если находится незаполненное поле, то его рамка подкрашивается красным - в этом есть неудобство, потому что если вкладки свернуты, то не видно, какое поле подкрашено. Именно для этого я пытаюсь сделать, чтобы подкрашивались сами вкладки (можно только заголовок таба). Я встречал решения как можно окрасить все табы с помощью стилей: первый таб, последний таб, текущий активный таб, но мне этот вариант не подходит, т.к. в моем случае таб может оказаться на любой позиции. Макет главного окна, в котором среди прочего содержится QToolBox, создан с помощью PyQt Designer.

Принцип такой: как только в цикле найдено незаполненное поле, то вкладка, в котором это поле содержится, подкрашивается красным (или только заголовок таба становится красным) и так пока цикл не дойдет до конца, если будут еще незаполненные поля, то эти вкладки также должны быть подкрашены. После этого, если пользователь заполнил поля, нажал кнопку Проверить, цикл запускается еще раз и, если поля заполнены, то убирает выделение красным (возвращает исходный стиль текста или фона вкладки).

Пример минимально-воспроизводимого кода.

from PyQt5.QtWidgets import *
import sys

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

        self.red_warning = "border-color: red; border-style: solid; border-width: 2px; font-weight: normal;"

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)

        # Add toolbar and items
        self.toolbox = QToolBox()

        self.lineEdit_1 = QLineEdit()
        self.toolbox.addItem(self.lineEdit_1, "Вкладка 1")
        self.lineEdit_2 = QLineEdit()
        self.toolbox.addItem(self.lineEdit_2, "Вкладка 2")
        self.lineEdit_3 = QLineEdit()
        self.toolbox.addItem(self.lineEdit_3, "Вкладка 3")

        self.buttonAdd = QPushButton('Проверить')
        self.buttonAdd.clicked.connect(self.check)

        vbox = QGridLayout(self.centralWidget)
        vbox.addWidget(self.toolbox, 0, 0, 1, 2)
        vbox.addWidget(self.buttonAdd, 2, 1)

    def check(self):
        fields = [self.lineEdit_1, self.lineEdit_2, self.lineEdit_3]
        for field in fields:
            if field.text() != '' and field.text().isspace():
                field.setStyleSheet(self.red_warning)
            elif field.text() == '':
                field.setStyleSheet(self.red_warning)
            else:
                field.setStyleSheet('')

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

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

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

я вам предложу другой подход реализации вашей задумки:

import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.Qt import *


class MyToolBoxWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent=parent)
        self.vertical_layout = QtWidgets.QVBoxLayout(self)
        self.vertical_layout.setContentsMargins(0, 0, 0, 0)
        self.vertical_layout.setSpacing(0)
        self.pages = []
        self.tabs = []

        self._first_v_spacerItem = QtWidgets.QSpacerItem(
            20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)

    def addItem(self, page, name, color=None):
        tab_button = QtWidgets.QPushButton(name)
        font = QtGui.QFont()
        font.setBold(True)
        tab_button.setFont(font)
        page.setSizePolicy(QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding))
        page.hide()
        self.pages.append(page)
        self.tabs.append(tab_button)
        self.vertical_layout.addWidget(tab_button)
        self.vertical_layout.addWidget(page)
        tab_button.clicked.connect(self._button_clicked)

        if color:
            self.setColor( (len(self.pages) - 1), color  )

    def setColor(self, index, color):
        palette = self.get_palette(color)
        self.pages[index].setPalette(palette)
        self.tabs[index].setPalette(palette)
        self.pages[index].setAutoFillBackground(True)

    def check_if_all_pages_are_hidden(self):
        areHidden = True
        for page in self.pages:
            if not page.isHidden():
                areHidden = False
                break
        if areHidden:
            self.vertical_layout.addItem(self._first_v_spacerItem)
        else:
            self.vertical_layout.removeItem(self._first_v_spacerItem)

    def _button_clicked(self):
        i = self.tabs.index(self.sender())
        if self.pages[i].isHidden():
            self.pages[i].show()
        else:
            self.pages[i].hide()
        self.check_if_all_pages_are_hidden()

    def get_palette(self, color):
        palette = QtGui.QPalette()
        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Button, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Light, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Midlight, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Dark, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Mid, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)

        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.BrightText, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Shadow, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.AlternateBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ToolTipBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ToolTipText, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Button, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Light, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Midlight, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Dark, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Mid, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)

        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.BrightText, brush)

        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Shadow, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.AlternateBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ToolTipBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ToolTipText, brush)

        brush = QtGui.QBrush(QtGui.QColor(42, 85, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Button, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Light, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Midlight, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Dark, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Mid, brush)

        brush = QtGui.QBrush(QtGui.QColor(42, 85, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)

        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.BrightText, brush)

        brush = QtGui.QBrush(QtGui.QColor(42, 85, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Shadow, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.AlternateBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipBase, brush)

        brush = QtGui.QBrush(QtGui.QColor(color))
        brush.setStyle(QtCore.Qt.SolidPattern)
        palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipText, brush)

        return palette
        

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)        

        self.my_tool_box = MyToolBoxWidget()

        page1 = QtWidgets.QLineEdit()
        self.my_tool_box.addItem(page=page1, name="Вкладка 1", color="#4ade00")
        page2 = QtWidgets.QLineEdit()
        self.my_tool_box.addItem(page=page2, name="Вкладка 2", color="#009deb")
        page3 = QtWidgets.QLineEdit()
        self.my_tool_box.addItem(page=page3, name="Вкладка 3", color="#f95300")
        page4 = QtWidgets.QLineEdit()
        self.my_tool_box.addItem(page=page4, name="Вкладка 4", color="#ccc")

        # Добавить проставку в конце
        self.my_tool_box.check_if_all_pages_are_hidden()
        
        self.buttonAdd = QPushButton('Проверить')
        self.buttonAdd.clicked.connect(self.check)

        vbox = QGridLayout(self.centralWidget)
        vbox.addWidget(self.my_tool_box, 0, 0, 1, 2)
        vbox.addWidget(self.buttonAdd, 2, 1)
        
        self.red_warning = """
                border-color: red; 
                border-style: solid; 
                border-width: 2px; 
                font-weight: normal;
        """
        self.fields = [page1, page2, page3, page4]

    def check(self):
#        fields = [page1, page2, page3, page4]
#        for field in self.fields:
        for index, field in enumerate(self.fields):
            if field.text() == '' or (field.text() != '' and field.text().isspace()):
                field.setStyleSheet(self.red_warning)
                self.my_tool_box.setColor(index, 'red')
#            elif field.text() == '':
#                field.setStyleSheet(self.red_warning)
            else:
                field.setStyleSheet('')
                self.my_tool_box.setColor(index, '#00FF00')

 
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    app.setStyle('Fusion')                        # !!! Важно !!!
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

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

→ Ссылка