0

I want to create a TreeView widget using PySide for Autodesk Maya that can display the content of a directory like the example below:

Treeview example

I did find an example using tkinter for a simple python script : Tkinter: Treeview widget. But I want to use Pyside so I can run it in Autodesk Maya

I did create a script that can display a simple TreeView widget:

this is my code:

try:
  from PySide2.QtCore import * 
  from PySide2.QtGui import * 
  from PySide2.QtWidgets import *
  from PySide2 import __version__
  from shiboken2 import wrapInstance 
  import collections
  import maya.OpenMayaUI as OpenMayaUI
except ImportError:
  from PySide.QtCore import * 
  from PySide.QtGui import * 
  from PySide import __version__
  from shiboken import wrapInstance 
  import collections
  import maya.OpenMayaUI as OpenMayaUI

treepop = collections.defaultdict(list)
treepop[""]=['layer_1',
             'layer_2',
             'layer_3',
             'layer_4',
             'layer_5',
             'layer_6',
             'layer_12']
treepop["layer_2"] = ['layer_7',
                        'layer_9',
                        'layer_11']
treepop["layer_3"] = ['layer_7']
treepop["layer_8"] = ['layer_10']
treepop["layer_10"] = ['layer_13']

def mayaToQT(name):
    # Maya -> QWidget
    ptr = OpenMayaUI.MQtUtil.findControl(name)
    if ptr is None:         ptr = OpenMayaUI.MQtUtil.findLayout(name)
    if ptr is None:         ptr = OpenMayaUI.MQtUtil.findMenuItem(name)
    if ptr is not None:     return wrapInstance(long(ptr),
                                                          QWidget)


cmds.window()
layout = cmds.columnLayout(rowSpacing=10, columnWidth=250)
qwidget= mayaToQT(layout)
qlayout = qwidget.children()[0]
treeview = QTreeWidget()
treeview.setSelectionMode(QAbstractItemView.ExtendedSelection)
treeview.setColumnCount(1)
treeview.setAlternatingRowColors(True)
treeview.clear()
qlayout.addWidget(treeview)

items = []
for k in treepop[""]:
    root_item = QTreeWidgetItem()
    root_item.setText(0,k)
    print(k)

    if k in treepop:
        for v in treepop[k]:
            child_item = QTreeWidgetItem()
            child_item.setText(0,v)
            root_item.addChild(child_item)

    items.append(root_item)
treeview.addTopLevelItems(items)

cmds.showWindow()

def getSelected():
    items = treeview.selectedItems()
    for i in items:
        print(i.text(0))

Can any one help me please!

Edit: I did fix the problem with your help, thank you all:

try:
  from PySide2.QtCore import * 
  from PySide2.QtGui import * 
  from PySide2.QtWidgets import *
  from PySide2 import __version__
  from shiboken2 import wrapInstance 
  import collections
  import maya.OpenMayaUI as OpenMayaUI
  import os
except ImportError:
  from PySide.QtCore import * 
  from PySide.QtGui import * 
  from PySide import __version__
  from shiboken import wrapInstance 
  import collections
  import maya.OpenMayaUI as OpenMayaUI
  import os
class MyTree(QTreeWidget):
    def __init__(self, parent=None):
        QTreeWidget.__init__(self, parent)        
        self.startDir = "C:/users/user/desktop/myFolder"
        self.setHeaderLabels([self.startDir])
        self.setColumnWidth(0,400)
        self.setContentsMargins(0, 0, 0, 0)
        self.header().setDefaultSectionSize(300)
        self.header().setStretchLastSection(False)
        self.header().setResizeMode(0, QHeaderView.ResizeToContents)
        self.header().setResizeMode(0, QHeaderView.Stretch)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setColumnCount(1)
        self.setAlternatingRowColors(True)
        self.fillTree()
        self.show()


    def fillTree(self):                
        def iterate(currentDir, currentItem):            
            for f in os.listdir(currentDir):

                path = os.path.join(currentDir, f)
                if os.path.isdir(path):

                    dirItem = QTreeWidgetItem(currentItem)
                    dirItem.setText(0, f)
                    iterate(path, dirItem)
        iterate(self.startDir, self)



def mayaToQT(name):
    # Maya -> QWidget
    ptr = OpenMayaUI.MQtUtil.findControl(name)
    if ptr is None:         ptr = OpenMayaUI.MQtUtil.findLayout(name)
    if ptr is None:         ptr = OpenMayaUI.MQtUtil.findMenuItem(name)
    if ptr is not None:     return wrapInstance(long(ptr),QWidget)


cmds.window(w=600, h=300)
layout = cmds.columnLayout(rowSpacing=60, columnWidth=400, w=600, h=600)
qwidget= mayaToQT(layout)
qlayout = qwidget.children()[0]
treeview = MyTree()

qlayout.addWidget(treeview)
cmds.showWindow()

But can any one help to set the height and width of QTreeView widget?

IT World
  • 165
  • 1
  • 10

3 Answers3

2

The QDirModel is great. Just in case you want another solution you can try this:

class MyTree(QtWidgets.QTreeWidget):
    def __init__(self, parent=None):
        super(MyTree, self).__init__(parent=parent)
        self.startDir = "C:/daten/backup"
        self.fillTree()
        self.show()

    def fillTree(self):        
        def iterate(currentDir, currentItem):            
            for f in os.listdir(currentDir):
                path = os.path.join(currentDir, f)
                if os.path.isdir(path):
                    dirItem = QtWidgets.QTreeWidgetItem(currentItem)
                    dirItem.setText(0, f)
                    iterate(path, dirItem)
                else:
                    fileItem = QtWidgets.QTreeWidgetItem(currentItem)
                    fileItem.setText(0, f)
        iterate(self.startDir, self)

It simply iterates over a starting directory until it does not find any directories any more.

haggi krey
  • 1,885
  • 1
  • 7
  • 9
1

You are mixing maya and Qt widgets, is there any reason for this? QtWidgets automatically create a window if the parent is none. A quite good practice is to subclass a widget what enables you to keep all necessay data in one place like this:

class MyTree(QtWidgets.QTreeWidget):
    def __init__(self, parent=None):
        super(MyTree, self).__init__(parent)
        self.fillTree()

    def fillTree(self):
        self.clear()
        for i in range(10):
            item = QtWidgets.QTreeWidgetItem(self)
            item.setText(0, str(i))

And then you can show it automatically if you add self.show() after the self.fillTree() in the init method or call it from maya:

mt = MyTree()
mt.show()

A window should appear. This window will not be always on top of the Maya window. If you want that, import the mayaMixin and inherit from the mixin:

import maya.app.general.mayaMixin as MayaMixin

class MyTree(MayaMixin.MayaQWidgetBaseMixin, QtWidgets.QTreeWidget):
    .....

Next you can start to fill the tree with correct data and add subitems. The subitems can be simpy added by using the current item as parent:

item = QtWidgets.QTreeWidgetItem(self)
item.setText(0, "parent")
subItem = QtWidgets.QTreeWidgetItem(item)
subItem.setText(0, "child")
haggi krey
  • 1,885
  • 1
  • 7
  • 9
  • But my question is how can I fill the treeview with folder content ? – IT World Nov 13 '19 at 12:56
  • Ah, okay, so simply read a folder content with: os.listdir() and for every add an item and search for subdirectorires or use os.walk() to get all files in a hierarchy. – haggi krey Nov 13 '19 at 13:49
  • Because I want to do something like this: https://stackoverflow.com/q/58270255/10591725. But Maya treeview does not allow me to add the same name of a folder into it. that's why I did choose to use PySide – IT World Nov 13 '19 at 14:42
  • What I want to say is that there is no need to use cmds.window() and its layouts, simpy use QT as described above. – haggi krey Nov 13 '19 at 15:06
  • 1
    he is mixing because he doesn't know Qt I think, Im the one who gave him this workaround to expend cmds.treeview : https://stackoverflow.com/questions/58270255/item-layer-7-already-exists-in-the-treeview-in-maya/58273086#58273086 – DrWeeny Nov 13 '19 at 15:11
  • @DrWeeny You're right, I want to use cmds.window() for other reasons too, so I can't use QT. I want to use PySide like you did give me in your answer – IT World Nov 13 '19 at 15:21
1

you need to organize your data ! In your last comment, you told me you didn't know what are your datas, when you have it you can just loop throught it and add child to the tree with 'while' or 'for'

my_data_folders = {'parent1': {'Lips':['A', 'B', 'C']} }

this part below is your loops to add children :

items = []
for k in treepop:
    # this is "parent1"
    root_item = QTreeWidgetItem()
    root_item.setText(0,k)

    if treepop[k]:
        # if there is children to "parent1", add Lips children to parent1
        for v in treepop[k]:
            child_item = QTreeWidgetItem()
            child_item.setText(0,v)
            root_item.addChild(child_item)
        if treepop[k][v]:
            for sub in treepop[k][v]:

                sub_item = QTreeWidgetItem()
                sub_item.setText(0, sub)
                child_item.addChild(sub_item)

    items.append(root_item)
treeview.addTopLevelItems(items)

anything is possible the most complex thing is to organize your data

Note that if you are trying to make an explorer, there is thing in Qt as QDirModel : QTreeView Display Directory https://doc.qt.io/qtforpython/PySide2/QtWidgets/QDirModel.html

model = QtWidgets.QDirModel()
model.setReadOnly(True);
model.setSorting(QtCore.QDir.DirsFirst|QtCore.QDir.IgnoreCase|QtCore.QDir.Name)
model.setFilter(QtCore.QDir.Dirs)

treeView.setModel(model)
DrWeeny
  • 2,487
  • 1
  • 14
  • 17
  • I did just show an example for folders structure in the screenshot, What I want to say I want to display all the folder's content specified in a given path like the Tkinter example – IT World Nov 13 '19 at 15:29
  • I don't know how much sub folders exist, so I can display images from a chosen sub folder – IT World Nov 13 '19 at 15:31
  • organise your data with a while loop, and item with it too, once you have your data, you loop inside it and nest Qtreewidget. Edit the code, try something and then we can help you by correcting your code – DrWeeny Nov 13 '19 at 15:34
  • @ITWorld If you are trying to recursively get any number of sub folders and their contents you can collect all of this data using the built-in `os.walk` – Green Cell Nov 14 '19 at 01:35
  • @GreenCell Can you suggest to me an example and how can I make difference between parent folders and sub folders? – IT World Nov 14 '19 at 10:21
  • @DrWeeny Is there a way to combine QTreeWidget with Autodesk Maya window ? – IT World Nov 15 '19 at 12:49
  • what do you mean ? – DrWeeny Nov 15 '19 at 15:57
  • I did fix the problem and I did use MayaToQt function that you did give in your answer but I have problems to set the qtreeview widget size – IT World Dec 04 '19 at 11:00
  • the qlayout variable is an instance of QVBoxLayout, so you can use qlayout.SetMaximumSize, qlayout.SetMinAndMaxSize, qlayout.SetMinimumSize and all other methods https://doc.qt.io/qt-5/qvboxlayout.html – DrWeeny Dec 05 '19 at 16:14