在表单完成之前不要更改 QTabWidget 的 TAB

do not change the TAB of the QTabWidget until the form is complete

我试图让用户在填写表格 1 之前不会切换到“表格 2”所在的下一个 TAB。

我尝试了“currentChange”事件,但它没有按我想要的方式工作,因为它在已经从 TAB 更改时显示警报。

有没有办法在任务完成之前保持当前 TAB 不变?

我附上代码和图片

import sys
from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets

class MyWidget(QtWidgets.QWidget):

    def __init__(self):
        super(MyWidget, self).__init__()
        self.setGeometry(0, 0, 800, 500)
        self.setLayout(QtWidgets.QVBoxLayout())

        #flag to not show the alert when starting the program
        self.flag = True

        #changes to True when the form is completed
        self.form_completed = False

        #WIDGET TAB 1
        self.widget_form1 = QtWidgets.QWidget()
        self.widget_form1.setLayout(QtWidgets.QVBoxLayout())
        self.widget_form1.layout().setAlignment(Qt.AlignHCenter)
        label_form1 = QtWidgets.QLabel("FORM 1")
        self.widget_form1.layout().addWidget(label_form1)

        #WIDGET TAB 2
        self.widget_form2 = QtWidgets.QWidget()
        self.widget_form2.setLayout(QtWidgets.QVBoxLayout())
        self.widget_form2.layout().setAlignment(Qt.AlignHCenter)
        label_form2 = QtWidgets.QLabel("FORM 2")
        self.widget_form2.layout().addWidget(label_form2)

        #QTABWIDGET
        self.tab_widget = QtWidgets.QTabWidget()
        self.tab_widget.currentChanged.connect(self.changed)
        self.tab_widget.addTab(self.widget_form1,"Form 1")
        self.tab_widget.addTab(self.widget_form2, "Form 2")

        self.layout().addWidget(self.tab_widget)

    def changed(self,index):
        if self.flag:
            self.flag = False
            return

        if not self.form_completed:
            QtWidgets.QMessageBox.about(self, "Warning", "You must complete the form")
            return

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    mw = MyWidget()
    mw.show()
    sys.exit(app.exec_())

当索引已经改变时currentChanged信号被发出(动词是过去时:Changed),所以如果你想防止更改,您必须检测任何用户尝试切换选项卡。

为此,您必须同时检查鼠标和键盘事件:

  • 在标签栏上单击鼠标左键;
  • Ctrl+TabCtrl+Shift+Tab 在选项卡小部件上;

由于您必须从主 window 控制该行为,唯一的解决方案是在选项卡小部件及其 tabBar() 上安装事件过滤器,然后如果该操作会改变索引但表单未完成,您必须 return True 以便小部件不会处理该事件。

请考虑以下假设必须保持活动的选项卡是当前(第一个添加的选项卡,或使用setCurrentIndex()设置的选项卡) .

class MyWidget(QtWidgets.QWidget):
    def __init__(self):
        # ...
        self.tab_widget.installEventFilter(self)
        self.tab_widget.tabBar().installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == event.KeyPress and \
            event.key() in (Qt.Key_Left, Qt.Key_Right):
                return not self.form_completed
        elif source == self.tab_widget.tabBar() and \
            event.type() == event.MouseButtonPress and \
            event.button() == Qt.LeftButton:
                tab = self.tab_widget.tabBar().tabAt(event.pos())
                if tab >= 0 and tab != self.tab_widget.currentIndex():
                    return self.isInvalid()
        elif source == self.tab_widget and \
            event.type() == event.KeyPress and \
            event.key() in (Qt.Key_Tab, Qt.Key_Backtab) and \
            event.modifiers() & Qt.ControlModifier:
                return self.isInvalid()
        return super().eventFilter(source, event)
    def isInvalid(self):
        if not self.form_completed:
            QTimer.singleShot(0, lambda: QtWidgets.QMessageBox.about(
                self, "Warning", "You must complete the form"))
            return True
        return False

请注意,我使用 QTimer 显示了消息框,以便立即正确地 return 事件过滤器。

还要考虑在对象创建和配置结束时连接信号是一种很好的做法,这对于通知 属性 更改的信号更为重要:您不应该在设置 属性 可以触发它。
由于空 QTabWidget 有一个 -1 索引,一旦您添加第一个选项卡,索引就会更改为 0,从而触发信号。只需在添加选项卡后移动currentChanged信号连接,就可以摆脱self.flag检查。