动态 QComboBox 填充取决于用户输入 PyQt5

Dynamic QComboBox fill dependent on user input PyQt5

我创建了 QTableWidget 并在前两列中插入了组合框。第一列包含唯一记录(列表列表中的第一个元素)。我的目标是使这些组合框完全动态,即如果用户在第一个组合框中选择 'Butterfly',第二个组合框将提供 'PP' 和 'BR' 供选择。

即使从另一端优化搜索也应该有效,即如果用户在第二个组合框中选择 'KL',那么第一个将自动填写 'Toy'。

我尝试(使用 pandas 数据框)根据用户选择成功过滤出结果。但是,因此我想将这些结果放入适当的组合框中(没有成功)。

然后我尝试采用此线程上发布的解决方案: 并将其合并到我的代码中,但没有成功。

下面是带有注释部分但不起作用的代码:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from pandas import DataFrame

class Window(QMainWindow):

    def __init__(self, parent = None):
        super(Window,self).__init__(parent)
        self.Table_of_widgets()

    def Table_of_widgets(self):

        rowCount = 20
        columnCount = 9

        self.table = QTableWidget()
        self.table.setColumnCount(columnCount)
        self.table.setRowCount(rowCount)
        self.table.setHorizontalHeaderLabels(['Section', 'Label', 'Product description', 'Picture', 'Product ID', "Amount", "Unit price", "Store", "Total price"])
        self.table.verticalHeader().hide()

        self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(5, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(6, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(7, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(8, QHeaderView.Stretch)

        self.table.showMaximized()

        list1 = [
        ['Butterfly','16/1/001','PP','Pepito Butterfly','350'],
        ['Butterfly','16/1/002','PP','Brown Butterfly','350'],
        ['Butterfly','16/1/003','PP','Blue Butterfly','350'],
        ['Butterfly','bra01','BR','White Butterfly','500'],
        ['Backpack','bra02','BR','Backpack-blue','1500'],
        ['Backpack','bra03','BR','Backpack-black','1250'],
        ['Toy','klv01','KL','Bear','200'],
        ['Toy','klv02','KL','Fish','500'],
        ['Toy','klv03','KL','Rabbit','400'],
        ['Toy','klv04','KL','Owl','450'],
        ]

        dataset = DataFrame(list1)
        fin = list(dataset[0].drop_duplicates())
        fin.insert(0,'')
        fin2 = list(dataset[2].drop_duplicates())
        fin2.insert(0,'')

        for i in range(rowCount):
            comboA = QComboBox()
            comboA.addItems(fin)
##            comboA.currentTextChanged.connect(self.onCurrentTextChanged)
            self.table.setCellWidget(i,0,comboA)

        for i in range(rowCount):
            comboB = QComboBox()
            comboB.addItems(fin2)         
            self.table.setCellWidget(i,1,comboB)

##    def onCurrentTextChanged(self, text):
##        self.comboB.clear()
##        elements = fin1
##        if isinstance(elements, list):
##            self.comboB.addItems(elements)
##        else:
##            self.comboB.addItem(elements)

if __name__ == "__main__":

    app = QApplication(sys.argv)
    app.setApplicationName('MyWindow')
    main = Window()
    sys.exit(app.exec_())

我想我没有以正确的方式连接信号。感谢您的任何建议!

编辑:

我尽量做到准确,但也许还有一个 space 不确定。

这是我想要的更多信息:

默认情况下,所有组合框都应设置为空白值。如果用户在 combo2 中选择空白值,combo1 没有任何变化,如果用户在 combo2 中选择 PP,combo1 中只会出现蝴蝶(和空白),如果用户在 combo2 中选择 BR,则只有蝴蝶和背包(和空白)会出现在 combo1 中.这同样适用于combo1:如果用户在combo1中选择Butterfly,则只有BR和PP(和空白)应该出现在combo 2中,如果他在combo1中选择Backpack,则只有BR(和空白)会出现

进一步编辑:

先前设定的目标已达到(感谢@eyllanesc)。现在我计划添加第三列组合框,提供来自 list1(qtablewidget 中的产品描述列)的第 4 个元素(即 list1[3])。为此,必须更改字典。在阅读了一些帖子后 (Access an arbitrary element in a dictionary in Python; ),我仍然无法形成所需的结构(可能在 for 循环中添加条目之前 createData 为空):

d = {" ": [[" "], [" "]]}
d_inverse = {" ": [[" "], [" "]]}

def createData(key1, key2, key3, data):
    if key2 not in data[[" "], [" "]][0]:
        data[[" "], [" "]][0].append(key2)
        if key3 not in data[[" "], [" "]][1]:
            data[[" "], [" "]][1].append(key3)
    if key1 in data.keys():
        if key2 not in data[key1]:
            data[key1].append(key2)
            if key3 not in data[key1]:
                data[key1].append(key3)
    else:
        data[key1] = [" ", key2, key3]
    return data

for item in template:
    item1 = item[0]
    item2 = item[3]
    item3 = item[2]
    d = createData(item1, item2, item3, d)
    d_inverse = createData(item3, item2, item1, d_inverse)

必须完成的第一个任务是创建一个允许处理简单形式数据的数据结构,在这种情况下,使用包含列表的字典:

self.d = {" ": []}

for item in list1:
    combo1 = item[0]
    combo2 = item[2]
    if combo2 not in self.d[" "]:
        self.d[" "].append(combo2)

    if combo1 in self.d.keys():
        if combo2 not in self.d[combo1]:
            self.d[combo1].append(combo2)
    else:
        self.d[combo1] = []

输出:

{ 
   ' '         : ['PP', 'BR', 'KL'], 
   'Butterfly' : ['PP', 'BR'], 
   'Backpack'  : ['BR'], 
   'Toy'       : ['KL'] 
}

然后连接QComboBoxcurrentTextChanged信号,但是你还必须传递其他关联的QComboBox,因为使用了lambda函数。使用 blockSignals() 方法,我们阻止在信号之间生成循环。

class Window(QMainWindow):
    [...]
    def Table_of_widgets(self):
        [...]

        list1 = [...]


        self.d = {" ": [" "]}
        self.d_inverse = {" ": [" "]}

        def createData(key1, key2, data):
            if key2 not in data[" "]:
                data[" "].append(key2)
            if key1 in data.keys():
                if key2 not in data[key1]:
                    data[key1].append(key2)
            else:
                data[key1] = [" ", key2]
            return data

        for item in list1:
            item1 = item[0]
            item2 = item[2]
            self.d = createData(item1, item2, self.d)
            self.d_inverse = createData(item2, item1, self.d_inverse)

        for i in range(rowCount):
            comboA = QComboBox()
            comboB = QComboBox()
            comboA.addItems(self.d.keys())
            comboB.addItems(self.d[comboA.currentText()])
            self.table.setCellWidget(i, 0, comboA)
            self.table.setCellWidget(i, 1, comboB)
            comboA.currentTextChanged.connect(lambda text, row=i: self.onComboACurrentTextChanged(text, row))
            comboB.currentTextChanged.connect(lambda text, row=i: self.onComboBCurrentTextChanged(text, row))

    def updateCombox(self, combo1, combo2, item1, item2):
        text = combo1.currentText()
        combo1.blockSignals(True)
        combo2.blockSignals(True)
        combo1.clear()
        combo2.clear()

        combo2.addItems(item1[text])
        combo2.setCurrentIndex(1 if text != " " else 0)
        combo1.addItems(item2[combo2.currentText()])
        combo1.setCurrentText(text)

        combo1.blockSignals(False)
        combo2.blockSignals(False)

    def onComboACurrentTextChanged(self, text, row):
        comboA = self.table.cellWidget(row, 0)
        comboB = self.table.cellWidget(row, 1)
        self.updateCombox(comboA, comboB, self.d, self.d_inverse)

    def onComboBCurrentTextChanged(self, text, row):
        comboA = self.table.cellWidget(row, 0)
        comboB = self.table.cellWidget(row, 1)
        self.updateCombox(comboB, comboA, self.d_inverse, self.d)