如何从 QComboBox 中获取所选项目以显示在 PyQt5 的 QTableWidget 中?(QComboBox 有选择项目的复选框) [英] How to get selected items from QComboBox to be displayed in QTableWidget in PyQt5? (QComboBox has checkbox to pick items)

查看:41
本文介绍了如何从 QComboBox 中获取所选项目以显示在 PyQt5 的 QTableWidget 中?(QComboBox 有选择项目的复选框)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 QTableWidget,其中每一行都有特定列的 QComboBox.我的每个 QCombobox 都有多个带有复选框的值.我想在同一行的下一个相应列SelectedMonths"中显示每个组合框中的选定项目,并在未选中时将其删除(反之亦然).

I have QTableWidget in which I have QComboBox in each row for particular column. My each QCombobox has multiple values with checkboxes. I want to display selected item/s from each combobox in the next respective column 'SelectedMonths' in the same row and remove them when unchecked (Vice-versa).

到目前为止,我已经准备好了脚本,它为我提供了所有已选中/未选中的项目,但我不知道如何获取激活组合框的行的索引.

Until now I have Script ready which gives me what all items have been checked/unchecked but I dont know how to get the index of the row for which combobox is activated.

获取工作流程的代码段

示例代码:

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

我写的代码:DemoCode.py

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

推荐答案

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

You should find a way to keep track of the row for each combo model, so that you can set the item text accordingly.

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

Note that I changed your code logic a bit, as there were some conceptual mistakes:

  • 如果不需要,则不要设置实例属性:所有那些 self.rowPositionself.monthList 等,每次 for 循环循环时都会更改,并且您之后就不需要它们了;
  • 避免对变量和函数使用大写名称
  • 月份列表总是相同的,在for循环之前构建它而不是每次都计算它
  • 不要将模型设置为函数中的组合,而是让它返回模型
  • don't set instance attributes if they are not required: all those self.rowPosition, self.monthList, etc, change everytime the for loop cycles, and you don't need them after that;
  • avoid using uppercase names for variables and functions
  • the month list is always the same, build it before the for cycle instead of computing it each time
  • instead of setting the model to the combo in the function, make it return the model

编辑:添加评论请求后的复制功能

Edit: added copy function after comment request

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)

我还建议删除Select Months"和Selected Months"项,并将它们用作表格标题.

I'd also suggest to remove the "Select Months" and "Selected Months" items, and use them as table headers.

这篇关于如何从 QComboBox 中获取所选项目以显示在 PyQt5 的 QTableWidget 中?(QComboBox 有选择项目的复选框)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆