expanding tabs to full window size?

1.3k views Asked by At

I've been struggling with something related to tabs for a few days now. I'm trying to make it so that the tab bar I have in my application extends across the full width of the window size. I’m working with both MacOS and Ubuntu, and while the final result of both differs, neither work.

Up to now, I've tried a few things. First, I made subclass of QtWidgets.QTabBar and use that as the tab bar. I tried setting expand to true (self.setExpand(True)), but from everything I’ve heard, that doesn’t let you override OS defaults.

The next idea was to override tabSizeHint, and it seems like this is the right approach, but I haven’t been able to figure out the implementation. Here’s what I’m doing as of now, that to me, seems like it should work:

import sys
from PySide2 import QtCore, QtWidgets, QtGui

class TabBar(QtWidgets.QTabBar):
    def __init__(self, parent=None):
        super(TabBar, self).__init__(parent)
        self.setExpanding(True)

    def tabSizeHint(self, index):
        size = QtWidgets.QTabBar.tabSizeHint(self, index)
        width = self.parent().size().width()
        size.setWidth( width / self.count() )
        return size

class TabWindow(QtWidgets.QTabWidget):
    def __init__(self, parent=None):
        super(TabWindow, self).__init__(parent)
        self.bar = TabBar()
        self.setTabBar(self.bar)
        self.initTabs()

    def initTabs(self):
        self.test1 = self.addTab(QtWidgets.QWidget(), "Test 1")
        self.test2 = self.addTab(QtWidgets.QWidget(),"Test 2")
        self.test3 = self.addTab(QtWidgets.QWidget(),"Test 3")
        self.test4 = self.addTab(QtWidgets.QWidget(),"Test 4")

class MainApplication(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)
        self.mainWidget = TabWindow()
        self.setCentralWidget(self.mainWidget)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_app = MainApplication()
    main_app.show()
    sys.exit(app.exec_())

This works when I initially start the program, but does not expand the size of the tabs if I expand the window. It seems that tabSizeHint is not getting called. Another (failed) approach I took is the follow:

class TabBar(QtWidgets.QTabBar):
    def __init__(self, parent=None):
        super(TabBar, self).__init__(parent)

class TabWindow(QtWidgets.QTabWidget):
    def __init__(self, parent=None):
        super(TabWindow, self).__init__(parent)
        self.bar = TabBar()
        self.setTabBar(self.bar)
        self.initTabs()
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(self.bar)
        self.setLayout(layout)

    def initTabs(self):
        self.test1 = self.addTab(QtWidgets.QWidget(), "Test 1")
        self.test2 = self.addTab(QtWidgets.QWidget(),"Test 2")
        self.test3 = self.addTab(QtWidgets.QWidget(),"Test 3")
        self.test4 = self.addTab(QtWidgets.QWidget(),"Test 4")

class MainApplication(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)
        self.mainWidget = TabWindow()
        self.setCentralWidget(self.mainWidget)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_app = MainApplication()
    main_app.show()
    sys.exit(app.exec_())

For this one, whenever I click on the tab, it will briefly show the 4 tabs taking up the whole width (as I want it to), but in the middle of the window rather than the top. Shortly after that, it will disappear and revert back to the default sized tabs on the top of the window, as though it's being overwritten by something else.

1

There are 1 answers

0
eyllanesc On BEST ANSWER

The QTabWidget calculates when it is necessary to change the size of the QTabBar, so the solution is to force to have a new width that is equal to that of the QTabWidget.

from PySide2 import QtCore, QtGui, QtWidgets 

class TabWindow(QtWidgets.QTabWidget):
    def __init__(self, parent=None):
        super(TabWindow, self).__init__(parent)
        self.initTabs()

    def initTabs(self):
        self.test1 = self.addTab(QtWidgets.QWidget(), "Test 1")
        self.test2 = self.addTab(QtWidgets.QWidget(),"Test 2")
        self.test3 = self.addTab(QtWidgets.QWidget(),"Test 3")
        self.test4 = self.addTab(QtWidgets.QWidget(),"Test 4")

    def resizeEvent(self, event):
        self.tabBar().setFixedWidth(self.width())
        super(TabWindow, self).resizeEvent(event)

class MainApplication(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)
        self.mainWidget = TabWindow()
        self.setCentralWidget(self.mainWidget)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main_app = MainApplication()
    main_app.resize(640, 480)
    main_app.show()
    sys.exit(app.exec_())

With the previous implementation if the width is small, the buttons appear (in Linux, I have not tested in Mac OS), one way to avoid this is to implement the tabSizeHint() method:

from PySide2 import QtCore, QtGui, QtWidgets 

class TabBar(QtWidgets.QTabBar):
    def __init__(self, parent=None):
        super(TabBar, self).__init__(parent)
        self.setExpanding(True)

    def tabSizeHint(self, index):
        if self.count() > 0:
            size = QtWidgets.QTabBar.tabSizeHint(self, index)
            width = self.parent().size().width()/self.count()
            return QtCore.QSize(width, size.height())
        return super(TabBar, self).tabSizeHint(index)

class TabWindow(QtWidgets.QTabWidget):
    def __init__(self, parent=None):
        super(TabWindow, self).__init__(parent)
        self.bar = TabBar()
        self.setTabBar(self.bar)
        self.initTabs()

    def initTabs(self):
        self.test1 = self.addTab(QtWidgets.QWidget(), "Test 1")
        self.test2 = self.addTab(QtWidgets.QWidget(),"Test 2")
        self.test3 = self.addTab(QtWidgets.QWidget(),"Test 3")
        self.test4 = self.addTab(QtWidgets.QWidget(),"Test 4")

    def resizeEvent(self, event):
        self.tabBar().setFixedWidth(self.width())
        super(TabWindow, self).resizeEvent(event)

class MainApplication(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainApplication, self).__init__(parent)
        self.mainWidget = TabWindow()
        self.setCentralWidget(self.mainWidget)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main_app = MainApplication()
    main_app.resize(640, 480)
    main_app.show()
    sys.exit(app.exec_())