可以做你想做的事。您需要为每个视图实现一个单独的 QAbstractProxyModel。组合框应过滤并仅保留第一列的非重复元素。另一个应该将第二行过滤到仅与组合框视图的当前状态相关的行。
如果你这样做了,在这个例子中,你最终会得到四个与模型相关的对象:你的数据(in Model.items)
、yourModel
和两个代理。
但我认为这根本不是一个好方法。这两个代理都很复杂,完全改变了原始模型的行、列结构。想象一下当模型第一列中的数据发生变化时,在每个代理中处理信号所需的复杂性。dataChanged
在实践中,我认为使用三个对象版本会更好:一个适当的(稍微详细说明的)数据类,然后是一对 QAbstractItemModels 共享该数据并且每个都专门用于它们支持的视图。可以将其想象为同一文件系统上的一对 QFileSystemModel。
必须将数据更改通知给两个 QAbstractItemModel,而您将无法享受由 Qt 框架自动实现的好处。但是,正如我上面指出的,在实践中,无论如何代理都不会轻易工作。
因此,这是一个基于您的代码的示例,并且更改尽可能少。请注意,我必须修复很多问题 - 您的导入不起作用,并且您的组合模型为某些角色返回了不正确的数据。
from PySide import QtGui, QtCore
import sys
class Data(object):
def __init__(self):
self.items = [['Pet', 'Dog'],['Pet', 'Cat'],['Bird','Eagle'],['Bird','Jay'],['Bird','Falcon']]
self.selectors = list({ k[0] for k in self.items})
def currentItems(self,select_on):
return [k[1] for k in self.items if k[0] == select_on]
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.data_obj = data
self.currentSelection = None
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.data_obj.currentItems(self.currentSelection))
def columnCount(self, parent=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or role != QtCore.Qt.DisplayRole: return
row=index.row()
return self.data_obj.currentItems(self.currentSelection)[row]
def setSelection(self,combo_row):
self.currentSelection = self.data_obj.selectors[combo_row]
self.layoutChanged.emit()
class ComboModel(QtCore.QAbstractListModel):
def __init__(self, data, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.data_obj = data
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.data_obj.selectors)
def data(self, index, role):
if not index.isValid() or role != QtCore.Qt.DisplayRole: return
row=index.row()
return self.data_obj.selectors[row]
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.data=Data()
self.tableModel = TableModel(self.data)
self.comboModel = ComboModel(self.data)
self.combo=QtGui.QComboBox()
self.combo.setModel(self.comboModel)
self.combo.activated.connect(self.tableModel.setSelection)
vLayout.addWidget(self.combo)
self.ViewA=QtGui.QTableView(self)
self.ViewA.setModel(self.tableModel)
self.ViewA.clicked.connect(self.viewClicked)
vLayout.addWidget(self.ViewA)
self.tableModel.setSelection(0)
def viewClicked(self, indexClicked):
print('indexClicked() row: %s column: %s'%(indexClicked.row(), indexClicked.column() ))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
但这是另一个更基于您的想法的版本,并且是我过去使用的模式。在这里,我们按照您的要求提供了一个模型,但提供了两个实际上都是 QAbstractItemModels 的接口。在这个例子中并没有什么不同,但是使单一模型的想法更加清晰。
第一个版本有一个由底层数据表示驱动的数据对象,因此可以非常干净和清晰。但它需要一个自定义的信号方法来向两个模型发出信号变化。
第二个版本有一个单一的集成模型对象,它封装了该信号。但在实际系统中,它可能仍需要连接到单独的数据对象——因此在实践中,此版本中可能有更多对象。
from PySide import QtGui, QtCore
import sys
class CombinedModel(object):
def __init__(self):
self.items = [['Pet', 'Dog'],['Pet', 'Cat'],['Bird','Eagle'],['Bird','Jay'],['Bird','Falcon']]
self.selectors = list({ k[0] for k in self.items})
self.table_if = TableModel(self)
self.combo_if = ComboModel(self)
self.currentSelection = None
def currentItems(self):
return [k[1] for k in self.items if k[0] == self.currentSelection]
def setSelection(self,combo_row):
self.currentSelection = self.selectors[combo_row]
self.table_if.layoutChanged.emit()
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, model, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.model = model
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.model.currentItems())
def columnCount(self, parent=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or role != QtCore.Qt.DisplayRole: return
row=index.row()
return self.model.currentItems()[row]
class ComboModel(QtCore.QAbstractListModel):
def __init__(self, model, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.model = model
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.model.selectors)
def data(self, index, role):
if not index.isValid() or role != QtCore.Qt.DisplayRole: return
row=index.row()
return self.model.selectors[row]
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
vLayout=QtGui.QVBoxLayout(self)
self.setLayout(vLayout)
self.model=CombinedModel()
self.combo=QtGui.QComboBox()
self.combo.setModel(self.model.combo_if)
self.combo.activated.connect(self.model.setSelection)
vLayout.addWidget(self.combo)
self.ViewA=QtGui.QTableView(self)
self.ViewA.setModel(self.model.table_if)
self.ViewA.clicked.connect(self.viewClicked)
vLayout.addWidget(self.ViewA)
self.model.setSelection(0)
def viewClicked(self, indexClicked):
print('indexClicked() row: %s column: %s'%(indexClicked.row(), indexClicked.column() ))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())