用例:用 tablewidget 展示查询到的学生信息,为了防止错误修改,让学生的性别项修改时只能是“男”或“女”
效果展示:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'a.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(798, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(0)
self.tableWidget.setRowCount(0)
self.verticalLayout.addWidget(self.tableWidget)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.verticalLayout_2.addLayout(self.verticalLayout)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "TextLabel"))
import datetime
import sys
import time
from collections import namedtuple
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QComboBox
from a import Ui_MainWindow
Student = namedtuple('Student', 'name gender age')
genders = ['男', '女']
class APP(QMainWindow, Ui_MainWindow):
def __init__(self):
super(APP, self).__init__()
self.setupUi(self)
self.setup_tablewidget()
def setup_tablewidget(self):
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '年龄'])
self.tableWidget.cellChanged.connect(self.revise_data)
# 填数据进去;一般是检索数据库得到数据再填进去,但是这里简化,直接录入
student1 = Student('绫波丽', '女', '14')
student2 = Student('明日香', '女', '14')
student3 = Student('碇真嗣', '女', '14')
self.update_tablewidget([student1, student2, student3])
def update_tablewidget(self, students):
# 阻塞信号,防止初始化添加信息的时候触发 revise 函数
self.tableWidget.blockSignals(True)
for i, student in enumerate(students):
self.tableWidget.insertRow(i)
name_item = QTableWidgetItem(student.name)
self.tableWidget.setItem(i, 0, name_item)
cb_gender = QComboBox()
cb_gender.addItems(genders)
cb_gender.setCurrentText(student.gender)
self.tableWidget.setCellWidget(i, 1, cb_gender)
age_item = QTableWidgetItem(student.age)
self.tableWidget.setItem(i, 2, age_item)
self.tableWidget.blockSignals(False)
def revise_data(self, i, j):
revise_str = self.tableWidget.item(i, j).text()
text = f'修改位置:{i} {j};修改为:{revise_str}'
self.label.setText(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = APP()
window.show()
sys.exit(app.exec_())
可见修改文本是可以响应的,但是修改 combo box 没有反应:因为修改时 combo box 的 current text,而这个变量本身没有变化,所以 tablewidget 没有检测到 cellChanged ,所以没有反应。
给 combo box 修改信号绑定函数,然后在绑定的函数里面通知 tablewidget 修改;这里的 bug 是:实际修改 combo box 的时候并不会选中该 item,所以有时候会发生修改的是第二项,但软件读到的是第一项这种错误。(注意观察示例中的“修改位置:”,这个打印的结果有时候会对应不上)
import datetime
import sys
import time
from collections import namedtuple
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QComboBox
from a import Ui_MainWindow
Student = namedtuple('Student', 'name gender age')
genders = ['男', '女']
class APP(QMainWindow, Ui_MainWindow):
def __init__(self):
super(APP, self).__init__()
self.setupUi(self)
self.setup_tablewidget()
def setup_tablewidget(self):
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '年龄'])
self.tableWidget.cellChanged.connect(self.revise_data)
# 填数据进去;一般是检索数据库得到数据再填进去,但是这里简化,直接录入
student1 = Student('绫波丽', '女', '14')
student2 = Student('明日香', '女', '14')
student3 = Student('碇真嗣', '女', '14')
self.update_tablewidget([student1, student2, student3])
def update_tablewidget(self, students):
# 阻塞信号,防止初始化添加信息的时候触发 revise 函数
self.tableWidget.blockSignals(True)
for i, student in enumerate(students):
self.tableWidget.insertRow(i)
name_item = QTableWidgetItem(student.name)
self.tableWidget.setItem(i, 0, name_item)
cb_gender = QComboBox()
cb_gender.addItems(genders)
cb_gender.setCurrentText(student.gender)
self.tableWidget.setCellWidget(i, 1, cb_gender)
cb_gender.currentIndexChanged.connect(self.cb_in_tw_changed)
age_item = QTableWidgetItem(student.age)
self.tableWidget.setItem(i, 2, age_item)
self.tableWidget.blockSignals(False)
def revise_data(self, i, j):
if j == 1:
revise_str = self.tableWidget.cellWidget(i, j).currentText()
else:
revise_str = self.tableWidget.item(i, j).text()
text = f'修改位置:{i} {j};修改为:{revise_str}'
self.label.setText(text)
def cb_in_tw_changed(self):
index = self.tableWidget.currentIndex() # todo: 这个是错的
print('current index tablewidget', int(index.row()), int(index.column()))![请添加图片描述](https://img-blog.csdnimg.cn/2a4bfbc3a89e4b3ab2a90738f1a46752.gif)
self.tableWidget.cellChanged.emit(int(index.row()), int(index.column()))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = APP()
window.show()
sys.exit(app.exec_())
为了解决这个问题,我们得直到修改信号是谁发出来的,并且把它的位置存下来,才能知道到底是哪个位置的 combo box 被修改了:(观察修改位置,这次是完全正确的了)
import datetime
import sys
import time
from collections import namedtuple
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidgetItem, QComboBox
from a import Ui_MainWindow
Student = namedtuple('Student', 'name gender age')
genders = ['男', '女']
class APP(QMainWindow, Ui_MainWindow):
def __init__(self):
super(APP, self).__init__()
self.cb_in_tw_dict = {}
self.setupUi(self)
self.setup_tablewidget()
def setup_tablewidget(self):
self.tableWidget.setColumnCount(3)
self.tableWidget.setHorizontalHeaderLabels(['姓名', '性别', '年龄'])
self.tableWidget.cellChanged.connect(self.revise_data)
# 填数据进去;一般是检索数据库得到数据再填进去,但是这里简化,直接录入
student1 = Student('绫波丽', '女', '14')
student2 = Student('明日香', '女', '14')
student3 = Student('碇真嗣', '女', '14')
self.update_tablewidget([student1, student2, student3])
def update_tablewidget(self, students):
self.cb_in_tw_dict.clear()
# 阻塞信号,防止初始化添加信息的时候触发 revise 函数
self.tableWidget.blockSignals(True)
for i, student in enumerate(students):
self.tableWidget.insertRow(i)
name_item = QTableWidgetItem(student.name)
self.tableWidget.setItem(i, 0, name_item)
cb_gender = QComboBox()
cb_gender.addItems(genders)
cb_gender.setCurrentText(student.gender)
self.tableWidget.setCellWidget(i, 1, cb_gender)
cb_gender.currentIndexChanged.connect(self.cb_in_tw_changed)
self.cb_in_tw_dict[cb_gender] = (i, 1)
age_item = QTableWidgetItem(student.age)
self.tableWidget.setItem(i, 2, age_item)
self.tableWidget.blockSignals(False)
def revise_data(self, i, j):
if j == 1:
revise_str = self.tableWidget.cellWidget(i, j).currentText()
else:
revise_str = self.tableWidget.item(i, j).text()
text = f'修改位置:{i} {j};修改为:{revise_str}'
self.label.setText(text)
def cb_in_tw_changed(self):
index = self.cb_in_tw_dict[self.sender()]
self.tableWidget.cellChanged.emit(*index)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = APP()
window.show()
sys.exit(app.exec_())
以上;有问题欢迎评论区交流。