Reputation: 461
I built a functionality for add new tabs in which only the new tabs has a close button, I mean the "Tab 1"
and the "+"
don't has the close button. So this it's the code:
tabs.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(628, 504)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setGeometry(QtCore.QRect(36, 34, 541, 396))
self.tabWidget.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded)
self.tabWidget.setTabsClosable(False)
self.tabWidget.setObjectName("tabWidget")
self.tab1 = QtWidgets.QWidget()
self.tab1.setObjectName("tab1")
self.tabWidget.addTab(self.tab1, "")
self.tab2 = QtWidgets.QWidget()
self.tab2.setObjectName("tab2")
self.tabWidget.addTab(self.tab2, "")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 628, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab1), _translate("MainWindow", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab2), _translate("MainWindow", "+"))
main.py
from tabs import Ui_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
class Tab(QtWidgets.QMainWindow, Ui_MainWindow):
tabs_list = []
def __init__(self):
super().__init__()
self.setupUi(self)
self.tabWidget.tabBarClicked.connect(self.newTab)
self.tabs_list.append(self.tab1)
self.tabs_list.append(self.tab2)
def newTab(self, event):
if event == len(self.tabs_list) - 1:
tab = QtWidgets.QWidget()
self.tabWidget.addTab(tab, "+")
self.tabs_list.append(tab)
self.tabWidget.setTabText(len(self.tabs_list) - 2, "Tab " + str(len(self.tabs_list) - 1))
self.setClosableTabs()
def setClosableTabs(self):
self.tabWidget.setTabsClosable(False)
self.tabWidget.setTabsClosable(True)
self.tabWidget.tabBar().setTabButton(0, QtWidgets.QTabBar.RightSide, None)
self.tabWidget.tabBar().setTabButton(len(self.tabs_list) - 1, QtWidgets.QTabBar.RightSide, None)
self.tabWidget.tabCloseRequested.connect(self.closeTab)
def closeTab(self, event):
print("close tab: ", event)
self.tabWidget.removeTab(event)
When I tried to add the close functionality I ran into with the event that contains the index of the tab that I want to close its triggered as many times as number of tabs there are, so then its close more than only one tab. What I'm doing wrong?
Upvotes: 2
Views: 534
Reputation: 48335
You are connecting the tabCloseRequested
signal everytime you are setting the tabs closable. Everytime you connect a signal to a slot, the slot will be called when the signal is emitted: if you connect it twice, the slot will be called twice.
In your case, if you create two tabs, the closed signal will be connected twice, so if you then try to close the first tab, closeTab(0)
will be called twice, resulting in closing both the first and the second (which will become the first after the previous one has been removed).
Remove the connection from setClosableTabs
and put it in the __init__
:
class Tab(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
# ...
self.tabWidget.tabCloseRequested.connect(self.closeTab)
Note that your implementation has other issues too, with the most important being using an internal list for the tab widgets.
Qt already provides what you need: count()
returns the amount of tabs, and widget(index)
returns the individual widgets based on the index, in case you're going to need it.
Using any other method is usually discouraged, as it might lead to errors or unexpected behavior if they are not properly implemented, and that's exactly your case:
newTab()
won't work, as it will return the wrong length of the list);Imagine what would happen if you create two instances of the same Tab class: if you add a tab to the first window, then the second window will see that too in its tabs_list
, since it's a class attribute that is shared among all instances.
This is a better and actually simpler implementation of what you're trying to do (note that you should remove the second "+" tab from your ui, as it's added programmatically):
class Tab(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.tabWidget.tabBarClicked.connect(self.newTab)
self.tabWidget.setTabsClosable(True)
self.tabWidget.tabCloseRequested.connect(self.closeTab)
# add the "+" tab to the tabbar, not the tabwidget
lastTab = self.tabWidget.tabBar().addTab('+')
self.tabWidget.tabBar().setTabButton(lastTab, QtWidgets.QTabBar.RightSide, None)
def newTab(self, event):
if event == self.tabWidget.count() - 1:
tab = QtWidgets.QWidget()
tabName = "Tab {}".format(self.tabWidget.count())
self.tabWidget.insertTab(self.tabWidget.count() - 1, tab, tabName)
Upvotes: 3