如何同步共享同一模型的多个视图 [英] How to sync multiple views sharing same model
问题描述
左侧列表视图单击填充右侧表视图,其中包含与单击的项目相对应的项.问题在于,每次单击左侧视图时,右侧表视图项目列表都会不断增长.我可以继续从每个左侧视图 click s 上的所有项目中清除右侧视图:
A left-side-list-view click populates a right-side-table-view with the corresponding to a clicked item items. The problem is that a right-side-table-view items list keeps growing with every left-side-view click. I can go ahead and clear a right-side view from all the items on every left-side-view click s with:
for i in range(self.rowCount()):
self.beginRemoveRows(QtCore.QModelIndex(), i, i)
self.endRemoveRows()
但这需要一次又一次地重新创建右侧视图项目(即使对于那些之前已经创建(然后被删除)的点击项目也是如此.
But that would require re-creating the right-side-view items again and again (even for those clicked items that were already created earlier (and then deleted).
我想知道是否有一种方法可以只创建那些从未创建过的右侧视图项目.而不是在左侧视图单击时删除它们:隐藏它们以在稍后再次单击相应的左侧视图项时取消隐藏.
I wonder if there is a way to create only those right-side-view items that were never created. And instead of deleting them on a left-side-view click: hiding them to unhide later when a corresponding left-side-view item is clicked again.
请避免使用简短的非描述性短语或关键字.而是发布示例代码,清楚地显示如何实现.再一次,我们的目标是在右侧视图中显示仅包含使用左侧视图单击其类型的那些动物的列表.
Please avoid a short non-descriptive phrases or keywords. Instead post the example code showing clearly how it could be achieved. Once again, the goal is to display in a right-side view a list of only those animals whose type is clicked using a left side-view.
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None):
totalItems=self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
key=str(self.items[index.row()])
column=index.column()
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
if not column: return key
else:
print key, column, elements.get(key,{}).get(column)
return elements.get(key,{}).get(column)
def rebuildItems(self, index):
key=index.data(QtCore.Qt.UserRole).toString()
totalItems=self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(key)
self.endInsertRows()
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.dataModelB=TableModel()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(self.dataModelB)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
稍后
模型/代理设置的工作示例:
EDITED LATER:
Working example of model/proxy setup:
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{1:'Bison',2:'Panther',3:'Elephant'},'Birds':{1:'Duck',2:'Hawk',3:'Pigeon'},'Fish':{1:'Shark',2:'Salmon',3:'Piranha'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None):
totalItems=self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 4
def data(self, index, role):
key=str(self.items[index.row()])
column=index.column()
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if role==QtCore.Qt.DisplayRole:
if not column: return key
else: return elements.get(key,{}).get(column)
def rebuildItems(self, index):
key=index.data(QtCore.Qt.UserRole).toString()
if key in self.items: return
totalItems=self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(key)
self.endInsertRows()
class ProxyTableModel(QtGui.QSortFilterProxyModel):
def __init__(self, parent=None):
super(ProxyTableModel, self).__init__(parent)
def headerData(self, column, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.TextAlignmentRole:
if orientation == QtCore.Qt.Horizontal:
return QtCore.QVariant(int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter))
return QtCore.QVariant(int(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter))
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation==QtCore.Qt.Horizontal:
return QtCore.QVariant("Species %s"%column)
return QtCore.QVariant(int(column + 1))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
listModel=ListModel()
listModel.buildItems()
tableModel=TableModel()
proxyTableModel=ProxyTableModel()
proxyTableModel.setSourceModel(tableModel)
proxyTableModel.setFilterKeyColumn(0)
self.viewA=QtGui.QListView()
self.viewA.setModel(listModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QTableView()
self.viewB.setModel(proxyTableModel)
self.viewB.setColumnHidden(0,True)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().sourceModel().rebuildItems(index)
key=index.data().toString()
self.viewB.model().setFilterRegExp(key)
window=Window()
sys.exit(app.exec_())
编辑 #2
这是基于 mdurant 提出的建议的工作代码(非常感谢!).不使用 proxy 模型
(过滤右侧视图的显示内容),而是使用现有索引(为了让这个例子的事情更简单,我将右侧视图切换到 QListView).
Here is a working code based on the suggestions made by mdurant (many thanks!). Instead of using a proxy model
(to filter the display content of right-side-view) an existing index is used (to keep things for this example simpler I switched right-side-view to QListView).
import os,sys
from PyQt4 import QtCore, QtGui
app=QtGui.QApplication(sys.argv)
elements={'Animals':{0:'Bison',1:'Panther',2:'Elephant',3:'Dog'},'Birds':{0:'Duck',1:'Hawk',2:'Pigeon'},'Fish':{0:'Shark',1:'Salmon'}}
class ListModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
key=str(self.items[index.row()])
if role==QtCore.Qt.UserRole:
return key
if role==QtCore.Qt.DisplayRole:
return key
def addItem(self, key=None):
totalItems=self.rowCount()
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(str(key))
self.endInsertRows()
def buildItems(self):
for key in elements:
self.addItem(key)
class TableModel(QtCore.QAbstractTableModel):
def __init__(self):
QtCore.QAbstractTableModel.__init__(self)
self.key=None
self.items=[]
def rowCount(self, parent=QtCore.QModelIndex()):
if not self.items: return 0
else: return len(self.items)
def columnCount(self, index=QtCore.QModelIndex()):
return 2
def data(self, index, role):
if not index.isValid() or not (0<=index.row()<len(self.items)): return QtCore.QVariant()
if not self.key: return QtCore.QVariant()
row=index.row()
if role==QtCore.Qt.DisplayRole:
return elements.get(self.key,{}).get(row)
def rebuildItems(self, index):
self.key=str(index.data(QtCore.Qt.UserRole).toString())
self.items=elements[self.key].keys()
self.reset()
self.dataChanged.emit(self.index(1,1), self.index(1,4))
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
mainLayout=QtGui.QHBoxLayout()
self.setLayout(mainLayout)
self.dataModel=ListModel()
self.dataModel.buildItems()
self.viewA=QtGui.QListView()
self.viewA.setModel(self.dataModel)
self.viewA.clicked.connect(self.onClick)
self.viewB=QtGui.QListView()
self.dataModelB=TableModel()
self.viewB.setModel(self.dataModelB)
# self.viewB.setColumnHidden(0,True)
mainLayout.addWidget(self.viewA)
mainLayout.addWidget(self.viewB)
self.show()
def onClick(self, index):
self.viewB.model().rebuildItems(index)
window=Window()
sys.exit(app.exec_())
推荐答案
这符合您的要求,只要不重复插入:
This does what you asked, as far as not repeating insertions:
def rebuildItems(self, index):
key=index.data(QtCore.Qt.UserRole)
totalItems=self.rowCount()
if not key in self.items:
self.beginInsertRows(QtCore.QModelIndex(), totalItems, totalItems)
self.items.append(key)
self.endInsertRows()
但是,对于隐藏项目,这是由视图(或代理模型)完成的,而不是模型本身.
However, for hiding items, that is something done by the view (or a proxy model), not the model itself.
这篇关于如何同步共享同一模型的多个视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!