3

I am trying to link the value of combobox in column 1 with the box in column 3. On change of value in column 1 the values in the dropdown combo box need to change to a new set. On click of the button, a new row is to be added with similar combobox capability. The issue is that the only row that is responsive to the combobox value change in column 1 is in the most recent row added. How can i retain the link in all rows while adding rows as needed?

I have it currently set that the active row is the most current. How can I obtain the active row on click of the combobox inorder to activate that row? I am storing all combobxes in a dict.

My Attempt:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(60, 100, 551, 331))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(3)
        self.tableWidget.setRowCount(0)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(60, 450, 75, 23))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        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"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "Col 1"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Col 2"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "Col 3"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))

class mainWindow(Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.populate_table)

    # Combo box creator templates
    def comboBox_populator(self,values):
        combo = QtWidgets.QComboBox()
        for element in values:
            combo.addItem(element)
        return combo

    # Action to do on vehcile change
    def onComboChange(self):
        # selVehNames = self.selVehNames
        self.switchTo = self.comboBoxRows[self.counter][0].currentText()
        if self.switchTo == [] or self.switchTo == '':
            pass
        else:
            if self.switchTo == 'a':
                col1Data3 = ['x','y','z']
            elif self.switchTo == 'b':
                col1Data3 = ['4','5','6']
            elif self.switchTo == 'c':
                col1Data3 = ['21','22','23']
            else:
                pass
            # Update dict with comboboxes
            # col1Data1 = self.comboBoxRows[self.counter][0]
            # col1Data2 = self.comboBoxRows[self.counter][1]
            # self.AllComboBoxes = [col1Data1, col1Data2, col1Data3]

            colDataBox3 = self.comboBox_populator(col1Data3)
            print(col1Data3)
            # self.comboBoxRows.update({self.counter:self.AllComboBoxes})
            self.tableWidget.setCellWidget(self.counter,2,colDataBox3)

    # Populate the table
    def populate_table(self):
        self.AllComboBoxes = []
        self.comboBoxRows = {}

        # Table row information
        rowCountcur = self.tableWidget.currentRow()
        self.tableWidget.insertRow(rowCountcur+1)
        self.counter = rowCountcur + 1

        # General Data
        col1Data1 = ['a','b','c']
        col1Data2 = ['e','f','g']
        col1Data3 = ['x','y','z']

        # Create combobox
        colDataBox1 = self.comboBox_populator(col1Data1)
        colDataBox2 = self.comboBox_populator(col1Data2)
        colDataBox3 = self.comboBox_populator(col1Data3)
        self.AllComboBoxes = [colDataBox1, colDataBox2, colDataBox3]
        self.comboBoxRows.update({self.counter:self.AllComboBoxes})

        # Populate columns
        self.tableWidget.setCellWidget(self.counter,0,self.comboBoxRows[self.counter][0])
        # Populate vehicle list and cell, col 2
        self.tableWidget.setCellWidget(self.counter,1,self.comboBoxRows[self.counter][1])
        # Populate mission order list and cell, col 3
        self.tableWidget.setCellWidget(self.counter,2,self.comboBoxRows[self.counter][2])

        self.comboBoxRows[self.counter][0].currentTextChanged.connect(self.onComboChange)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = mainWindow()
    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Kevin_ALA
  • 233
  • 2
  • 11

1 Answers1

3

The problem in your case is that self.counter never changes since currentRow does not indicate the row number and in your case it is always -1 so self.counter will always be 0.

The key to the problem is to obtain the row of the QComboBox and to obtain it you must follow the following procedure:

  • Obtain combobox using sender() in the slot associated with the currentIndexChanged signal.

  • Obtain the position of the QComboBox topleft from the viewport() of the QTableWidget using mapTo() method.

  • Get row using the QModelIndex obtained by the indexAt() method.

On the other hand you can use itemData to store the options of the other combobox with respect to the initial combobox.

from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.m_tablewidget = QtWidgets.QTableWidget(0, 3)
        self.m_tablewidget.setHorizontalHeaderLabels(
            ["Col 1", "Col 2", "Col 3"]
        )
        self.m_button = QtWidgets.QPushButton("Add Row", clicked=self.onClicked)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(self.m_tablewidget)
        lay.addWidget(self.m_button, alignment=QtCore.Qt.AlignLeft)

    @QtCore.pyqtSlot()
    def onClicked(self):
        d = {
            "a": ["x", "y", "z"],
            "b": ["4", "5", "6"],
            "c": ["21", "22", "23"],
        }
        combobox1 = QtWidgets.QComboBox()
        for k, v in d.items():
            combobox1.addItem(k, v)
        combobox2 = QtWidgets.QComboBox()
        combobox2.addItems(combobox1.currentData())

        combobox3 = QtWidgets.QComboBox()
        combobox3.addItems(["e", "f", "g"])

        combobox1.currentIndexChanged.connect(self.onCurrentTextChanged)

        rc = self.m_tablewidget.rowCount()
        self.m_tablewidget.insertRow(rc)

        for i, combo in enumerate((combobox1, combobox2, combobox3)):
            self.m_tablewidget.setCellWidget(rc, i, combo)

    @QtCore.pyqtSlot()
    def onCurrentTextChanged(self):
        combobox1 = self.sender()
        if not isinstance(combobox1, QtWidgets.QComboBox):
            return
        p = combobox1.mapTo(self.m_tablewidget.viewport(), QtCore.QPoint())
        ix = self.m_tablewidget.indexAt(p)
        if not ix.isValid() or ix.column() != 0:
            return
        r = ix.row()
        data = combobox1.currentData()
        combobox3 = self.m_tablewidget.cellWidget(r, 2)
        if not isinstance(combobox3, QtWidgets.QComboBox):
            return
        combobox3.clear()
        combobox3.addItems(data)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I envy your programming skills. Thanks for the help. I would never have figured it out. Please let me know if you have any references to help me learn these tricks. – Kevin_ALA Jun 25 '19 at 16:34