closeTab 函数它在 PyQt5 中关闭多个选项卡

Posted

技术标签:

【中文标题】closeTab 函数它在 PyQt5 中关闭多个选项卡【英文标题】:closeTab function it closes more than one tab in PyQt5 【发布时间】:2020-12-27 16:31:37 【问题描述】:

我构建了一个添加新标签的功能,其中只有新标签有关闭按钮,我的意思是"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】:

每次您将标签设置为可关闭时,您都会连接tabCloseRequested 信号。每次你连接一个信号到一个槽,这个槽会在信号发射时被调用:如果你连接两次,槽就会被调用两次。

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

setClosableTabs的连接去掉,放到__init__

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

请注意,您的实现还有其他问题,其中最重要的是使用标签小部件的内部列表。

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

    当标签关闭时,您不会从列表中删除标签(因此newTab() 将不起作用,因为它会返回错误的列表长度); 您正在为一个列表使用 class 属性,该列表应该只包含属于 instance 成员的对象;

想象一下,如果您创建同一个 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)

【讨论】:

以上是关于closeTab 函数它在 PyQt5 中关闭多个选项卡的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VC++ 项目中关闭 Unicode?

在 PyQt 中关闭窗口后如何检索属性值?

如何在关闭特定选项卡而不是在 Angular 2 中关闭浏览器时清除本地存储?

当有多个具有不同通知ID的通知时,如何在android中关闭通知?

在QT中关闭窗口之前获取应用程序退出信号

在 perl 中关闭多个输出管道而不阻塞每个输出管道