Search code examples
pythoncssqtpyqtqtabwidget

How to make different width of some tabs in qtabwidget?


In my project there is a QTabWidget with 5 tabs, using styleSheet I changed style of whole widget, but some tabs become small for text in them. How to make individual width for some tabs? enter image description here

As you can see, first 3 tabs have normal width, but last 2 are too small for text in them. Stylesheet:

QTabWidget::pane
{               
    background-color: rgb(212, 234, 255);
    border: 1px solid; /*граница*/
    border-color: rgb(255, 255, 255);
}
QTabWidget::tab-bar
{   
    left: 10px; /*перемещение кнопок вкладок*/
    width: 650px;
}
QTabBar::tab
{
    font: 75 11pt "MS Shell Dlg 2";
    font-weight: bold;
    background-color: qlineargradient(spread:pad, x1:0.502, y1:1, x2:0.493, y2:0, 
                                stop:0 rgba(53, 92, 88, 255), 
                                stop:1 rgba(45, 143, 132, 255));
                                
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    min-width: 5px;
    padding: 6px;   
    border: 1px solid;
    border-color: rgb(255, 255, 255);
}
QTabBar::tab:selected, 
QTabBar::tab:hover
{
    background-color: rgb(63, 171, 160);
}
QTabBar::tab:!selected
{
    margin-top: 5px
}
QTabBar::tab:selected
{
    margin-left: 4px;
    margin-right: 4px;
    background-color: qlineargradient(spread:pad, x1:0.502, y1:1, x2:0.493, y2:0, 
                                stop:0 rgba(53, 92, 88, 255), 
                                stop:1  rgb(58, 207, 192));
}

Additional info: Im not changing .ui or .py files of UI; For creating UI I using QtDesigner; All logic code is in separate file, where I importing UI file.


Solution

  • tl;dr

    Move the font properties to the main QTabBar type selector:

    QTabBar {
        font: 75 11pt "MS Shell Dlg 2";
        font-weight: bold;
    }
    QTabBar::tab {
        background-color: qlineargradient(spread:pad, x1:0.502, y1:1, x2:0.493, y2:0, 
                                    stop:0 rgba(53, 92, 88, 255), 
                                    stop:1 rgba(45, 143, 132, 255));
        ...
    
    

    Explanation

    The issue is caused by the fact that the font is applied to the ::tab subcontrol.

    While that may make sense, it creates a conceptual problem: QTabBar uses the widget font to provide the proper tabSizeHint() and the QSS rule is based on that too, even if the ::tab subcontrol has a different font set.

    I agree that the implementation is not perfect, but since a subcontrol can also have pseudo states (eg, :hover or :selected), the result is that the font metrics for a subcontrol are not considered for layout. Simply put: a subcontrol selector must not change the subcontrol size, not even if its font metrics change.

    Note that this is quite important: state changes should never alter the layout. Imagine what would happen if you set a default bold font for all tabs, but a normal one for the hovered one. If you move the mouse on the right edge of a tab, it will become "hovered", and its font would become "not bold", but that would shorten its width, making the one on its right as hovered; at the next mouse movement, the previously hovered one will be bold again, and it will become hovered again. And so on.

    The solution, then, is to properly set the font properties on the QTabBar widget instead (as shown at the beginning of this answer).

    In case you really need custom pseudo state based font (for instance, the currently selected tab), then the only remaining solution is to set a custom QTabBar override both its minimumTabSizeHint() and tabSizeHint() and ensure that the tab bar is always expanded in order to include the required space.