ComboBox in QTableWidget: Zelleintrag neben veränderter ComboBox einfügen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Luisa_H
User
Beiträge: 3
Registriert: Samstag 8. Dezember 2018, 13:58

Samstag 8. Dezember 2018, 14:32

Hallo zusammen,

ich möchte gerne einen Zelleneintrag zu der Zeile hinzufügen, in der mit der ComboBox eine Auswahl getroffen wurde. Dazu habe ich die einzelnen Comboboxen einer Liste hinzugefügt, um über den Listenindex die Tabellenzeile in Erfahrung zu bringen. Sobald ich versuche das "currentIndexChanged"-Signal der einzelnen Comboboxen über eine for-Schleife mit meiner Funktion "fill_cell" zu verbinden, wird der neue Wert, unabhänig von der Zeile der veränderten Combobox, in die letzte Zeile eingefügt. Was muss ich in meinem Code ändern, damit der Wert immer neben der geänderten Combobox steht?
Danke für die Hilfe!

Code: Alles auswählen

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout, QComboBox


class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 table'
        self.left = 20
        self.top = 40
        self.width = 500
        self.height = 300
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.createTable()

        # Add box layout, add table to box layout and add box layout to widget
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.tableWidget)
        self.setLayout(self.layout)

        # Show widget
        self.show()

    def createTable(self):
        # Create table
        self.tableWidget = QTableWidget()
        self.tableWidget.setRowCount(4)
        self.tableWidget.setColumnCount(2)

        combo_box_options = ["Option 0", "Option 1", "Option 2"]
        combo_box_list = []

        for i in range(0, self.tableWidget.rowCount()):
            self.combo = QComboBox()
            combo_box_list.append(self.combo)
            combo_box_list[i].addItems(combo_box_options)
            self.tableWidget.setCellWidget(i, 0, combo_box_list[i])

        ## Mit diesem Code funktioniert es
        # combo_box_list[0].currentIndexChanged.connect(lambda idx: self.fill_cell(idx, 0))
        # combo_box_list[1].currentIndexChanged.connect(lambda idx: self.fill_cell(idx, 1))
        # combo_box_list[2].currentIndexChanged.connect(lambda idx: self.fill_cell(idx, 2))
        # combo_box_list[3].currentIndexChanged.connect(lambda idx: self.fill_cell(idx, 3))
        
        # Sobald ich die Reihe als Variable definiere, funktioniert die Zuweisung nicht mehr: Die Zelle wird unabhängig
        # von der angesteuerten ComboBox immer in der letzten Reihe hinzugefügt
        for j in range(0, self.tableWidget.rowCount()):
            combo_box_list[j].currentIndexChanged.connect(lambda idx: self.fill_cell(idx, j))

    def fill_cell(self, table_idx):
        self.tableWidget.setItem(table_idx, 1, QTableWidgetItem('NewCell'))
        print(table_idx)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())
    
__deets__
User
Beiträge: 6178
Registriert: Mittwoch 14. Oktober 2015, 14:29

Samstag 8. Dezember 2018, 14:49

Das ist eine der beliebten Fallen: Abschluessen (englisch: Closures) in Python fangen die um sie herum existierenden NAMEN ein. Dein lambda kennt also j als Namen, nimmt sich aber den Wert, den j als letztes gehabt hat.

Zwei prominente Moeglichkeiten, dass zu loesen:

- explizite benamte Argumente im lambda: lambda j=j, idx=idx: self.fill_cell(idx, j)
- partial: ... connect(functools.partial(self.fill_cell, idx, j))
Luisa_H
User
Beiträge: 3
Registriert: Samstag 8. Dezember 2018, 13:58

Montag 10. Dezember 2018, 10:37

Danke, mit der zweiten Möglichkeit hat es geklappt. Wie kann ich zusätzlich den Index der neuen Combobox Auswahl mit übergeben?
__deets__
User
Beiträge: 6178
Registriert: Mittwoch 14. Oktober 2015, 14:29

Montag 10. Dezember 2018, 11:15

Ah, das habe ich verbockt. Du kannst natuerlich mit partial auch Argumente offen lassen, und dann wird das aus dem Signal fallende Argument auch benutzt. Ich hab' nicht genau genug hingeschaut, und schon gleich beide "ge-curried".
Antworten