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