嗨,我正在为带有子对象的对象创建一个对话框,一个带有 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 文本框中键入内容时 TreeView 被过滤
#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());
一旦用户在 TreeView 中选择了一个项目(第 3 项,其中 Bar 已被选择)。代码应该获取所有选定的子项,将它们添加到模型中,最后展开选定的节点以显示所有子项(第 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
到目前为止,我已经完成了大部分工作。事实上这一切。除了 TreeView 的扩展之外,当有一些过滤时。
当没有应用过滤器时,我可以让它工作,但是一旦 TreeView 的列表被过滤,它就会有点偶然,即 TreeView 并不总是在正确的节点上展开。
如何确保 TreeView 在正确的索引处展开,以便在筛选文件夹列表并将文件添加到筛选列表时。如何确保 TreeView 扩展到正确的位置。我在 Windows 上使用 python 2.7,Qt 4.8。
最佳答案
问题不是它没有扩展,而是它受到 QSortProxyModel 过滤器的影响,该过滤器应该只应用于 topLevels。我使用了一个新角色,如果您已经有更多的 child ,则不会添加更多 child ,我也认为单击的信号最适合这种情况。
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
方法决定是否显示该行,在您的情况下,应该向顶层做出“Apple”、“Bee”等的决定。所以第一件事是来识别这些项目,主要特征是它们没有父级,因此我们访问 parent()
,如果它有效,则它有一个父级,如果它不是 topLevel,那么该方法必须通过过滤器并对其他过滤器返回 True,以便它们可见。
关于python - 源模型更改后更新 QFilterProxyModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48132313/