Python 在带有QStandardItemModel的QComboBox上使用QDataWidgetMapper
我试图通过映射器(QDataWidgetMapper)将数据从QTableModel链接到QComboBox,类似于此处显示的Qt示例: 使用propertyName“currentIndex”或“currentText”,我知道我可以直接映射组合框。但是我想映射一个用户定义的数据 下面是一个小例子:有一个名为CategoryID的对象,还有一个名为ID和Name的类别。combobox具有所有可能的类别,但其索引应根据对象的CategoryID进行更改 以下是我到目前为止所拥有的: 表格模型:Python 在带有QStandardItemModel的QComboBox上使用QDataWidgetMapper,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我试图通过映射器(QDataWidgetMapper)将数据从QTableModel链接到QComboBox,类似于此处显示的Qt示例: 使用propertyName“currentIndex”或“currentText”,我知道我可以直接映射组合框。但是我想映射一个用户定义的数据 下面是一个小例子:有一个名为CategoryID的对象,还有一个名为ID和Name的类别。combobox具有所有可能的类别,但其索引应根据对象的CategoryID进行更改 以下是我到目前为止所拥有的: 表格模型:
class ObjectModel(QAbstractTableModel):
def __init__(self, objects, parent=None):
super(ObjectModel, self).__init__(parent)
self.columns = ['name', 'category']
self.objectList = objects
def rowCount(self, parent=QModelIndex()):
return len(self.objectList)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columns[section].title()
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
row = self.objectList[index.row()]
column_key = self.columns[index.column()]
return row[column_key]
else:
return None
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self.objectList:
column_key = self.columns[index.column()]
self.objectList[index.row()][column_key] = value
self.dataChanged.emit(index, index, [])
return True
return True
class CategoryModel(QStandardItemModel):
def __init__(self, categories, parent=None):
super(CategoryModel, self).__init__(parent)
self.insertColumns(0, 2, QModelIndex())
self.insertRows(0, len(categories), QModelIndex())
self.categoryList = sorted(categories, key=lambda idx: (idx['name']))
for i, category in enumerate(categories):
self.setData(self.index(i, 0, QModelIndex()), category["id"], Qt.UserRole)
self.setData(self.index(i, 1, QModelIndex()), category["name"], Qt.UserRole)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
return self.categoryList[index.row()]['name']
if role == Qt.UserRole:
return self.categoryList[index.row()]["id"]
class CustomView(QWidget):
def __init__(self, parent=None):
super(CustomView, self).__init__(parent)
self.mapper = QDataWidgetMapper()
self.spinboxMapperIndex = QSpinBox()
self.lineEdit = QLineEdit()
self.comboBox = QComboBox()
self.spinboxMapperIndex.valueChanged.connect(self.changeMapperIndex)
self.setupLayout()
def setModel(self, model):
self.mapper.setModel(model)
self.mapper.addMapping(self.lineEdit, 0)
self.mapper.addMapping(self.comboBox, 1, b'currentData')
self.mapper.toFirst()
def changeMapperIndex(self, index):
self.mapper.setCurrentIndex(index)
def setupLayout(self):
layout = QVBoxLayout()
layout.addWidget(self.spinboxMapperIndex)
layout.addWidget(self.lineEdit)
layout.addWidget(self.comboBox)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
categoryList = [
{
"id": 23,
"name": "Flower"
},
{
"id": 456,
"name": "Furniture"
}
]
categoryModel = CategoryModel(categoryList)
objectList = [
{
"name": "Lotus",
"category": 23
},
{
"name": "Table",
"category": 456
}
]
objectModel = ObjectModel(objectList)
view = CustomView()
view.comboBox.setModel(categoryModel)
view.setModel(objectModel)
view.show()
sys.exit(app.exec_())
StandardItemModel:
class ObjectModel(QAbstractTableModel):
def __init__(self, objects, parent=None):
super(ObjectModel, self).__init__(parent)
self.columns = ['name', 'category']
self.objectList = objects
def rowCount(self, parent=QModelIndex()):
return len(self.objectList)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columns[section].title()
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
row = self.objectList[index.row()]
column_key = self.columns[index.column()]
return row[column_key]
else:
return None
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self.objectList:
column_key = self.columns[index.column()]
self.objectList[index.row()][column_key] = value
self.dataChanged.emit(index, index, [])
return True
return True
class CategoryModel(QStandardItemModel):
def __init__(self, categories, parent=None):
super(CategoryModel, self).__init__(parent)
self.insertColumns(0, 2, QModelIndex())
self.insertRows(0, len(categories), QModelIndex())
self.categoryList = sorted(categories, key=lambda idx: (idx['name']))
for i, category in enumerate(categories):
self.setData(self.index(i, 0, QModelIndex()), category["id"], Qt.UserRole)
self.setData(self.index(i, 1, QModelIndex()), category["name"], Qt.UserRole)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
return self.categoryList[index.row()]['name']
if role == Qt.UserRole:
return self.categoryList[index.row()]["id"]
class CustomView(QWidget):
def __init__(self, parent=None):
super(CustomView, self).__init__(parent)
self.mapper = QDataWidgetMapper()
self.spinboxMapperIndex = QSpinBox()
self.lineEdit = QLineEdit()
self.comboBox = QComboBox()
self.spinboxMapperIndex.valueChanged.connect(self.changeMapperIndex)
self.setupLayout()
def setModel(self, model):
self.mapper.setModel(model)
self.mapper.addMapping(self.lineEdit, 0)
self.mapper.addMapping(self.comboBox, 1, b'currentData')
self.mapper.toFirst()
def changeMapperIndex(self, index):
self.mapper.setCurrentIndex(index)
def setupLayout(self):
layout = QVBoxLayout()
layout.addWidget(self.spinboxMapperIndex)
layout.addWidget(self.lineEdit)
layout.addWidget(self.comboBox)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
categoryList = [
{
"id": 23,
"name": "Flower"
},
{
"id": 456,
"name": "Furniture"
}
]
categoryModel = CategoryModel(categoryList)
objectList = [
{
"name": "Lotus",
"category": 23
},
{
"name": "Table",
"category": 456
}
]
objectModel = ObjectModel(objectList)
view = CustomView()
view.comboBox.setModel(categoryModel)
view.setModel(objectModel)
view.show()
sys.exit(app.exec_())
查看:
class ObjectModel(QAbstractTableModel):
def __init__(self, objects, parent=None):
super(ObjectModel, self).__init__(parent)
self.columns = ['name', 'category']
self.objectList = objects
def rowCount(self, parent=QModelIndex()):
return len(self.objectList)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columns[section].title()
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
row = self.objectList[index.row()]
column_key = self.columns[index.column()]
return row[column_key]
else:
return None
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self.objectList:
column_key = self.columns[index.column()]
self.objectList[index.row()][column_key] = value
self.dataChanged.emit(index, index, [])
return True
return True
class CategoryModel(QStandardItemModel):
def __init__(self, categories, parent=None):
super(CategoryModel, self).__init__(parent)
self.insertColumns(0, 2, QModelIndex())
self.insertRows(0, len(categories), QModelIndex())
self.categoryList = sorted(categories, key=lambda idx: (idx['name']))
for i, category in enumerate(categories):
self.setData(self.index(i, 0, QModelIndex()), category["id"], Qt.UserRole)
self.setData(self.index(i, 1, QModelIndex()), category["name"], Qt.UserRole)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
return self.categoryList[index.row()]['name']
if role == Qt.UserRole:
return self.categoryList[index.row()]["id"]
class CustomView(QWidget):
def __init__(self, parent=None):
super(CustomView, self).__init__(parent)
self.mapper = QDataWidgetMapper()
self.spinboxMapperIndex = QSpinBox()
self.lineEdit = QLineEdit()
self.comboBox = QComboBox()
self.spinboxMapperIndex.valueChanged.connect(self.changeMapperIndex)
self.setupLayout()
def setModel(self, model):
self.mapper.setModel(model)
self.mapper.addMapping(self.lineEdit, 0)
self.mapper.addMapping(self.comboBox, 1, b'currentData')
self.mapper.toFirst()
def changeMapperIndex(self, index):
self.mapper.setCurrentIndex(index)
def setupLayout(self):
layout = QVBoxLayout()
layout.addWidget(self.spinboxMapperIndex)
layout.addWidget(self.lineEdit)
layout.addWidget(self.comboBox)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
categoryList = [
{
"id": 23,
"name": "Flower"
},
{
"id": 456,
"name": "Furniture"
}
]
categoryModel = CategoryModel(categoryList)
objectList = [
{
"name": "Lotus",
"category": 23
},
{
"name": "Table",
"category": 456
}
]
objectModel = ObjectModel(objectList)
view = CustomView()
view.comboBox.setModel(categoryModel)
view.setModel(objectModel)
view.show()
sys.exit(app.exec_())
Main:
class ObjectModel(QAbstractTableModel):
def __init__(self, objects, parent=None):
super(ObjectModel, self).__init__(parent)
self.columns = ['name', 'category']
self.objectList = objects
def rowCount(self, parent=QModelIndex()):
return len(self.objectList)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.columns[section].title()
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
row = self.objectList[index.row()]
column_key = self.columns[index.column()]
return row[column_key]
else:
return None
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
if self.objectList:
column_key = self.columns[index.column()]
self.objectList[index.row()][column_key] = value
self.dataChanged.emit(index, index, [])
return True
return True
class CategoryModel(QStandardItemModel):
def __init__(self, categories, parent=None):
super(CategoryModel, self).__init__(parent)
self.insertColumns(0, 2, QModelIndex())
self.insertRows(0, len(categories), QModelIndex())
self.categoryList = sorted(categories, key=lambda idx: (idx['name']))
for i, category in enumerate(categories):
self.setData(self.index(i, 0, QModelIndex()), category["id"], Qt.UserRole)
self.setData(self.index(i, 1, QModelIndex()), category["name"], Qt.UserRole)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole or role == Qt.EditRole:
return self.categoryList[index.row()]['name']
if role == Qt.UserRole:
return self.categoryList[index.row()]["id"]
class CustomView(QWidget):
def __init__(self, parent=None):
super(CustomView, self).__init__(parent)
self.mapper = QDataWidgetMapper()
self.spinboxMapperIndex = QSpinBox()
self.lineEdit = QLineEdit()
self.comboBox = QComboBox()
self.spinboxMapperIndex.valueChanged.connect(self.changeMapperIndex)
self.setupLayout()
def setModel(self, model):
self.mapper.setModel(model)
self.mapper.addMapping(self.lineEdit, 0)
self.mapper.addMapping(self.comboBox, 1, b'currentData')
self.mapper.toFirst()
def changeMapperIndex(self, index):
self.mapper.setCurrentIndex(index)
def setupLayout(self):
layout = QVBoxLayout()
layout.addWidget(self.spinboxMapperIndex)
layout.addWidget(self.lineEdit)
layout.addWidget(self.comboBox)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
categoryList = [
{
"id": 23,
"name": "Flower"
},
{
"id": 456,
"name": "Furniture"
}
]
categoryModel = CategoryModel(categoryList)
objectList = [
{
"name": "Lotus",
"category": 23
},
{
"name": "Table",
"category": 456
}
]
objectModel = ObjectModel(objectList)
view = CustomView()
view.comboBox.setModel(categoryModel)
view.setModel(objectModel)
view.show()
sys.exit(app.exec_())
如果我将ID更改为逻辑增量整数,并且在映射过程中使用currentIndex作为propertyName,则这是可行的。但是如果我更改类别列表中的顺序,我希望使用更通用的方法