Issue
I was wondering if it is possible in PyQt, when trying to hide QTabWidget, to hide the contents themselves, but keep the QTabBar visible.
As of now, I have custom TabBar and TabWidget that inherit from QTabBar and QTabWidget. My TabBar is vertical and on the west side of the TabWidget.
I have created the button and connected a slot to it that is supposed to hide the TabWidget. Issue is, hiding the TabWidget hides the TabBar, which I do not want.
I have tried overriding .hide() method, tried
self.tab_widget.hide()
self.tab_widget.tabBar().show()
But nothing works, since the TabWidget is the parent of TabBar, hiding TabWidget, automatically hides TabBar.
Of course I could probably construct my own poor man's TabWidget from two widgets so that I could hide and show the widgets whenever I want, but inhereting from QTabWidget is very convenient and I do not want to do it from scratch.
I also upon hiding could just resize tab widget to the width of the TabBar, but I feel that is stupid solution as well.
My Idea is to have an expandable/shrinkable and hideable sidebar, such as in VSCode.
Solutions in C++ QT will be helpful as well, as I understand both, and it is not necessarily Python issue, but Qt.
Solution
QTabWidget is a composite widget, made of a QTabBar and a QStackedWidget.
Most importantly, it overrides basic aspects that are required for layout management, such as sizeHint()
, minimumSizeHint()
and sizePolicy()
.
You cannot just toggle the visibility of the tab bar (nor the stacked widget contents):
- as you already found out, hiding the QTabWidget and showing the tab bar is fundamentally a no-op, since the parent visibility has precedence: calling
show()
orsetVisible(True)
on a nested child (a QWidget without aQt.Window
window flag) will only make it visible as long as the parent is shown; - trying to hide the stacked widget is irrelevant, because the QTabWidget size hint functions will always consider the stacked widget hints, no matter the visibility;
This is a possible implementation that toggles visibility of the tab "pages" whenever a tab is clicked on the currently visible page (if any): clicking on a currently selected and visible tab will always hide the contents, while contents will be made visible when clicking on any tab, even if no contents are visible.
from PyQt5.QtWidgets import *
class ToggleTabWidget(QTabWidget):
_contentsVisible = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tabBarClicked.connect(self.toggleContentsVisibleFromClick)
self._stackedWidget = self.findChild(QStackedWidget)
def toggleContentsVisibleFromClick(self, index):
if not self._contentsVisible or index == self.currentIndex():
self.toggleContentsVisibility()
def toggleContentsVisibility(self):
self.setContentsVisible(not self._contentsVisible)
def setContentsVisible(self, visible):
if self._contentsVisible != visible:
self._contentsVisible = visible
self._stackedWidget.setVisible(visible)
self.setDocumentMode(not visible)
tabHint = self.tabBar().sizeHint()
maxSize = 16777215 # default maximum size
if not self.tabPosition() & self.West:
# horizontal
if not visible:
maxSize = tabHint.height()
self.setMaximumHeight(maxSize)
else:
if not visible:
maxSize = tabHint.width()
self.setMaximumWidth(maxSize)
class Test(QWidget):
def __init__(self):
super().__init__()
self.tabWidget = ToggleTabWidget()
self.tabWidget.addTab(QTextEdit('hello world'), 'Hello')
self.tabWidget.addTab(QTextEdit('bye world'), 'Bye')
self.table = QTableWidget(10, 2)
layout = QVBoxLayout(self)
layout.addWidget(self.tabWidget)
layout.addWidget(self.table)
app = QApplication([])
test = Test()
test.show()
app.exec()
Note that:
- this doesn't consider style changes (including further calls to
setStyleSheet()
) or font changes that might affect the size of the tab bar; - a proper implementation should not use
setMaximum<size-or-dimension>()
, but overridesizeHint()
andminimumSizeHint()
instead, and it should also consider possible changes in the tab widget size policy; - due to the above, explicit changes in the
maximum<size-or-dimension>
done outside of the class should be taken into account; - the
setDocumentMode
is used to completely "hide" the contents of the tab pages, and will ignore any previous or further explicit call; if you need to use that property, you have to implement a further property that manages the explicitly set value and the internal one set by the visibility toggling;
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.