How to make the background color the same as the form background?

二次信任 提交于 2021-01-01 04:18:03

问题


In PyQt5 I'm getting some unexpected behavior from QTabWidget, the background seems to be white instead of the default form color (roughly light gray). Here is an example:

# QTabWidget2.py

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QTabWidget, \
    QGraphicsView, QFrame, QGridLayout
from PyQt5.QtGui import QPalette
from PyQt5.Qt import Qt


def main():
    app = QApplication([])
    mainForm = MainForm()
    mainForm.show()
    app.exec()
# end main

class MainForm(QWidget):

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

        # set default form size and location
        self.setGeometry(300, 300, 800, 600)

        # declare a graphics view
        self.bigLabel = QLabel('Big Label')
        self.setFontSize(self.bigLabel, 18)
        self.bigLabel.setAlignment(Qt.AlignCenter)
        self.bigLabel.setFrameStyle(QFrame.Panel)

        # declare a small label and a button
        self.label = QLabel('Label')
        self.setFontSize(self.label, 12)
        self.label.setAlignment(Qt.AlignCenter)
        self.button = QPushButton('Button')
        self.setFontSize(self.button, 12)

        self.vboxLayout = QVBoxLayout()
        self.vboxLayout.addWidget(self.label)
        self.vboxLayout.addWidget(self.button)
        self.vboxLayout.addStretch(1)

        self.hboxLayout = QHBoxLayout()
        self.hboxLayout.addWidget(self.bigLabel, 10)
        self.hboxLayout.addLayout(self.vboxLayout, 1)

        self.containerWidget = QWidget()
        self.containerWidget.setLayout(self.hboxLayout)

        self.tabWidget = QTabWidget()
        self.tabWidget.addTab(self.containerWidget, 'My Tab')

        self.gridLayout = QGridLayout()

        self.gridLayout.addWidget(self.tabWidget)

        self.setLayout(self.gridLayout)

    # end function

    def setFontSize(self, widget, fontSize):
        font = widget.font()
        font.setPointSize(fontSize)
        widget.setFont(font)
    # end function

# end class

if __name__ == '__main__':
    main()

Here is what it looks like on Ubuntu 18.04:

My question is, how can I make the QTabWidget background the same color as the form (in this case a QWidget) background?

Some things I have tried:

Many widgets have a function like this:

someWidget.setBackgroundBrush(self.palette().brush(QPalette.Window))

But QTabWidget does not seem to have setBackgroundBrush or an equivalent I can find.

I've found some posts that suggest to use style sheets to achieve this, but I'm not sure how to set this up. Would I need to sub-class QTabWidget to achieve this? Also, how could I get the default background form color? I could use simple guess and check to get close, but then it may change slightly across different platforms so this is not especially desirable.

--- Edit ---

Arrrrrrrggggggg !!! Qt can be really frustrating sometimes. If I add this just after declaring the QTabWidget:

        widgetColor = self.palette().color(QPalette.Background)
        widgetColorRgba = widgetColor.red(), widgetColor.green(), widgetColor.blue(), widgetColor.alpha()
        print('widgetColorRgb = ' + str(widgetColorRgba))

        styleSheetString = 'background-color: rgba(' + str(widgetColorRgba[0]) + ', ' + \
            str(widgetColorRgba[1]) + ', ' + str(widgetColorRgba[2]) + ', ' + str(widgetColorRgba[3]) + ');'

        print('styleSheetString = ' + str(styleSheetString))

        # this line works
        self.tabWidget.setStyleSheet(styleSheetString)

        # this line does not work !!!
        self.tabWidget.tabBar().setStyleSheet(styleSheetString)

It correctly changes the body of the QTabWidget to the default form background color, but it does not change the color of the tab!!


回答1:


There are two possible solutions for this problem.

The main reason for this behavior can be found in the style that is being used.

Each Qt style decides how the palette colors are used to paint a widget. This means that even if you set a specific color for (let's say) the background, it is not guaranteed that the widget will have that specific background color.

This concept is better explained if you think about buttons: they often have a "shade" gradient, that is based on the Button color role, but the background is not exactly that color. In the following image, I'm showing a button for which I set a plain red (#ff0000) color for the Button role, but, as you can see, it's not red:

The palette colors are, in fact, a reference.

Some widgets don't have a specific role for their painting behavior, and it's up to the style to decide which role use and how, and that's the case of QTabWidget. On Linux the default style is usually "Fusion", which uses the Button role to paint the background of the tab widget, but when that background is painted, a gradient based on that color is used instead. Again, a full red color applied for the Button role (aka, the tab widget background), that is not an actual red:

There are two possible solutions for this.

1. Use another style

The "Oxygen" style seem to be more coherent with the parent background when dealing with QTabWidget.

def main():
    app = QApplication([])
    app.setStyle(QStyleFactory.create('oxygen'))

To know what styles are installed on the system, just call QStyleFactory.keys(). Note that not all styles are available for every system. Usually, "Fusion" and "Windows" are available, which means that if you try to access the "Oxygen" style and it's not installed, the fallback style will be used instead.

2. Use a comprehensive stylesheet for the tab bar too

The reason for your tab not using the background set by the stylesheet is due to the fact that the style (fusion) is still using the aforementioned gradient applied to the background color, and that's because the tab can have a different color whether it's selected or not (specifically, lighter than the background if selected, darker if not).
To avoid that, you need to set the stylesheet for all tabbar pseudo states.

    bgd = 'rgba({}, {}, {}, {})'.format(*self.palette().color(QPalette.Window).getRgb())

    # get the default margins for layouts and use them for text padding of
    # the tab; obviously, you can use your own default padding instead
    margins = []
    for side in (QStyle.PM_LayoutTopMargin, QStyle.PM_LayoutRightMargin, QStyle.PM_LayoutBottomMargin, QStyle.PM_LayoutLeftMargin):
        margin = self.style().pixelMetric(side, None, None)
        if side in (QStyle.PM_LayoutTopMargin, QStyle.PM_LayoutBottomMargin):
            margin //= 2
        margins.append('{}px'.format(margin))
    padding = ' '.join(margins)

    self.tabWidget.setStyleSheet('''
        /* this selector applies the background color only to QWidgets that
        are direct children of QTabWidget */
        QTabWidget > QWidget {{
            background-color: {bgd};
        }}
        QTabBar::tab {{
            padding: {padding};
            border-left: 1px solid palette(mid);
            border-right: 1px solid palette(mid);
            border-top: 1px solid palette(mid);
            border-top-left-radius: 2px;
            border-top-right-radius: 2px;
            border-bottom: 1px solid palette(mid);
            margin: 0;
        }}
        QTabBar::tab:selected {{
            border-color: palette(dark);
            border-bottom: none;
        }}
        QTabBar::tab:!selected {{
            margin-top: 2px;
            margin-bottom: -2px;
        }}
    '''.format(bgd=bgd, padding=padding))

And that's the result:



来源:https://stackoverflow.com/questions/60195074/how-to-make-the-background-color-the-same-as-the-form-background

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!