I found an example of using QAbstractItemModel with QTreeView that was written using PyQt4. I have adjusted the code for my need and used the PySide6. Majority of functionality is working apart of one – when I click the button with the name of the project it gives me an error:
...in but_clicked
name = dialog.sender().text()
^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'text'
Any suggection how can I correct it?
The full code is here:
from PySide6 import QtGui, QtCore
from PySide6.QtWidgets import QTreeView, QApplication, QDialog, QVBoxLayout, QLabel, QFrame, QHBoxLayout, QPushButton
import random
HORIZONTAL_HEADERS = ("Project", "Folder")
class PrjCollection(list):
def __init__(self, *args, **kwargs):
super(PrjCollection, self).__init__(*args, **kwargs)
def create_prj(self, *args, **kwargs):
p = Prj(*args, **kwargs)
self.append(p)
return p
class Prj(object):
def __init__(self, name, folder):
self.folder = folder
self.name = name
self.number = random.randint(0, 100)
def __repr__(self):
print(self.number)
return "PROJECT - %s %s" % (self.name, self.folder)
class TreeItem(object):
def __init__(self, project, header, parent_item):
self.project = project
self.parent_item = parent_item
self.header = header
self.children = []
def add_child(self, child):
self.children.append(child)
def child(self, row):
return self.children[row]
def child_count(self):
return len(self.children)
def column_count(self):
return 1
def data(self, column):
if self.project == None:
if column == 0:
# return QtCore.QVariant(self.header)
return self.header
if column == 1:
# return QtCore.QVariant("")
return ""
else:
if column == 0:
# return QtCore.QVariant(self.project.name)
return self.project.name
if column == 1:
# return QtCore.QVariant(self.project.folder)
return self.project.folder
# return QtCore.QVariant()
return None
def parent(self):
return self.parent_item
def row(self):
if self.parent_item:
return self.parent_item.children.index(self)
return 0
class TreeModel(QtCore.QAbstractItemModel):
def __init__(self, projects, parent=None):
super(TreeModel, self).__init__(parent)
self.projects = projects or []
self.root_item = TreeItem(None, "All", None)
self.parents = {0: self.root_item}
self.setup_model_data()
def columnCount(self, parent=None):
if parent and parent.isValid():
return parent.internalPointer().column_count()
else:
return 1
def data(self, index, role):
if not index.isValid():
# return QtCore.QVariant()
return None
item = index.internalPointer()
if role == QtCore.Qt.DisplayRole:
return item.data(index.column())
if role == QtCore.Qt.UserRole:
if item:
return item.project
# return QtCore.QVariant()
return None
def headerData(self, column, orientation, role):
if (orientation == QtCore.Qt.Horizontal and
role == QtCore.Qt.DisplayRole):
try:
# return QtCore.QVariant(HORIZONTAL_HEADERS[column])
return HORIZONTAL_HEADERS[column]
except IndexError:
pass
# return QtCore.QVariant()
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if not parent.isValid():
parentItem = self.root_item
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
childItem = index.internalPointer()
if not childItem:
return QtCore.QModelIndex()
parentItem = childItem.parent()
if parentItem == self.root_item:
return QtCore.QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.column() > 0:
return 0
if not parent.isValid():
p_Item = self.root_item
else:
p_Item = parent.internalPointer()
return p_Item.child_count()
def setup_model_data(self):
for project in self.projects:
folder = project.folder
if folder not in self.parents:
newparent = TreeItem(None, folder, self.root_item)
self.root_item.add_child(newparent)
self.parents[folder] = newparent
parentItem = self.parents[folder]
newItem = TreeItem(project, "", parentItem)
parentItem.add_child(newItem)
def searchModel(self, project):
def searchNode(node):
for child in node.children:
if project == child.project:
index = self.createIndex(child.row(), 0, child)
return index
if child.child_count() > 0:
result = searchNode(child)
if result:
return result
retarg = searchNode(self.parents[0])
return retarg
def find_GivenName(self, name):
app = None
for project in self.projects:
if project.name == name:
app = project
break
if app != None:
index = self.searchModel(app)
return (True, index)
return (False, None)
if __name__ == "__main__":
def but_clicked():
name = dialog.sender().text()
print("BUTTON CLICKED:", name)
result, index = model.find_GivenName(name)
if result:
if index:
tv.setCurrentIndex(index)
return
tv.clearSelection()
app = QApplication([])
prj_col = PrjCollection()
for name, folder in (("Project1", "Folder1"),
("Project2", "Folder1"), ("Project11", "Folder2")):
prj_col.create_prj(name, folder)
model = TreeModel(prj_col)
dialog = QDialog()
dialog.setMinimumSize(300, 150)
layout = QVBoxLayout(dialog)
tv = QTreeView(dialog)
tv.setModel(model)
tv.setAlternatingRowColors(True)
layout.addWidget(tv)
label = QLabel("Search for the following project")
layout.addWidget(label)
buts = []
frame = QFrame(dialog)
layout2 = QHBoxLayout(frame)
for project in model.projects:
but = QPushButton(project.name, frame)
buts.append(but)
layout2.addWidget(but)
but.clicked.connect(but_clicked)
layout.addWidget(frame)
dialog.exec()
app.closeAllWindows()
1