Unsolved QTabLayout arrows showing on Windows but not on Mac
-
In my application that needs to work on Windows and Mac, I've had a problem with QTabWidget() where it doesn't show the scroll arrows that would be required to see some of the tabs, if the tab headers exceeds the Window size.
My reproducible example code is below, adding 30 tabs to a QTabWidget.
On Windows, the result looks like this. The arrows make it possible to view all the tabs.
However the result on Mac looks like this. It has no arrows, and if the number of tabs exceeds the width available on the display, then there is no way (that I've found) to be able to view tab 29, at all.
Is this a bug with Qt on Mac? Or is there a property I need to set in order to make these arrows appear in MacOS?
I have tried populating the tabs with widgets, but it did not have any effect, so I removed them from the example.
Thanks in advance for any help.
Example code:
import sys from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QLabel, QTabWidget, QFrame, QScrollArea class TabWidgetTest(QDialog): def __init__(self): super().__init__() self.title = 'PyQt5 tests' self.setMinimumSize(200, 200) self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint) self.layout = QGridLayout(self) self.scrollArea = QScrollArea() self.innerLayout = QGridLayout() self.scrollArea.setLayout(self.innerLayout) self.layout.addWidget(self.scrollArea) self.tabWidget = QTabWidget() self.innerLayout.addWidget(self.tabWidget, 0, 0) self.footerLabel = QLabel("Footer") self.innerLayout.addWidget(self.footerLabel, 1, 0) self.tabs = {} for tabIndex in range(0, 30): self.tabWidget.addTab(QFrame(), "Tab " + str(tabIndex)) if __name__ == '__main__': app = QApplication(sys.argv) ex = TabWidgetTest() ex.show() sys.exit(app.exec_())
-
@donquibeats
I believe you need read carefully through post in this forum:
https://forum.qt.io/topic/94574/how-to-get-usesscrollbuttons-buttons-to-scroll-tabs-when-it-has-many-tabs-for-macIt looks like you do not get them because of Mac style, you would need to change to Fusion?
-
Thanks very much for the link, that does seem to be the same problem. I will test out the Fusion option on Mac in the next couple of days.
-
Apologies for the delay in trying this out.
Unfortunately, setting the Fusion stylesheet hasn't made anything better.
I understand that having no arrows to navigate across multiple tabs is standard Mac behaviour but - how are Mac users supposed to navigate through large numbers of tabs? What's the 'proper' way to do it? Or indeed, what's any way to do it?
I tried updating my code to add a scrollbar, but because the QTabWidget always resizes to fit the window, the scrollbar is always full. Maybe there's a way I can fix the size of the QTabWidget based on the tabs, so that the scroll bar will work?
In the link provided before, Safari was cited as an example of how Mac users don't normally get arrows to navigate between tabs. However the behaviour of tabs in Safari is very different to PyQt5- in Safari they shrink to different proportions, and change sizes and move around when the viewed tab changes. None of that happens in a PyQt5 test app.
In the meantime, I've still got a situation where Mac users are unable to view certain tabs, and can't find any way of getting them into view.
My updated test code is:
import sys from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QDialog, QGridLayout, QLabel, QTabWidget, QFrame, QScrollArea class TabWidgetTest(QDialog): def __init__(self): super().__init__() self.title = 'PyQt5 tests' self.setMinimumSize(200, 200) self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint) self.layout = QGridLayout(self) self.scrollArea = QScrollArea() self.innerLayout = QGridLayout() self.scrollArea.setLayout(self.innerLayout) self.layout.addWidget(self.scrollArea) self.tabWidget = QTabWidget() self.innerLayout.addWidget(self.tabWidget, 0, 0) self.footerLabel = QLabel("Footer") self.innerLayout.addWidget(self.footerLabel, 1, 0) self.tabs = {} for tabIndex in range(0, 30): self.tabWidget.addTab(QFrame(), "Tab " + str(tabIndex)) self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) if __name__ == '__main__': app = QApplication(sys.argv) app.setStyleSheet("Fusion") ex = TabWidgetTest() ex.show() sys.exit(app.exec_())
-
-
Thanks for the response.
If horizontal scrolling is used on a Mac, please can you tell me why it's not working for me in the code example that I posted yesterday? The horizontal scroll bar doesn't scale, or allow the user to scan across, because it seems to adapt to 100% of the visible width, rather than 100% of the width of all the tab headings.
-
One thing: don't use a layout on a QScrollArea. Put it on the widget that you set on the QScrollArea.
-
Sorry but I'm still having difficulty understanding what the hierarchy of the layout should be, and where the scrolling should go- with reference to my test code from last week.
QGridLayout, QFrame etc. don't have "setHorizontalScrollPolicy" methods, while QScrollAreas can only be set with layouts, not widgets.
If I put a widget within a QFrame and then set that QFrame as the QScrollArea layout, no scroll bar appears.
I've tried other nested combinations but still haven't reached a point where a tab widget becomes scrollable.
I think I might be getting my Russian dolls in the wrong order. Please can you help me understand what the order of things, from outside to inside, is meant to be in order for a scrollbar to appear?
-
The order should be something like:
- A container widget
- A layout on the container widget
- Add stuff to that layout
- Set the container widget on the QScrollArea
and voila.