Python 如何从QComboBox中获取要在PyQt5中的QTableWidget中显示的选定项?(QComboBox具有用于选择项目的复选框)

Python 如何从QComboBox中获取要在PyQt5中的QTableWidget中显示的选定项?(QComboBox具有用于选择项目的复选框),python,python-3.x,pyqt,pyqt5,Python,Python 3.x,Pyqt,Pyqt5,我有一个QTableWidget,其中每一行中都有一个特定列的QComboBox。我的每个QCombobox都有多个带有复选框的值。我希望在同一行的下一列“SelectedMonths”中显示每个组合框中的选定项目,并在取消选中时将其删除(反之亦然) 到目前为止,我已经准备好了脚本,它告诉我所有项目都被选中/取消选中了,但我不知道如何获取激活combobox的行的索引 获取工作流的代码段 示例代码: QtDesigner生成的代码:Demo.py from PyQt5 import QtCor

我有一个QTableWidget,其中每一行中都有一个特定列的QComboBox。我的每个QCombobox都有多个带有复选框的值。我希望在同一行的下一列“SelectedMonths”中显示每个组合框中的选定项目,并在取消选中时将其删除(反之亦然)

到目前为止,我已经准备好了脚本,它告诉我所有项目都被选中/取消选中了,但我不知道如何获取激活combobox的行的索引

获取工作流的代码段

示例代码:

QtDesigner生成的代码:Demo.py

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(464, 291)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(30, 30, 411, 221))
        self.tableWidget.setRowCount(1)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setObjectName("tableWidget")
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 1, item)
        self.tableWidget.horizontalHeader().setVisible(False)
        self.tableWidget.verticalHeader().setVisible(False)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        item = self.tableWidget.item(0, 0)
        item.setText(_translate("MainWindow", "Select Months"))
        item = self.tableWidget.item(0, 1)
        item.setText(_translate("MainWindow", "Selected Months"))
        self.tableWidget.setSortingEnabled(__sortingEnabled)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QTableWidgetItem
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt
from datetime import date
from dateutil.relativedelta import relativedelta

from Demo import Ui_MainWindow

def CheckableCombobox(combo, options):
    model = QStandardItemModel(len(options), 1)
    firstItem = QtGui.QStandardItem("SelectMonths")
    firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
    firstItem.setSelectable(False)
    model.setItem(0, 0, firstItem)
    for i, area in enumerate(options):
        item = QStandardItem(area)
        item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
        item.setData(Qt.Unchecked, Qt.CheckStateRole)
        model.setItem(i+1, 0, item)
    combo.setModel(model)

class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):                    
    def __init__(self):
        super(DemoCode, self).__init__()
        self.setupUi(self)  

        self.rowPosition = self.tableWidget.rowCount()
        for row in range(0,3):
            self.tableWidget.insertRow(self.rowPosition)
            for column in range(0,2):
                if column == 0:
                    self.ComboBox = QtWidgets.QComboBox()
                    dtStart = date.today()
                    self.Monthlist = []
                    for n in range(1, 5):
                        self.Monthlist.append((dtStart + relativedelta(months=-n)).strftime('1-%b-%Y'))
                    CheckableCombobox(self.ComboBox, self.Monthlist)
                    self.ComboBox.model().itemChanged.connect(self.on_itemChanged)
                    self.tableWidget.setCellWidget(self.rowPosition, column, self.ComboBox)
                elif column == 1:
                    item = QTableWidgetItem('')
                    self.tableWidget.setItem(self.rowPosition, column, item)

            self.rowPosition += 1

        self.tableWidget.setColumnWidth(1,150)

    def on_itemChanged(self, item):
        current_state = item.data(Qt.CheckStateRole)
        print(current_state, item.text())

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = DemoCode()    
    window.show()
    sys.exit(app.exec_())
我编写的代码:DemoCode.py

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(464, 291)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(30, 30, 411, 221))
        self.tableWidget.setRowCount(1)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setObjectName("tableWidget")
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 1, item)
        self.tableWidget.horizontalHeader().setVisible(False)
        self.tableWidget.verticalHeader().setVisible(False)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        item = self.tableWidget.item(0, 0)
        item.setText(_translate("MainWindow", "Select Months"))
        item = self.tableWidget.item(0, 1)
        item.setText(_translate("MainWindow", "Selected Months"))
        self.tableWidget.setSortingEnabled(__sortingEnabled)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QTableWidgetItem
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt
from datetime import date
from dateutil.relativedelta import relativedelta

from Demo import Ui_MainWindow

def CheckableCombobox(combo, options):
    model = QStandardItemModel(len(options), 1)
    firstItem = QtGui.QStandardItem("SelectMonths")
    firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
    firstItem.setSelectable(False)
    model.setItem(0, 0, firstItem)
    for i, area in enumerate(options):
        item = QStandardItem(area)
        item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
        item.setData(Qt.Unchecked, Qt.CheckStateRole)
        model.setItem(i+1, 0, item)
    combo.setModel(model)

class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):                    
    def __init__(self):
        super(DemoCode, self).__init__()
        self.setupUi(self)  

        self.rowPosition = self.tableWidget.rowCount()
        for row in range(0,3):
            self.tableWidget.insertRow(self.rowPosition)
            for column in range(0,2):
                if column == 0:
                    self.ComboBox = QtWidgets.QComboBox()
                    dtStart = date.today()
                    self.Monthlist = []
                    for n in range(1, 5):
                        self.Monthlist.append((dtStart + relativedelta(months=-n)).strftime('1-%b-%Y'))
                    CheckableCombobox(self.ComboBox, self.Monthlist)
                    self.ComboBox.model().itemChanged.connect(self.on_itemChanged)
                    self.tableWidget.setCellWidget(self.rowPosition, column, self.ComboBox)
                elif column == 1:
                    item = QTableWidgetItem('')
                    self.tableWidget.setItem(self.rowPosition, column, item)

            self.rowPosition += 1

        self.tableWidget.setColumnWidth(1,150)

    def on_itemChanged(self, item):
        current_state = item.data(Qt.CheckStateRole)
        print(current_state, item.text())

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = DemoCode()    
    window.show()
    sys.exit(app.exec_())

您应该找到一种方法来跟踪每个组合模型的行,以便可以相应地设置项目文本

请注意,我稍微更改了您的代码逻辑,因为存在一些概念错误:

  • 如果实例属性不是必需的,就不要设置它们:所有那些
    self.rowPosition
    self.monthList
    ,等等,每次for循环都会更改,之后就不需要它们了
  • 避免对变量和函数使用大写名称
  • 月份列表总是一样的,在for循环之前构建它,而不是每次都计算它
  • 不要将模型设置为函数中的组合,而是让它返回模型
编辑:在注释请求后添加了复制功能

def createModel(options):
    model = QStandardItemModel(len(options), 1)
    firstItem = QtGui.QStandardItem("SelectMonths")
    firstItem.setBackground(QtGui.QBrush(QtGui.QColor(200, 200, 200)))
    firstItem.setSelectable(False)
    model.setItem(0, 0, firstItem)
    for i, area in enumerate(options):
        item = QStandardItem(area)
        item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
        item.setData(Qt.Unchecked, Qt.CheckStateRole)
        model.setItem(i+1, 0, item)
    return model

class DemoCode(QtWidgets.QMainWindow, Ui_MainWindow):                    
    def __init__(self):
        super(DemoCode, self).__init__()
        self.setupUi(self)  

        monthList = [(date.today() + relativedelta(months=-n)).strftime('1-%b-%Y') for n in range(1, 5)]
        self.models = {}

        rows = self.tableWidget.rowCount()
        for row in range(rows, rows + 3):
            self.tableWidget.insertRow(row)
            comboBox = QtWidgets.QComboBox()
            model = createModel(monthList)
            comboBox.setModel(model)
            model.itemChanged.connect(lambda _, row=row: self.on_itemChanged(row))
            self.models[row] = model
            self.tableWidget.setCellWidget(row, 0, comboBox)
            item = QTableWidgetItem()
            self.tableWidget.setItem(row, 1, item)

        self.tableWidget.setColumnWidth(1,150)

    def on_itemChanged(self, tableRow):
        model = self.models[tableRow]
        items = []
        for row in range(model.rowCount()):
            comboItem = model.index(row, 0)
            if comboItem.data(Qt.CheckStateRole):
                items.append(comboItem.data())
        self.tableWidget.item(tableRow, 1).setText(', '.join(items))

    def copyFromRow(self, tableRow):
        sourceModel = self.models[tableRow]
        checkedRows = []
        for row in range(sourceModel.rowCount()):
            if sourceModel.index(row, 0).data(Qt.CheckStateRole):
                checkedRows.append(row)
        for model in self.models.values():
            if model == sourceModel:
                continue
            for row in range(model.rowCount()):
                model.setData(
                    model.index(row, 0), 
                    Qt.Checked if row in checkedRows else Qt.Unchecked, 
                    Qt.CheckStateRole)

我还建议删除“选择月份”和“选择月份”项目,并将它们用作表格标题。

谢谢@musicamante它起作用了!!如果您还可以告诉我,如果要通过按按钮将所选项目从第一行复制到所有行,那就太好了,我该怎么做?我的意思是,如果我从第一行选择两个项目,它将在其他组合框以及组合框旁边的列中保持选中这两个项目。@VirenKheni我不确定我是否理解。让我们看看:如果我按下一个按钮,它会将第一行组合框的选中状态设置为所有其他组合框?其他组合框中已选中的项目如何?是否应取消选中?是,它应覆盖第一行的选择。在此之后,如果我选择/删除第二行或第三行中的新项目,选择将相应更改。@VirenKheni我已经更新了答案,该函数使用
tableRow
访问正确的模型,请记住,如果您仍然使用第一行作为“标题”(但是,同样,您不应该),您必须考虑到这一点;因此,在您的情况下,您应该调用
copyFromRow(1)
从第一个组合进行复制,而通常情况下,行应该从0开始。谢谢!它是完美的!:)