如何同步共享相同模型的多个视图

时间:2014-09-26 19:35:52

标签: python qt pyqt

左侧列表视图单击会使用与所单击项目项对应的右侧表视图填充。问题是右侧表视图项列表随着每个左侧视图单击而不断增长。 我可以继续清除每个左侧视图点击s上所有项目的右侧视图:

for i in range(self.rowCount()):
    self.beginRemoveRows(QtCore.QModelIndex(), i, i)
    self.endRemoveRows()

但这需要一次又一次地重新创建右侧视图项(即使是那些之前已经创建(然后删除)的项目。

我想知道是否有办法只创建那些从未创建的右侧视图项。而不是在左侧视图上单击删除它们:隐藏它们以便稍后在再次单击相应的左侧视图项时取消隐藏。

请避免使用简短的非描述性短语或关键字。而是发布示例代码,清楚地显示它是如何实现的。再次,目标是在右侧视图中显示仅使用左侧视图单击其类型的动物的列表。

enter image description here

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

以后编辑:

模型/代理设置的工作示例:

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

enter image description here

以下是基于 mdurant 提出的建议的工作代码(非常感谢!)。不使用proxy model(过滤右侧视图的显示内容)而是使用现有索引(为了使本示例的内容更简单,我将右侧视图切换到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_())

2 个答案:

答案 0 :(得分:2)

现在有单行。

,当我没有选择任何内容时,可以隐藏此行
class TableModel(QtCore.QAbstractTableModel):

    sel = None

    def __init__(self):
        QtCore.QAbstractTableModel.__init__(self)
        self.items=[]    
    def rowCount(self, parent=QtCore.QModelIndex()):
        return 1
    def columnCount(self, index=QtCore.QModelIndex()):
        return 4
    def data(self, index, role):
        if not index.isValid() or not (0<=index.row()<len(self.items)): return 
        key=self.sel
        column=index.column()
        if role==QtCore.Qt.DisplayRole:
            if not column:  return str(key)
            else:
                return elements.get(key,{}).get(column) if (self.sel is not None) else QtCore.QVariant()

    def rebuildItems(self, index):
        key=index.data(QtCore.Qt.UserRole)
        if not key in self.items:
            self.items.append(key)
        self.sel = key
        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.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)

答案 1 :(得分:1)

这就是你所要求的,只要不重复插入:

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

但是,对于隐藏项目,这是由视图(或代理模型)完成的,而不是模型本身。