源模型更改后更新 QFilterProxyModel
updating QFilterProxyModel once the source model changes
您好,我正在为有子对象的对象创建一个对话框,一个带有用于过滤的 QlineEdit 的 QTreeview。当对话框最初出现时,它看起来像 (no.1)
代码如下所示。我只用重要的部分总结了它
#These are global so can be referenced from any function. and all set
#when i initialise my diaglog.
model=QtGui.QStandardItemModel()
treeview=QtGui.QTreeview()
proxymodel=QtGui.QSortFilterProxyModel(treeview)
treeview.setmodel(proxymodel)
proxymodel.setSourceModel(model)
def initialise_treeview(self):
#This builds the treeview with a list of root nodes only
root_nodes=["Apple","Ardvark","Ankle","Bee","Bark","Bar","Carrot"]# a list of root nodes
for objects in root_nodes:
item=QtGui.QStandardItem(objects)
model.appendRow(item)
No.2 显示当用户在 LineEdit 文本框中键入内容时被过滤的树视图
#When a user types into the search field the Treeview gets filtered via the proxymodel
QtCore.QObject.connect(LineEdit,QtCore.Signal("TextChanged(QString)")),update_filter)
def update_filter(self,text):
#filter the model based on the text in the qlineedit
proxymodel.setFilterRegExp(LineEdit.text());
一旦用户在树视图中选择了一个项目(第 3 条,其中已选择栏)。代码应该获取所有选中的子项,将它们添加到模型中,最后展开选中的节点以显示所有子项(第 4 个)
#update_treeview function is called to add children to the selected item
QtCore.QObject.connect(treeview.selectionModel(),QtCore.Signal("currentChanged(QModelIndex,QmodelIndex)")),update_treeview)
def update_treeview(self,currentindex,previousindex):
sourcemodel_index=proxymodel.mapToSource(currentindex)
parent_item=QtGui.QStandardItem()
#get the item from the source model
parent_item=model.itemFromIndex(sourcemodel_index)
for childitem in list_of_children:
file_item=QtGui.QStandardItem(str(childitem))
model.appendRow(file_item)
treeview.expand(currentindex) #this doesn't work when proxymodel has been filtered
到目前为止,我已经完成了大部分工作。其实都是。除了树视图的扩展,当有一些过滤。
我在没有应用过滤器的情况下工作,但是一旦树视图的列表被过滤,它就会有点碰运气,即树视图并不总是在正确的节点展开。
如何确保树视图在正确的索引处展开,以便在筛选文件夹列表并将文件添加到筛选列表时。我怎样才能确保树视图展开到正确的位置。我在 windows.
上使用 python 2.7,Qt 4.8
问题不是它不扩展,而是它受到QSortProxyModel过滤器的影响,过滤器应该只应用于topLevels。我已经使用了新的角色,不再添加更多children 如果你已经有了,我也认为点击信号最适合这种情况。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
HaveChildrenRole = Qt.UserRole
class SortFilterProxyModel(QSortFilterProxyModel):
def filterAcceptsRow(self, source_row, source_parent):
ix = self.sourceModel().index(source_row, 0, source_parent)
if not ix.parent().isValid(): # check if the item has no parent
return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
else: # as it has a parent, the filter does not apply
return True
class Widget(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.treeView = QTreeView(self)
self.le = QLineEdit(self)
self.layout().addWidget(self.treeView)
self.layout().addWidget(self.le)
self.model = QStandardItemModel(self)
self.proxy = SortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.treeView.setModel(self.proxy)
self.initialise_treeview()
self.le.textChanged.connect(self.update_filter)
self.treeView.clicked.connect(self.onClicked)
def initialise_treeview(self):
root_nodes = ["Apple", "Ardvark", "Ankle", "Bee", "Bark", "Bar", "Carrot"] # a list of root nodes
for obj in root_nodes:
item = QStandardItem(obj)
item.setData(False, HaveChildrenRole)
self.model.appendRow(item)
def update_filter(self, text):
self.proxy.setFilterRegExp(text)
def onClicked(self, ix):
s_ix = self.proxy.mapToSource(ix)
it = self.model.itemFromIndex(s_ix)
if not it.data(HaveChildrenRole) and it.parent() is None:
for children in ["A", "B", "C", "D"]:
it.appendRow(QStandardItem(children))
it.setData(True, HaveChildrenRole)
self.treeView.expand(ix)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
解释:
filterAcceptsRow
方法决定是否显示该行,在您的情况下,应该对 topLevel 做出 "Apple"、"Bee" 等决定。所以首先是识别这些项目,主要特征是它们没有 parent,因此我们访问 parent()
,如果它有效,则它有一个 parent,如果它不是topLevel,那么该方法必须通过过滤器,而对于其他方法,我们 return True 以便它们可见。
您好,我正在为有子对象的对象创建一个对话框,一个带有用于过滤的 QlineEdit 的 QTreeview。当对话框最初出现时,它看起来像 (no.1)
代码如下所示。我只用重要的部分总结了它
#These are global so can be referenced from any function. and all set
#when i initialise my diaglog.
model=QtGui.QStandardItemModel()
treeview=QtGui.QTreeview()
proxymodel=QtGui.QSortFilterProxyModel(treeview)
treeview.setmodel(proxymodel)
proxymodel.setSourceModel(model)
def initialise_treeview(self):
#This builds the treeview with a list of root nodes only
root_nodes=["Apple","Ardvark","Ankle","Bee","Bark","Bar","Carrot"]# a list of root nodes
for objects in root_nodes:
item=QtGui.QStandardItem(objects)
model.appendRow(item)
No.2 显示当用户在 LineEdit 文本框中键入内容时被过滤的树视图
#When a user types into the search field the Treeview gets filtered via the proxymodel
QtCore.QObject.connect(LineEdit,QtCore.Signal("TextChanged(QString)")),update_filter)
def update_filter(self,text):
#filter the model based on the text in the qlineedit
proxymodel.setFilterRegExp(LineEdit.text());
一旦用户在树视图中选择了一个项目(第 3 条,其中已选择栏)。代码应该获取所有选中的子项,将它们添加到模型中,最后展开选中的节点以显示所有子项(第 4 个)
#update_treeview function is called to add children to the selected item
QtCore.QObject.connect(treeview.selectionModel(),QtCore.Signal("currentChanged(QModelIndex,QmodelIndex)")),update_treeview)
def update_treeview(self,currentindex,previousindex):
sourcemodel_index=proxymodel.mapToSource(currentindex)
parent_item=QtGui.QStandardItem()
#get the item from the source model
parent_item=model.itemFromIndex(sourcemodel_index)
for childitem in list_of_children:
file_item=QtGui.QStandardItem(str(childitem))
model.appendRow(file_item)
treeview.expand(currentindex) #this doesn't work when proxymodel has been filtered
到目前为止,我已经完成了大部分工作。其实都是。除了树视图的扩展,当有一些过滤。
我在没有应用过滤器的情况下工作,但是一旦树视图的列表被过滤,它就会有点碰运气,即树视图并不总是在正确的节点展开。
如何确保树视图在正确的索引处展开,以便在筛选文件夹列表并将文件添加到筛选列表时。我怎样才能确保树视图展开到正确的位置。我在 windows.
上使用 python 2.7,Qt 4.8问题不是它不扩展,而是它受到QSortProxyModel过滤器的影响,过滤器应该只应用于topLevels。我已经使用了新的角色,不再添加更多children 如果你已经有了,我也认为点击信号最适合这种情况。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
HaveChildrenRole = Qt.UserRole
class SortFilterProxyModel(QSortFilterProxyModel):
def filterAcceptsRow(self, source_row, source_parent):
ix = self.sourceModel().index(source_row, 0, source_parent)
if not ix.parent().isValid(): # check if the item has no parent
return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
else: # as it has a parent, the filter does not apply
return True
class Widget(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
self.setLayout(QVBoxLayout())
self.treeView = QTreeView(self)
self.le = QLineEdit(self)
self.layout().addWidget(self.treeView)
self.layout().addWidget(self.le)
self.model = QStandardItemModel(self)
self.proxy = SortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.treeView.setModel(self.proxy)
self.initialise_treeview()
self.le.textChanged.connect(self.update_filter)
self.treeView.clicked.connect(self.onClicked)
def initialise_treeview(self):
root_nodes = ["Apple", "Ardvark", "Ankle", "Bee", "Bark", "Bar", "Carrot"] # a list of root nodes
for obj in root_nodes:
item = QStandardItem(obj)
item.setData(False, HaveChildrenRole)
self.model.appendRow(item)
def update_filter(self, text):
self.proxy.setFilterRegExp(text)
def onClicked(self, ix):
s_ix = self.proxy.mapToSource(ix)
it = self.model.itemFromIndex(s_ix)
if not it.data(HaveChildrenRole) and it.parent() is None:
for children in ["A", "B", "C", "D"]:
it.appendRow(QStandardItem(children))
it.setData(True, HaveChildrenRole)
self.treeView.expand(ix)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
解释:
filterAcceptsRow
方法决定是否显示该行,在您的情况下,应该对 topLevel 做出 "Apple"、"Bee" 等决定。所以首先是识别这些项目,主要特征是它们没有 parent,因此我们访问 parent()
,如果它有效,则它有一个 parent,如果它不是topLevel,那么该方法必须通过过滤器,而对于其他方法,我们 return True 以便它们可见。