动态 QComboBox 填充取决于用户输入 PyQt5 [英] Dynamic QComboBox fill dependent on user input PyQt5

查看:115
本文介绍了动态 QComboBox 填充取决于用户输入 PyQt5的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created QTableWidget and in first two columns inserted comboboxes. The first column contains unique records (first elements from list of lists). My aim is to make these combo boxes fully dynamic, i.e. if the user selects 'Butterfly' within the first combobox, the second combobox will offer 'PP' and 'BR' for selection.

细化搜索应该从另一边工作,即如果用户在第二个组合框中选择KL",那么第一个将自动填充玩具".

Refining the search should work even from other side, i.e. if user selects 'KL' in the second combobox, then the first one will automaticaly fill in 'Toy'.

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

I tried (using pandas dataframe) to filter out the results based upon user selection with success. However, consequently I wanted put these results into appropriate combobox (with no success).

然后我尝试采用发布在此线程上的解决方案:如何根据 PyQt5 中的另一个 QComboBox 更改一个 QComboBox 的内容? 并将其合并到我的代码中但没有成功.

Then I tried to adopt solution posted on this thread: How can I change the contents of one QComboBox depending on another QComboBox in PyQt5? and incorporate it into my code with no success.

以下是注释部分不起作用的代码:

Here below is the code with commented sections that do not work:

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

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

I think I failed to connect the signal in a proper way. Thanks for any suggestion!

我试图尽可能精确,但也许仍然存在不确定性.

I tried to be as precise as possible but perhaps there still was a space for uncertainty.

以下是我所追求的更多信息:

Here is further information what I am after:

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

All comboxes should be set to blank values by default. If user selects in combo2 blank value, nothing changes for combo1, if user selects PP in combo2, only Butterfly (and blank) will appear in combo1, if user selects BR in combo2, only Butterfly and Backpack (and blank) will appear in combo1. The same should be valid for combo1: if user selects Butterfly in combo1, only BR and PP (and blank) should appear in combo 2, if he chooses Backpack in combo1 only BR (and blank) will appear

进一步

达到了之前设定的目标(感谢@eyllanesc).现在我计划从 list1(qtablewidget 中的产品描述列)添加第三列组合框,提供第 4 个元素(即 list1[3]).为此,必须更改字典.阅读一些帖子后(在 Python 中访问字典中的任意元素; 字典在 Python 3.6+ 中排序) I仍然无法形成所需的结构(可能在 for 循环中添加条目之前 createData 为空):

Previously stated goal was reached (thanks to @eyllanesc). Now I plan to add third column of comboboxes offering 4th element (i.e. list1[3]) from list1 (product description column within qtablewidget). For that the dictionary must be changed. After reading some posts (Access an arbitrary element in a dictionary in Python; Dictionaries are ordered in Python 3.6+) I still fail to form the structure that is needed (maybe createData is empty before entries are added within for loop):

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)

推荐答案

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

The first task that must be done is to create a structure of data that allows to handle the data of simple form, in this case a dictionary is used that contain lists:

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() 方法,我们可以阻止在信号之间生成循环.

Then connect the currentTextChanged signals of the QComboBox, but you must also pass the other associated QComboBox for that the lambda function is used. with the blockSignals() method we block that a loop is generated between the signals.

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)

这篇关于动态 QComboBox 填充取决于用户输入 PyQt5的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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