我正在尝试在qtablewidget的Pyqt5中链接3个不同的组合框。前两个在一个插槽中链接,第三个在另一个插槽中使用不同的插槽链接到第二个组合框。在第一个组合框更改时,第二个组合框更改,从而使第三个组合框更改(类似于选车网站)。
当前问题是,在更改第一个组合框时,第二个信号也会执行,这使它执行两次,并给我字典键错误,因为第一次执行不包含键。尝试访问字典时,该错误发生在第81行。 在两次运行索引时查看该图像:
尝试
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox, QMainWindow, QApplication, QFileDialog
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)
self.vehicleHardware_dict = {'k': ['LiftSource_Wing_ChordConstantChordTapered', 'TPS_Active_Coolant'], 'X51': ['TPS_Passive_Tile', 'ThrustSource_Airbreathing_ScramjetTwoD']}
self.procesVeh_dict = {'k': ['Aerodynamics', 'Optimization', 'Propulsion', 'Weight_Balance'], 'X51': ['Aerodynamics', 'Optimization', 'Propulsion', 'Weight_Balance']}
self.processMethod_dict = {'Aerodynamics': ['kia', 'T1_case2_outNoIn'], 'Optimization': ['thomas'], 'Propulsion': ['test', 'rocket', 'T1_case3_InOutSame_inLess'], 'Weight_Balance': ['wing weight', 'T1_case1_inNoOut', 'T1_case3_inOutEq_inMore']}
self.methodInput_dict = {'T1_case1_inNoOut': ['T'], 'T1_case2_outNoIn': [], 'T1_case3_InOutSame_inLess': ['T'], 'T1_case3_inOutEq_inMore': ['THRUST_REF'], 'kia': ['ACS', 'AEXIT', 'AE_AT', 'AIP', 'AISP', 'AISP_AVAIL_V', 'AISP_EFF', 'AISP_EFF_V', 'THETA2_N'], 'rocket': ['AIP', 'AISP', 'AISP_AVAIL_V', 'AISP_EFF', 'AISP_EFF_V', 'AISP_HW', 'AISP_REF'], 'test': ['ACS', 'Y_V'], 'thomas': ['ACS', 'AEXIT', 'AE_AT', 'AIP', 'AISP', 'AISP_AVAIL_V', 'CS', 'DIA_BODY'], 'wing weight': ['A', 'ABASE', 'ACAP', 'ACAP_SPLN', 'ACS', 'AEXIT', 'AE_AT']}
@QtCore.pyqtSlot()
def onClicked(self):
combobox1_vehicle = QtWidgets.QComboBox()
combobox2_hardware = QtWidgets.QComboBox()
# combo_dummy = QtWidgets.QComboBox()
for k, v in self.processMethod_dict.items():
combobox1_vehicle.addItem(k, v)
for kk, vv in self.methodInput_dict.items():
combobox2_hardware.addItem(kk, vv)
combobox3 = QtWidgets.QComboBox()
combobox3.addItems(combobox2_hardware.currentData())
combobox1_vehicle.currentIndexChanged.connect(self.onCurrentTextChanged1)
combobox2_hardware.currentIndexChanged.connect(self.onCurrentTextChanged2)
rc = self.m_tablewidget.rowCount()
self.m_tablewidget.insertRow(rc)
for i, combo in enumerate((combobox1_vehicle, combobox2_hardware, combobox3)):
self.m_tablewidget.setCellWidget(rc, i, combo)
@QtCore.pyqtSlot()
def onCurrentTextChanged1(self):
combobox1_vehicle = self.sender()
if not isinstance(combobox1_vehicle, QtWidgets.QComboBox):
return
p = combobox1_vehicle.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_vehicle.currentData()
combobox2_hardware = self.m_tablewidget.cellWidget(r, 1)
if not isinstance(combobox2_hardware, QtWidgets.QComboBox):
return
combobox2_hardware.clear()
combobox2_hardware.addItems(data)
@QtCore.pyqtSlot()
def onCurrentTextChanged2(self):
combobox2_hardware = self.sender()
if not isinstance(combobox2_hardware, QtWidgets.QComboBox):
return
p = combobox2_hardware.mapTo(self.m_tablewidget.viewport(), QtCore.QPoint())
ix = self.m_tablewidget.indexAt(p)
if not ix.isValid() or ix.column() != 1:
return
r = ix.row()
# data = combobox2_hardware.currentData()
valueOfKey = combobox2_hardware.currentText()
print(combobox2_hardware)
print(p)
print(ix)
data = self.methodInput_dict[valueOfKey]
combobox3 = self.m_tablewidget.cellWidget(r, 2)
if not isinstance(combobox3, QtWidgets.QComboBox):
return
combobox3.clear()
if data == None:
combobox3.addItem("")
else:
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_())
答案 0 :(得分:2)
在信息很多的情况下,有必要寻找一种处理信息的数据结构。在这种情况下,您可以使用QAbstractItemModel
共享同一行的所有QComboBox,并更改显示的内容,您应该使用setRootModelIndex()
方法。在下面的示例中,我添加了QTreeView
,以便您可以看到模型的分布方式。
from PyQt5 import QtCore, QtGui, QtWidgets
d = {
"Aerodynamics": {
"kia": [
"ACS",
"AEXIT",
"AE_AT",
"AIP",
"AISP",
"AISP_AVAIL_V",
"AISP_EFF",
"AISP_EFF_V",
"THETA2_N",
],
"T1_case2_outNoIn": [],
},
"Optimization": {
"thomas": [
"ACS",
"AEXIT",
"AE_AT",
"AIP",
"AISP",
"AISP_AVAIL_V",
"CS",
"DIA_BODY",
]
},
"Propulsion": {
"test": ["ACS", "Y_V"],
"rocket": [
"AIP",
"AISP",
"AISP_AVAIL_V",
"AISP_EFF",
"AISP_EFF_V",
"AISP_HW",
"AISP_REF",
],
"T1_case3_InOutSame_inLess": ["T"],
},
"Weight_Balance": {
"wing weight": [
"A",
"ABASE",
"ACAP",
"ACAP_SPLN",
"ACS",
"AEXIT",
"AE_AT",
],
"T1_case1_inNoOut": ["T"],
"T1_case3_inOutEq_inMore": ["THRUST_REF"],
},
}
def dict_to_model(item, d):
if isinstance(d, dict):
for k, v in d.items():
it = QtGui.QStandardItem(k)
item.appendRow(it)
dict_to_model(it, v)
elif isinstance(d, list):
for v in d:
dict_to_model(item, v)
else:
item.appendRow(QtGui.QStandardItem(str(d)))
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)
self.m_treeview = QtWidgets.QTreeView()
model = QtGui.QStandardItemModel(self)
dict_to_model(model.invisibleRootItem(), d)
self.m_treeview.setModel(model)
self.m_treeview.expandAll()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QVBoxLayout(central_widget)
lay.addWidget(self.m_tablewidget)
lay.addWidget(self.m_treeview)
lay.addWidget(self.m_button, alignment=QtCore.Qt.AlignLeft)
@QtCore.pyqtSlot()
def onClicked(self):
rc = self.m_tablewidget.rowCount()
self.m_tablewidget.insertRow(rc)
model = QtGui.QStandardItemModel(self)
dict_to_model(model.invisibleRootItem(), d)
it = model.invisibleRootItem()
combos = []
for i in range(3):
combo = QtWidgets.QComboBox()
combo.setModel(model)
ix = model.indexFromItem(it)
combo.setRootModelIndex(ix)
combo.setCurrentIndex(0)
it = it.child(0)
self.m_tablewidget.setCellWidget(rc, i, combo)
combos.append(combo)
for combo in combos:
combo.currentIndexChanged[int].connect(self.onCurrentIndexChanged)
@QtCore.pyqtSlot(int)
def onCurrentIndexChanged(self, index):
combo = self.sender()
if not isinstance(combo, QtWidgets.QComboBox):
return
p = combo.mapTo(self.m_tablewidget.viewport(), QtCore.QPoint())
ix = self.m_tablewidget.indexAt(p)
if not ix.isValid():
return
r, c = ix.row(), ix.column()
if c == (self.m_tablewidget.columnCount() - 1):
return
model = combo.model()
combo2 = self.m_tablewidget.cellWidget(r, c + 1)
ix = combo.rootModelIndex()
child_ix = model.index(index, 0, ix)
combo2.setRootModelIndex(child_ix)
combo2.setCurrentIndex(0)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())