Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Treeview + QFileSystemModel, how can i retrieve multi selection list



  • Hello Guys,
    I have alot of queries, this is just tip of the iceberg.
    I create a treeview with qfilesystemmodel for folder icons visibility all worked fine.(any better approach please let me know)
    What i want, is there by any chance we can get multiselection list(drag select list of items from tree view), because i was successful with single toggle, below is test code

    	index = self.qtreeview.currentIndex()
    	for ix in self.qtreeview.selectionModel().selectedIndexes():
    		text = ix.data(QtCore.Qt.DisplayRole)  # or ix.data()
    		print(text)
    	print(self.model.filePath(index))
    

    as you can see above for loop, yes it still considers only single click item
    and if possible can you provide an eg.



  • @blossomsg Hi,

    Did you configure the tree view to support extended or multiple selection ?

    tree->setSelectionMode(QAbstractItemView.ExtendedSelection);
    

    see https://doc.qt.io/qt-5/qabstractitemview.html#selectionMode-prop



  • Hey @Gojir4 ,

    Yes i did

    	self.treeview.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
    

    so selection works fine, after the selection i want to query all the highlighted selections
    and pyside2 should return me object or str or unicode, so through that i can extract exact path of all the highlighted items



  • @blossomsg I'm not sure to understand what is the problem here. anyway here is a small example using signal selectionChanged from QItemSelectionModel.

    from PySide2.QtWidgets import QTreeView, QAbstractItemView, QApplication
    from PySide2.QtGui import QStandardItemModel, QStandardItem
    from PySide2.QtCore import Qt, QObject, QItemSelectionModel
    import sys
    
    a = QApplication(sys.argv)
    
    tree = QTreeView()
    model = QStandardItemModel(tree)
    tree.setModel(model)
    tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
    
    row = QStandardItem('Row 1')
    model.appendRow(row)
    row.appendRow(QStandardItem('Row 1 1'))
    row.appendRow(QStandardItem('Row 1 2'))
    row = QStandardItem('Row 2')
    model.appendRow(row)
    row.appendRow(QStandardItem('Row 2 1'))
    row.appendRow(QStandardItem('Row 2 2'))
    model.appendRow(QStandardItem('Row 3'))
    model.appendRow(QStandardItem('Row 4'))
    
    selectionModel: QItemSelectionModel = tree.selectionModel()
    def selectionChanged(selected, deselected):
        print('selected: {}'.format(','.join(str(i.row()) for i in selected.indexes())))
        # Displaying Row index 
        print('full selection: {}'.format(','.join(str(i.row()) for i in selectionModel.selectedIndexes())))
        # Displaying data
        print('full selection text: {}'.format(','.join(str(i.data()) for i in selectionModel.selectedIndexes())))
    
    selectionModel.selectionChanged.connect(selectionChanged)
    
    tree.show()
    a.exec_()
    


  • Hey Thanks for the snippet @Gojir4 ,
    the extended selection works fine, but if now i want to print every item that i have selected randomly how can i do that?

    eg:
    D:/
    a
    b
    c
    e
    f

    so then if i select a, c, e, f-- how can i return selection values of all four items as strings
    any approach?



  • @blossomsg Using i.data() instead of i.row()

    I have updated my previous post to display data. Note with QFileSystemModel you probably need to use QFileSystemModel.FilePathRole role instead of default Qt.DisplayRole. see https://doc.qt.io/qt-5/qfilesystemmodel.html#Roles-enum

    So instead of i.data(), it will be i.data(QtWidgets.QFileSystemModel.FilePathRole)

    def selectionChanged(selected, deselected):
        ...
        # Displaying Row index 
        print('full selection: {}'.format(','.join(str(i.row()) for i in selectionModel.selectedIndexes())))
        # Displaying data
        print('full selection text: {}'.format(','.join(str(i.data()) for i in selectionModel.selectedIndexes())))
    

    Outputs:

    full selection: 1,2,0,1
    full selection text: Row 2,Row 3,Row 2 1,Row 2 2
    

    For converting list of QModelIndex to string list:

    stringlist = [str(i.data()) for i in selectionModel.selectedIndexes()]
    # or simpler
    stringlist = []
    for i in selectionModel.selectedIndexes():
        stringlist.append(str(i.data()))
    


  • Hey @Gojir4 ,

    This is nearly what i want, i just don't understand one line
    this some override

    selectionModel: QItemSelectionModel = tree.selectionModel()

    is this python3, or only pyside2

    can you explain, as i have not come across this approach



  • @blossomsg
    selectionModel: QItemSelectionModel = tree.selectionModel()

    I haven't used it myself, but I believe in later Python 3 you can (optionally) write : type-specification when you create a variable. I use the : type-specification only for the parameters received by methods. This is not a PySide2 thing.

    If you don't like it, or your Python doesn't, it should be just:
    selectionModel = tree.selectionModel()

    It only affects the reading/editing experience anyway, has no effect at runtime.



  • @JonB Exact
    @blossomsg That's only for my editor knowing the type and providing auto-completion, sry for confusion



  • @Gojir4
    No need to apologise, it's good style. The last time I first looked at Python at Python 3.something-less-than-7/6/5??, it had the : type for method parameters, and the -> type for returns, but not for variables, and it barfed if you tried one. So I wrote all my code using method param types (which personally I highly recommend, but then I like C++ and not Python!), and never could do anything about variables. So that support must have arrived at some more recent Python 3 version? (Or, it's just possible that it was PyCharm which didn't yet understand it, but I thought I saw it only arrived in a recent Python 3?)


  • Lifetime Qt Champion

    Hi,

    Type hinting has been introduced in Python 3.5.



  • @SGaist
    Indeed. In 3.5 "type annotations of function parameters, a.k.a. type hints". But the line in @Gojir4 code:

    selectionModel: QItemSelectionModel = tree.selectionModel()
    

    is variable type-hinting. And I believe that did not come till Python 3.6, see https://stackoverflow.com/questions/39971929/what-are-variable-annotations-in-python-3-6 and https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-pep526.

    So I must have started out on 3.5.x.


  • Lifetime Qt Champion

    @JonB You're right. I just read the question as "when did type hinting" come to Python.



  • @JonB I did start using Python 3.6 and switched quickly to 3.8. Taking inspiration from PySide2 functions declaration it was natural for me to use this type hinting also in the code, without even knowing it was something new :). I agree with your I also use method param types, that's make code more clear and understandable, especially with custom types, and probably also because of ten years of C++ :D.



  • Hello Guys,

    Thank you for all your effort especially @Gojir4
    your snippet was amazing

    https://stackoverflow.com/questions/21684336/how-to-get-the-index-for-the-filepath-of-a-selected-file-via-qfilesystemmodel

    and the above link helped me resolve the 4 modelindex values to 1 modelindex --- which results 1 path rather than showing all the 4 column paths

    from PySide2 import QtCore
    from PySide2 import QtWidgets
    from PySide2 import QtGui
    import sys
    
    
    def selectionChanged(selected, deselected):    
        index = qtreeview_files.currentIndex()
        print model.filePath(index)
    
    
    qtreeview_files = QtWidgets.QTreeView()
    model = QtWidgets.QFileSystemModel()
    model.setRootPath("")
    qtreeview_files.setModel(model)
    qtreeview_files.hideColumn(1)
    qtreeview_files.hideColumn(2)
    qtreeview_files.hideColumn(3)
    qtreeview_files.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
    selectionModel  = qtreeview_files.selectionModel()
    win_wid = QtWidgets.QWidget()
    layout = QtWidgets.QVBoxLayout()
    layout.addWidget(qtreeview_files)
    win_wid.setLayout(layout)
    #win_wid.resize(200, 50)
    
    
    win_wid.show()
    
    
    
    selectionModel.selectionChanged.connect(selectionChanged)
    


  • Sorry for late reply got caught up with some personal work

    just an updated code.

    from PySide2 import QtCore
    from PySide2 import QtWidgets
    from PySide2 import QtGui
    import sys
    import os
    
    
    def selectionChanged(selected, deselected):    
        index = qtreeview_files.currentIndex()
        print model.filePath(index)
    
    
    qtreeview_files = QtWidgets.QTreeView()
    model = QtWidgets.QFileSystemModel()
    model.setRootPath("")
    qtreeview_files.setModel(model)
    qtreeview_files.hideColumn(1)
    qtreeview_files.hideColumn(2)
    qtreeview_files.hideColumn(3)
    qtreeview_files.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
    selectionModel  = qtreeview_files.selectionModel()
    win_wid = QtWidgets.QWidget()
    layout = QtWidgets.QVBoxLayout()
    layout.addWidget(qtreeview_files)
    win_wid.setLayout(layout)
    #win_wid.resize(200, 50)
    
    
    win_wid.show()
    
    ##after you confirm the selection run this to get final selection list
    list_of_sel_files = []
    all = qtreeview_files.selectedIndexes()
    for x in all:
        print model.filePath(x)
        list_of_sel_files.append(model.filePath(x))
    ##########################################
    
    selectionModel.selectionChanged.connect(selectionChanged)
    

    closing ticket


Log in to reply