pyqt5 在 tablewidget 中加入 comboBox,并对 comboBox 的修改做出响应

文章目录

  • 背景介绍
  • 初始代码
    • UI 代码
    • 逻辑代码
    • 效果展示
  • 低阶修改
  • 进阶修改

背景介绍

用例:用 tablewidget 展示查询到的学生信息,为了防止错误修改,让学生的性别项修改时只能是“男”或“女”
效果展示:
pyqt5 在 tablewidget 中加入 comboBox,并对 comboBox 的修改做出响应_第1张图片

初始代码

UI 代码

# -*- 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 ,所以没有反应。
pyqt5 在 tablewidget 中加入 comboBox,并对 comboBox 的修改做出响应_第2张图片

低阶修改

给 combo box 修改信号绑定函数,然后在绑定的函数里面通知 tablewidget 修改;这里的 bug 是:实际修改 combo box 的时候并不会选中该 item,所以有时候会发生修改的是第二项,但软件读到的是第一项这种错误。(注意观察示例中的“修改位置:”,这个打印的结果有时候会对应不上)
pyqt5 在 tablewidget 中加入 comboBox,并对 comboBox 的修改做出响应_第3张图片

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 被修改了:(观察修改位置,这次是完全正确的了)
pyqt5 在 tablewidget 中加入 comboBox,并对 comboBox 的修改做出响应_第4张图片

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_())

以上;有问题欢迎评论区交流。

你可能感兴趣的:(Windows开发,qt,python,ui)