小能豆

closeTab 函数可关闭 PyQt5 中的多个选项卡

py

我创建了一个添加新选项卡的功能,其中只有新选项卡有关闭按钮,我的意思是,"Tab 1""+"没有关闭按钮。所以这是代码:

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)

1.png

2.png

当我尝试添加关闭功能时,我遇到了包含要关闭的选项卡索引的事件,该事件触发的次数与选项卡数量相同,因此它会关闭多个选项卡。我做错了什么?


阅读 17

收藏
2024-12-21

共1个答案

小能豆

tabCloseRequested每次设置可关闭的标签时,您都会连接信号。每次将信号连接到插槽时,信号发出时将调用插槽:如果您连接两次,则插槽将被调用两次。

在您的情况下,如果您创建了两个选项卡,则关闭信号将被连接两次,因此如果您尝试关闭第一个选项卡,closeTab(0)则会被调用两次,从而导致关闭第一个第二个选项卡(在前一个选项卡被删除后,第二个选项卡将成为第一个)。

从中删除连接setClosableTabs并将其放入__init__

class Tab(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        # ...
        self.tabWidget.tabCloseRequested.connect(self.closeTab)

请注意,您的实现也存在其他问题,其中最重要的是使用选项卡小部件的内部列表。

Qt 已经提供了您所需要的:count()返回选项卡数量,并widget(index)根据索引返回单个小部件,以防您需要它。
通常不鼓励使用任何其他方法,因为如果未正确实现,可能会导致错误或意外行为,而这正是您的情况:

  1. 当选项卡关闭时,您不会将其从列表中删除(因此它将newTab()不起作用,因为它将返回错误的列表长度);
  2. 您正在使用列表的类属性,该列表应仅包含作为实例成员的对象;

想象一下如果您创建同一个 Tab 类的两个实例会发生什么:如果您向第一个窗口添加一个选项卡,那么第二个窗口也会在其 中看到该选项卡tabs_list,因为它是所有实例之间共享的类属性。

这是您要尝试执行的操作的一个更好且实际上更简单的实现(请注意,您应该从 UI 中删除第二个“+”选项卡,因为它是通过编程添加的):

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)
2024-12-21