在表单完成之前不要更改 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+Tab 和 Ctrl+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
检查。
我试图让用户在填写表格 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+Tab 和 Ctrl+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
检查。