Leonardo Ferreira
Leonardo Ferreira

Reputation: 1

Problem resizing QTabWidget according to tab content (PyQT)

I know there are some answers provided regarding the QTabWidget resize (Link 1, Link 2, and others); however, I can't get it working properly in my application.

The idea is to create a window that resizes according to the QTabWidget size. Currently, I have two tabs, and the first one has a smaller size compared with the other one.

When I press the second tab, the window size increases as intended but, if I go back to the first tab, the window doesn't shrink. I tried changing the QSizePolicy of each tab as well as resizing the tab and the window but it doesn't change the outcome.

How can I solve the fact the window doesn't shrink? Here is the code:


import os
import os.path
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
    QSizePolicy,
    QApplication,
    QLabel,
    QMainWindow,
    QTabWidget,
    QDesktopWidget,
    QRadioButton,
    QLineEdit,
    QVBoxLayout,
    QHBoxLayout,
    QGridLayout,
    QWidget,
)

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupMainUi()
    
    def setupMainUi(self):
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        main_window_layout = QVBoxLayout(self.centralWidget)
        self.centralWidget.setLayout(main_window_layout)

        self.tabs = QTabWidget()
        self.tabs.addTab(self.loadTab1(), "Tab1")
        self.tabs.addTab(self.loadTab2(), "Tab2")

        self.tabs.currentChanged.connect(self.updateSizes)
        self.updateSizes(0)
        
        main_window_layout.addWidget(self.tabs)

    def updateSizes(self, index):
            
        for i in range(self.tabs.count()):
            if i != index:
                self.tabs.widget(i).setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        
        self.tabs.widget(index).setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        self.tabs.widget(index).resize(self.tabs.widget(index).minimumSizeHint())
        self.tabs.widget(index).adjustSize()
        self.resize(self.minimumSize())
        self.adjustSize()
   
    def loadTab1(self):
        
        self.ticketTab = QWidget()
        self.ticketTab.setEnabled(False)

        date_layout = QGridLayout()
        self.ticket = QLabel("Number:", self)
        self.ticket_number = QLineEdit()
        self.ticket_number.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        date_layout.addWidget(self.ticket, 0, 0)
        date_layout.addWidget(self.ticket_number, 0, 1)
        
        self.ticketTab.setLayout(date_layout)
        
        return self.ticketTab 
    
    def loadTab2(self):
        
        self.familyTab = QWidget()
        self.familyTab.setEnabled(False)
        
        family_default_layout = QVBoxLayout()
        self.family_default_checkbox = QRadioButton("Default")
        self.family_default_checkbox.setChecked(True)
        self.family_default_checkbox.setLayoutDirection(Qt.RightToLeft) 
        family_default_layout.addWidget(self.family_default_checkbox, alignment = Qt.AlignRight)
        
        family_layout = QHBoxLayout() 
        self.family_label = QLabel("Number of Families:", self)
        self.family_number = QLineEdit()
        self.family_number.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.family_number.textChanged.connect(lambda:self.checkInput(self.family_number))
        family_layout.addWidget(self.family_label, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        family_layout.addWidget(self.family_number, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        family_default_layout.addLayout(family_layout)
        
        temp_family_layout = QHBoxLayout() 
        self.family_label_1 = QLabel("Number of Families:", self)
        self.family_number_1 = QLineEdit()
        self.family_number_1.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        temp_family_layout.addWidget(self.family_label_1, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        temp_family_layout.addWidget(self.family_number_1, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        family_default_layout.addLayout(temp_family_layout)
        
        min_sub_family_layout = QHBoxLayout() 
        self.min_subfamily_label = QLabel("Minimum Number of SubFamilies:", self)
        self.min_subfamily_number = QLineEdit()
        self.min_subfamily_number.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        min_sub_family_layout.addWidget(self.min_subfamily_label, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        min_sub_family_layout.addWidget(self.min_subfamily_number, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        family_default_layout.addLayout(min_sub_family_layout)
        
        max_sub_family_layout = QHBoxLayout() 
        self.max_subfamily_label = QLabel("Maximum Number of SubFamilies:", self)
        self.max_subfamily_number = QLineEdit()
        self.max_subfamily_number.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        max_sub_family_layout.addWidget(self.max_subfamily_label, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        max_sub_family_layout.addWidget(self.max_subfamily_number, alignment=Qt.AlignLeft | Qt.AlignVCenter)
        family_default_layout.addLayout(max_sub_family_layout)
        
        self.familyTab.setLayout(family_default_layout)
        
        return self.familyTab
    
os.chdir("../..")

app = QApplication(sys.argv)
win = MainWindow()

qr = win.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
win.move(qr.topLeft()) 
win.move(win.pos().x(), win.pos().y() - 180)

win.show()
sys.exit(app.exec())

Sorry for the simple question. Only recently I have been exploring PyQT.

Upvotes: 0

Views: 1192

Answers (1)

musicamante
musicamante

Reputation: 48231

QTabWidget is based on QStackedWidget, which always uses the biggest size hint of all pages.

In order to avoid that, you can override both sizeHint and minimumSizeHint and ensure that it only returns the current widget hint.

Then, since resizing require some internal event handling, you can ensure that the application does that by calling processEvents() and then call adjustSize.

class ResizingTabWidget(QTabWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.currentChanged.connect(self.updateGeometry)

    def minimumSizeHint(self):
        return self.sizeHint()

    def sizeHint(self):
        current = self.currentWidget()
        if not current:
            return super().sizeHint()
        return current.sizeHint()


class MainWindow(QMainWindow):
    # ...
    def setupMainUi(self):
        # ...
        self.tabs = ResizingTabWidget()
        # ...

    def updateSizes(self):
        QApplication.processEvents()
        self.adjustSize()

Note that you don't need to call updateSizes in the __init__.
Also, be aware that from the UX perspective this is not a very good approach, as UIs that continuously resize themselves are considered annoying by many and often confuse the user.

Upvotes: 1

Related Questions