collect all items in QTreeview recursively - python

How can I collect all Qtreeview items so i can then iterate over them and apply necessary changes like display text updates, or color changes?
Is there an easy way to collect all of them using the 'match' method?
def get_checked(self):
model = self.treeview.model()
checked = model.match(
model.index(0, 0), QtCore.Qt.CheckStateRole,
QtCore.Qt.Checked, -1,
QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
for index in checked:
item = model.itemFromIndex(index)
print(item.text())
test code:
from PySide import QtGui, QtCore
from PySide import QtSvg, QtXml
import sys
class Person:
def __init__(self, name="", children=None):
self.name = name
self.children = children if children else []
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.resize(300, 400)
self.init_ui()
def init_ui(self):
# Setup Tabs Widget
# self.treeview = QtGui.QTreeView()
self.treeview = QtGui.QTreeView()
self.treeview.setHeaderHidden(True)
self.treeview.setUniformRowHeights(True)
self.treeview.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.model = QtGui.QStandardItemModel()
self.treeview.setModel(self.model)
self.action = QtGui.QAction('Print', self)
self.action.setShortcut('F5')
self.action.triggered.connect(self.get_checked)
fileMenu = QtGui.QMenu("&File", self)
fileMenu.addAction(self.action)
self.menuBar().addMenu(fileMenu)
# Setup central widget
self.setCentralWidget(self.treeview)
# populate data
self.populate_people()
self.treeview.expandAll()
def populate_people(self):
parent = Person("Kevin", [
Person("Tom", [Person("Sally"), Person("Susan")]),
Person("Snappy", [Person("John"), Person("Kimmy"),
Person("Joe")]),
Person("Chester", [Person("Danny"), Person("Colleen")])
]
)
self.create_nodes(parent, self.model)
def create_nodes(self, node, parent):
tnode = QtGui.QStandardItem()
tnode.setCheckable(True)
tnode.setData(QtCore.Qt.Unchecked, role=QtCore.Qt.CheckStateRole)
tnode.setData(node.name , role=QtCore.Qt.DisplayRole)
tnode.setData(node, role=QtCore.Qt.UserRole) # store object on item
parent.appendRow(tnode)
for x in node.children:
self.create_nodes(x, tnode)
def get_checked(self):
print "collecting..."
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Here is a recursive solution (requires Python >= 3.3):
def iterItems(self, root):
def recurse(parent):
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
yield from recurse(child)
if root is not None:
yield from recurse(root)
Alternative recursive solution (for Python2/Python3):
def iterItems(self, root):
def recurse(parent):
if root is not None:
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
for item in recurse(child):
yield item
return recurse(root)
And here is an iterative solution (for Python2/Python3):
def iterItems(self, root):
if root is not None:
stack = [root]
while stack:
parent = stack.pop(0)
for row in range(parent.rowCount()):
for column in range(parent.columnCount()):
child = parent.child(row, column)
yield child
if child.hasChildren():
stack.append(child)
(NB: this solution gives a more predictable ordering, and is a little faster)
Usage:
root = self.treeview.model().invisibleRootItem()
for item in self.iterItems(root):
print(item.text())
The root argument can be any item in a QStandardItemModel.

Related

How to add a menu only in the QTreeWidgetItem after pressing the right click? [duplicate]

I have the following code to create a QTreeWidget and a contextmenu with 2 actions.
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(['Name', 'Cost ($)'])
cg = QtWidgets.QTreeWidgetItem(['carrots', '0.99'])
c1 = QtWidgets.QTreeWidgetItem(['carrot', '0.33'])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
def eventFilter(self, source: QtWidgets.QTreeWidget, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.tw):
menu = QtWidgets.QMenu()
AAction = QtWidgets.QAction("AAAAA")
AAction.triggered.connect(lambda :self.a(source.itemAt(event.pos())))
BAction = QtWidgets.QAction("BBBBBB")
BAction.triggered.connect(lambda :self.b(source, event))
menu.addAction(AAction)
menu.addAction(BAction)
menu.exec_(event.globalPos())
return True
return super(Dialog, self).eventFilter(source, event)
def a(self, item):
if item is None:
return
print("A: {}".format([item.text(i) for i in range(self.tw.columnCount())]))
def b(self, source, event):
item = source.itemAt(event.pos())
if item is None:
return
print("B: {}".format([item.text(i) for i in range(source.columnCount())]))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
When opening the contextmenu in the header and clicking on one of the actions it prints either carrot or carrots, depending on where in the contextmenu I click. But I give the position of right click event to the functions.
So why is this happening and what can I do to stop it?
Your code has 2 errors:
The main error is that the itemAt() method uses the coordinates with respect to the viewport() and not with respect to the view (the QTreeWidget) so you will get incorrect items (the header occupies a space making the positions with respect to the QTreeWidget and the viewport() have an offset).
You should not block the eventloop, for example blocking the eventFilter you may be blocking other events that would cause errors that are difficult to debug, in this case it is better to use a signal.
class Dialog(QtWidgets.QDialog):
rightClicked = QtCore.pyqtSignal(QtCore.QPoint)
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(["Name", "Cost ($)"])
cg = QtWidgets.QTreeWidgetItem(["carrots", "0.99"])
c1 = QtWidgets.QTreeWidgetItem(["carrot", "0.33"])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.viewport().installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
self.rightClicked.connect(self.handle_rightClicked)
def eventFilter(self, source: QtWidgets.QTreeWidget, event):
if event.type() == QtCore.QEvent.ContextMenu and source is self.tw.viewport():
self.rightClicked.emit(event.pos())
return True
return super(Dialog, self).eventFilter(source, event)
def handle_rightClicked(self, pos):
item = self.tw.itemAt(pos)
if item is None:
return
menu = QtWidgets.QMenu()
print_action = QtWidgets.QAction("Print")
print_action.triggered.connect(lambda checked, item=item: self.print_item(item))
menu.addAction(print_action)
menu.exec_(self.tw.viewport().mapToGlobal(pos))
def print_item(self, item):
if item is None:
return
texts = []
for i in range(item.columnCount()):
text = item.text(i)
texts.append(text)
print("B: {}".format(",".join(texts)))
Although it is unnecessary that you use an eventFilter to handle the contextmenu since a simpler solution is to set the contextMenuPolicy of the QTreeWidget to Qt::CustomContextMenu and use the customContextMenuRequested signal:
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.tw = QtWidgets.QTreeWidget()
self.tw.setHeaderLabels(["Name", "Cost ($)"])
cg = QtWidgets.QTreeWidgetItem(["carrots", "0.99"])
c1 = QtWidgets.QTreeWidgetItem(["carrot", "0.33"])
self.tw.addTopLevelItem(cg)
self.tw.addTopLevelItem(c1)
self.tw.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tw.customContextMenuRequested.connect(self.handle_rightClicked)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tw)
def handle_rightClicked(self, pos):
item = self.tw.itemAt(pos)
if item is None:
return
menu = QtWidgets.QMenu()
print_action = QtWidgets.QAction("Print")
print_action.triggered.connect(lambda checked, item=item: self.print_item(item))
menu.addAction(print_action)
menu.exec_(self.tw.viewport().mapToGlobal(pos))
def print_item(self, item):
if item is None:
return
texts = []
for i in range(item.columnCount()):
text = item.text(i)
texts.append(text)
print("B: {}".format(",".join(texts)))

How to get model index children in QSortFilterProxyModel of QFileSystemModel?

I have a file system folder with wollowing structure on a Hard disk:
So, I want to see the the folliwing structure in my QTreeView:
I try to use QSortFilterProxy model to do that.
My strategy:
identify 'Folder_1' item in filterAcceptsRow and decline insertion of 'Folder_1' and its children
recursively get children of 'Folder_1' (because it can has another folders)
insert children instead of 'Folder_1'
So, I stuck on step 2.
Is my strategy right?
How to get children of parent item in filterAcceptsRow ?
Do I have to use another method to do that?
Where (instance and method) I should do children insertion (step 3)?
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSortFilterProxyModel
class MyFilterModel(QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(MyFilterModel, self).__init__(*args, **kwargs)
def filterAcceptsRow(self, sourceRow, sourceParent):
index = self.sourceModel().index(sourceRow, 0, sourceParent)
print('data =', index.data())
if index.data() == 'Folder_1':
child_index = self.sourceModel().index(sourceRow+1, 0, sourceParent)
print(child_index.data())
rowCount = self.sourceModel().rowCount(index)
accepted = QSortFilterProxyModel.filterAcceptsRow(self, sourceRow,
sourceParent)
if rowCount > 0 and not accepted:
for row in range(rowCount):
if self.filterAcceptsRow(row, index):
return True
return accepted
class Myview(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self)
self._root_path = r"C:\Users\Dmitriy.Kubarev\Documents\TEST_FILE_SYSTEM"
model = QtWidgets.QFileSystemModel()
sourceIndex = model.setRootPath(self._root_path)
proxy_model = MyFilterModel()
proxy_model.setSourceModel(model)
view = QtWidgets.QTreeView()
view.setModel(proxy_model)
central_widget = QtWidgets.QWidget()
main_layout = QtWidgets.QVBoxLayout()
button = QtWidgets.QPushButton('ok')
main_layout.addWidget(button)
main_layout.addWidget(view)
central_widget.setLayout(main_layout)
proxyIndex = proxy_model.mapFromSource(sourceIndex)
view.setRootIndex(proxyIndex)
self.setCentralWidget(central_widget)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
myview = Myview()
myview.show()
sys.exit(app.exec_())

Assigning values of a signal to a variable

I'm new to signal and slots in python and currently designing a GUI with Pyqt5. User requires to select from a mix of qcombobox where each element is a qmenu. I'm trying to store the selection of the path user is taking using signals.
Image of selection GUI
Attempt:
Using the pathChanged in a class as:
pathChanged = QtCore.pyqtSignal(list)
and later in the init print the selected path with:
combo.pathChanged.connect(print)
But this would not save the value of my path to a variable but just showing it on the console. If I equate the above to a variable, then I just receive the memory location.
How can I store the selections in a list and the list gets appended after each user selection?
Trying to implement the idea from the original code: https://stackoverflow.com/a/52723148/6942881
And my code is:
from PyQt5 import QtCore, QtWidgets
data = {'Concept': {
"Aircraft":{
"Blended Wing":[],
"Lifting Body":["Flat Bottom","Round Bottom","Wing"],
"Wing Body":["Fixed","Rotary","Swept"]},
"Launch Vehicle":{
"SSTO":["Expendable","Reusable","Partially Reusable"],
"TSTO":["Expendable","Reusable","Partially Reusable"],
"MSTO":["Expendable","Reusable","Partially Reusable"]}
}
}
class ComboBoxExpandable(QtWidgets.QPushButton):
currentTextChanged = QtCore.pyqtSignal(str)
pathChanged = QtCore.pyqtSignal(list)
def setData(self, value):
menu = QtWidgets.QMenu(self)
self.setMenu(menu)
self.append_element(value, menu)
menu.triggered.connect(self.on_triggered)
def printer(self,path):
# print(path)
return path
#QtCore.pyqtSlot(QtWidgets.QAction)
def on_triggered(self, action):
self.setText(action.text())
path = [action.text()]
w = action.parentWidget()
while w.parentWidget() and isinstance(w.parentWidget(), QtWidgets.QMenu):
path.insert(0, w.title())
w = w.parentWidget()
self.pathChanged.emit(path)
self.currentTextChanged.emit(self.text())
self.printer(path)
#staticmethod
def append_element(value, menu):
if isinstance(value, list):
for e in value:
ComboBoxExpandable.append_element(e, menu)
elif isinstance(value, dict):
for k, v in value.items():
if v==[]:
menu.addAction(k)
else:
ComboBoxExpandable.append_element(v, menu.addMenu(k))
else:
menu.addAction(value)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
combo = ComboBoxExpandable()
combo.setData(data)
result_label = QtWidgets.QLabel()
combo.currentTextChanged.connect(result_label.setText)
combo.pathChanged.connect(print)
lay = QtWidgets.QFormLayout(self)
lay.addRow("Select Concept: ", combo)
lay.addRow("Concept Selected: ", result_label)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
The solution is to create a slot connected to that signal where the list that is transported through the signal is added to a member of the class:
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self._paths = [] # <---container
combo = ComboBoxExpandable()
combo.setData(data)
result_label = QtWidgets.QLabel()
combo.currentTextChanged.connect(result_label.setText)
combo.pathChanged.connect(self.on_pathChanged)
lay = QtWidgets.QFormLayout(self)
lay.addRow("Select Concept: ", combo)
lay.addRow("Concept Selected: ", result_label)
#QtCore.pyqtSlot(list)
def on_pathChanged(self, path):
self._paths.append(path) # append path
print(self._paths)

How to add QTreeView in a QTableView column

I am fairly new to PyQt, I'm working on a project that contains a QTableView, with one of its columns displaying system paths. I would like to add a QTreeView so users can click the + or > buttons to expand what is underneath the paths.
Here is my basic implementation:
from PyQt4 import QtGui
from PyQt4 import QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.resize(600,400)
self.setWindowTitle("My Basic Treeview")
self.treeview = QtGui.QTreeView(self)
self.treeview.model = QtGui.QFileSystemModel()
self.treeview.model.setRootPath('/opt')
self.treeview.setModel(self.treeview.model)
self.treeview.setColumnWidth(0, 200)
self.setCentralWidget(self.treeview)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Although, in the above case, I get all folders but I just want the /opt path and its underneath folders.
import operator
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MyWindow(QWidget):
def __init__(self, data_list, header, *args):
QWidget.__init__(self, *args)
# setGeometry(x_pos, y_pos, width, height)
self.setGeometry(300, 200, 570, 450)
self.setWindowTitle("Click on column title to sort")
table_model = MyTableModel(self, data_list, header)
table_view = QTableView()
table_view.setModel(table_model)
# set font
font = QFont("Courier New", 14)
table_view.setFont(font)
# set column width to fit contents (set font first!)
table_view.resizeColumnsToContents()
# enable sorting
table_view.setSortingEnabled(True)
layout = QVBoxLayout(self)
layout.addWidget(table_view)
self.setLayout(layout)
class MyTableModel(QAbstractTableModel):
def __init__(self, parent, mylist, header, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.mylist = mylist
self.header = header
def rowCount(self, parent):
return len(self.mylist)
def columnCount(self, parent):
return len(self.mylist[0])
def data(self, index, role):
if not index.isValid():
return None
elif role != Qt.DisplayRole:
return None
return self.mylist[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.header[col]
return None
# the solvent data ...
header = ['Name', ' Email', ' Status', ' Path']
# use numbers for numeric data to sort properly
data_list = [
('option_A', 'zyro#email.com', 'Not Copied', '/Opt'),
('option_B', 'zyro#email.com', 'Not Copied', '/Users'),
]
app = QApplication([])
win = MyWindow(data_list, header)
win.show()
app.exec_()
Visual example :
I think your question can be divided in two parts:
how, in a QTreeView, the /opt path and its children can be shown, but without showing its siblings. In other words, how is it possible to show the root directory in a QTreeView ;
how can a QTreeView be added to a QTableView.
1. How to include the root directory in a QTreeView :
The root of a QTreeView is the directory for which the content is shown in the view. It is set when calling the method setRootIndex. According to a post by wysota on Qt Centre:
You can't display the invisibleRootItem because it is a fake item used only to have an equivalent of empty QModelIndex.
A workaround would be to set the root directory to the parent of /opt and filtering out the siblings of /opt with a subclass of a QSortFilterProxyModel. Note that I've also reimplemented the sizeHint method which will be necessary for the resizing of the rows of the QTableView:
from PyQt4 import QtGui, QtCore
import os
class MyQTreeView(QtGui.QTreeView):
def __init__(self, path, parent=None):
super(MyQTreeView, self).__init__(parent)
ppath = os.path.dirname(path) # parent of path
self.setFrameStyle(0)
#---- File System Model ----
sourceModel = QtGui.QFileSystemModel()
sourceModel.setRootPath(ppath)
#---- Filter Proxy Model ----
proxyModel = MyQSortFilterProxyModel(path)
proxyModel.setSourceModel(sourceModel)
#---- Filter Proxy Model ----
self.setModel(proxyModel)
self.setHeaderHidden(True)
self.setRootIndex(proxyModel.mapFromSource(sourceModel.index(ppath)))
#--- Hide All Header Sections Except First ----
header = self.header()
for sec in range(1, header.count()):
header.setSectionHidden(sec, True)
def sizeHint(self):
baseSize = super(MyQTreeView,self).sizeHint()
#---- get model index of "path" ----
qindx = self.rootIndex().child(0, 0)
if self.isExpanded(qindx): # default baseSize height will be used
pass
else: # shrink baseShize height to the height of the row
baseSize.setHeight(self.rowHeight(qindx))
return baseSize
class MyQSortFilterProxyModel(QtGui.QSortFilterProxyModel):
def __init__(self, path, parent=None):
super(MyQSortFilterProxyModel, self).__init__(parent)
self.path = path
def filterAcceptsRow(self, row, parent):
model = self.sourceModel()
path_dta = model.index(self.path).data()
ppath_dta = model.index(os.path.dirname(self.path)).data()
if parent.data() == ppath_dta:
if parent.child(row, 0).data() == path_dta:
return True
else:
return False
else:
return True
2. How to add a *QTreeView* to a *QTableView* :
It is possible to add a QTreeView to a QTableView by using a QItemDelegate. The post by Pavel Strakhov greatly helped me for this, since I had never used QTableView in combination with delegates before answering to this question. I always used QTableWidget instead with the setCellWidget method.
Note that I've setup a signal in the MyDelegate class which call the method resizeRowsToContents in the MyTableView class. This way, the height of the rows resize according the the reimplementation of the sizeHint method of the MyQTreeView class.
class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, parent, mylist, header, *args):
super(MyTableModel, self).__init__(parent, *args)
self.mylist = mylist
self.header = header
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.mylist)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.mylist[0])
def data(self, index, role):
if not index.isValid():
return None
elif role != QtCore.Qt.DisplayRole:
return None
return self.mylist[index.row()][index.column()]
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.header[col]
return None
class MyDelegate(QtGui.QItemDelegate):
treeViewHeightChanged = QtCore.pyqtSignal(QtGui.QWidget)
def createEditor(self, parent, option, index):
editor = MyQTreeView(index.data(), parent)
editor.collapsed.connect(self.sizeChanged)
editor.expanded.connect(self.sizeChanged)
return editor
def sizeChanged(self):
self.treeViewHeightChanged.emit(self.sender())
class MyTableView(QtGui.QTableView):
def __init__(self, data_list, header, *args):
super(MyTableView, self).__init__(*args)
#---- set up model ----
model = MyTableModel(self, data_list, header)
self.setModel(model)
#---- set up delegate in last column ----
delegate = MyDelegate()
self.setItemDelegateForColumn(3, delegate)
for row in range(model.rowCount()):
self.openPersistentEditor(model.index(row, 3))
#---- set up font and resize calls ----
self.setFont(QtGui.QFont("Courier New", 14))
self.resizeColumnsToContents()
delegate.treeViewHeightChanged.connect(self.resizeRowsToContents)
3. Basic application :
Here is a basic application based on the code you provided in your OP:
if __name__ == '__main__':
header = ['Name', ' Email', ' Status', ' Path']
data_list = [('option_A', 'zyro#email.com', 'Not Copied', '/opt'),
('option_B', 'zyro#email.com', 'Not Copied', '/usr')]
app = QtGui.QApplication([])
win = MyTableView(data_list, header)
win.setGeometry(300, 200, 570, 450)
win.show()
app.exec_()
Which results in:

Comparing QTreeView/QAbstractItemModel to QTreeWidget

I'm building a tool in PySide for Maya (3D software) that auto versions and saves files in a directory.
I've spent the past few days trying to convert my initial QTreeWidget code into a model/view pattern with QTreeView and QAbstractItemModel to get tool tips and other functions, but I'm finding it harder than anticipated. When I'm learning a new coding language/technique I like to find two scripts that do the same thing- one with the new technique and one with the old technique. This way I can compare and breakdown what the new code is doing.
My big obstacle is that I'm having trouble finding a QTreeView sample that does what my QTreeWidget sample does. Also, most examples manually populate the QTreeView which doesn't help me much either. It would be great if someone could modify the QTreeView code so it does what my QTreeWidget code does. Comments on best practices for QTreeView would be great as well!
My QTreeWidget code currently...
1) gets a list of strings from a source and lists them in the first column
2) gets the date from each string and places it in the second column
QTreeView code:
from PySide import QtCore, QtGui
from shiboken import wrapInstance
import maya.OpenMayaUI as mui
import sys, os
def get_parent():
ptr = mui.MQtUtil.mainWindow()
return wrapInstance( long( ptr ), QtGui.QWidget )
################################################################################
class MyTree(QtGui.QMainWindow):
def __init__(self, parent=get_parent() ):
super(MyTree, self).__init__(parent)
data = MyData.init()
frame = QtGui.QFrame();
frame.setLayout( QtGui.QHBoxLayout() );
treeViewModel = TreeViewModel(data)
treeView = Widget_TreeView(treeViewModel)
frame.layout().addWidget( treeView );
self.setCentralWidget(frame)
################################################################################
class MyData():
def __init__(self, txt, parent=None):
self.txt = txt
self.tooltip = None
self.parent = parent
self.child = []
self.icon = []
self.index = None
self.widget = None
#---------------------------------------------------------------------------
# test initialization
#staticmethod
def init():
root = MyData("root")
root.tooltip = "root tooltip"
for i in range(0, 2):
child1 = MyData("child %i" % (i), root)
child1.tooltip = "child1 tooltip"
root.child.append(child1)
for x in range(0, 2):
child2 = MyData("child %i %i" % (i, x), child1)
child2.tooltip = "child2 tooltip"
child1.child.append(child2)
return root
# my failed attempt at adding my own data.
'''
path = "C:\Program Files"
contents = os.listdir( path )
data_list = []
for item in contents:
_data = MyData(item)
_data.tooltip = "_data tooltip"
data_list.append(_data)
return data_list # [0] adding this adds the first item to the UI,
# but i need every item from the directory
'''
################################################################################
class TreeViewModel(QtCore.QAbstractItemModel):
#---------------------------------------------------------------------------
def __init__(self, tree):
super(TreeViewModel, self).__init__()
self.__tree = tree
self.__view = None
#---------------------------------------------------------------------------
def flags(self, index):
flag = QtCore.Qt.ItemIsEnabled
if index.isValid():
flag |= QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
return flag
#---------------------------------------------------------------------------
def index(self, row, column, parent=QtCore.QModelIndex()):
node = QtCore.QModelIndex()
if parent.isValid():
nodeS = parent.internalPointer()
nodeX = nodeS.child[row]
node = self.__createIndex(row, column, nodeX)
else:
node = self.__createIndex(row, column, self.__tree)
return node
#---------------------------------------------------------------------------
def parent(self, index):
return QtCore.QModelIndex()
#---------------------------------------------------------------------------
def rowCount(self, index=QtCore.QModelIndex()):
count = 1
node = index.internalPointer()
if node is not None:
count = len(node.child)
return count
#---------------------------------------------------------------------------
def columnCount(self, index=QtCore.QModelIndex()):
return 2
#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
data = None
return data
#---------------------------------------------------------------------------
def setView(self, view):
self.__view = view
#---------------------------------------------------------------------------
def __createIndex(self, row, column, node):
if node.index == None:
index = self.createIndex(row, column, node)
node.index = index
if node.widget is None:
node.widget = Widget_Tooltip(node)
self.__view.setIndexWidget(index, node.widget)
return node.index
################################################################################
class Widget_TreeView(QtGui.QTreeView):
#---------------------------------------------------------------------------
def __init__(self, model, parent=None):
super(Widget_TreeView, self).__init__(parent)
self.setModel(model)
#self.setIndentation(0)
model.setView(self)
root = model.index(0,0)
################################################################################
class Widget_Tooltip(QtGui.QWidget):
#---------------------------------------------------------------------------
def __init__(self, node):
super(Widget_Tooltip, self).__init__()
# Vars
self.node = node
self.txt = None
# Commands
self.create_tooltip(self.node)
############################################
def create_tooltip(self, node):
layout = QtGui.QHBoxLayout()
self.txt = QtGui.QLabel( node.txt)
self.txt.setToolTip("Text tooltip %s %s" % (node.txt, node.tooltip))
layout.addWidget(self.txt, 1)
self.setLayout(layout)
################################################################################
if __name__ == '__main__':
try:
form_ui.close()
form_ui.deleteLater()
except:
pass
form_ui = MyTree()
form_ui.show()
try:
form_ui.show()
except:
form_ui.close()
form_ui.deleteLater()
QTreeWidget code:
import sys, os, time
from PySide import QtCore, QtGui
from shiboken import wrapInstance
import maya.OpenMayaUI as mui
def get_parent():
ptr = mui.MQtUtil.mainWindow()
return wrapInstance( long( ptr ), QtGui.QWidget )
class Main_Window(QtGui.QDialog):
def __init__(self, parent = get_parent()):
super(Main_Window, self).__init__(parent)
# Commands
self.create_gui()
self.create_layout()
self.get_contents( None )
def create_gui( self ):
self.tw_file_list = File_List( self )
self.parent = self.tw_file_list.invisibleRootItem()
def create_layout( self ):
self.layout = QtGui.QHBoxLayout( self )
self.layout.addWidget(self.tw_file_list)
self.setLayout( self.layout )
def get_contents( self, path ):
self.tw_file_list.clear()
path = "C:\Program Files"
contents = os.listdir( path )
for item in contents:
print item
parent = self.tw_file_list.invisibleRootItem()
date = self.get_date( item, path)
self.add_item(item, date, parent)
def add_item(self, name, date, parent):
item = QtGui.QTreeWidgetItem(parent)
item.setText(0, name)
item.setText(1, date)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled )
return item
def get_date( self, item, path):
path = "C:\Program Files"
file = str(path + "/" + item)
date = time.localtime(os.path.getmtime(file))
clean_date = "{0}_{1}_{2} {3}:{4}".format( date[0], date[1], date[2], date[3], str(date[4]).zfill(2) )
return clean_date
############################################
class File_List( QtGui.QTreeWidget ):
''' Create the file filters '''
def __init__( self, parent=get_parent() ):
super( File_List, self ).__init__( parent )
# Setup UI
self.setColumnCount(2)
self.setHeaderLabels(["name","date"])
self.parent = self.invisibleRootItem()
############################################
if __name__ == "__main__":
# Workaround hack for a PySide bug within maya
try:
main_ui.close()
main_ui.deleteLater()
except:
pass
# Show stuff
main_ui = Main_Window()
main_ui.show()
try:
main_ui.show()
except:
main_ui.close()
main_ui.deleteLater()
Here's your QTreeWidget example, simplified:
import sys
from PySide import QtCore, QtGui
class File_List( QtGui.QTreeWidget ):
def __init__( self, parent=None):
super( File_List, self ).__init__( parent )
self.setColumnCount(2)
self.setHeaderLabels(["name","date"])
self.get_contents()
def get_contents( self):
self.clear()
contents = ["path1","path2"]
for path in contents:
date = self.get_date(path)
self.add_item(path,date)
def add_item(self, name, date):
item = QtGui.QTreeWidgetItem(self)
item.setText(0, name)
item.setText(1, date)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled )
return item
def get_date(self, path):
return "a date"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
win= File_List()
win.show()
sys.exit(app.exec_())
And here's the same thing with a QTreeView and a QStandardItemModel (+ how to add children):
import sys
from PySide import QtCore, QtGui
class MyModel(QtGui.QStandardItemModel):
def __init__(self, parent=None):
super(MyModel, self).__init__(parent)
self.get_contents()
def get_contents(self):
self.clear()
contents=["path1","path2"]
for path in contents:
date = self.get_date(path)
self.add_item(path,date)
def add_item(self,name,date):
item1 = QtGui.QStandardItem(name)
item2 = QtGui.QStandardItem(date)
self.appendRow([item1, item2])
#to append child items
childItem=QtGui.QStandardItem("child")
item1.appendRow(childItem)
def get_date(self, path):
return "a date"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
model=MyModel()
treeView=QtGui.QTreeView()
treeView.setModel(model)
model.setHorizontalHeaderLabels(["name","date"])
treeView.show()
sys.exit(app.exec_())

Categories