QfileSystemModel : removes rows that gaps can exist within them



  • please see the following post !!! thanks



  • The same way you would reimplement any Python class' method:

    @
    class MyFileSystemModel(QFileSystemModel):
    def removeRows(self, row, count, parent=QModelIndex()):
    # Your implementation...
    @

    Not sure why you would want to reimplement this method on QFileSystemModel though...



  • I want to send files to recycle bin when removing rows ,
    since
    @bool QFileSystemModel::remove ( const QModelIndex & index ) const
    @

    deletes files from the file system; it does not move them to a location where they can be recovered.
    so I use another python module to do this
    https://pypi.python.org/pypi/Send2Trash
    since

    @ bool QAbstractItemModel::removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() )@

    can only removes rows in one piece, next to each other without any gaps.
    but I want to removes rows that gaps can exist within them ,so I decided to reimplement this method with the following code ,but when removeRows in my code is run , the view then end up in an invalid state.I wonder how to fix this problem ……
    @
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from send2trash import send2trash

    class FileSystemModel(QFileSystemModel):
    def init(self, parent=None):
    super(QFileSystemModel, self).init(parent)

    def removeRows(self, first, rows=1 , parent = QModelIndex()):
        file = self.index(first, 0, parent)
        filePath=self.filePath(file )
        print(filePath)
        self.beginRemoveRows(parent, first,  first+rows-1)
        try:
            send2trash(filePath)
        except  OSError as e:
            self.endRemoveRows()
            return False
        else:
            self.endRemoveRows()
            return True
    

    if name == "main":
    app = QApplication(sys.argv)
    model= FileSystemModel()
    model.setRootPath(r"E:\Project\viviDownloader\Download\finished")

    tableView=QTableView()
    tableView.setModel(model)
    displayedIndex=model.index(r"E:\Project\viviDownloader\Download\finished")
    tableView.setRootIndex(displayedIndex)
    
    tableView.setSelectionBehavior( QAbstractItemView.SelectRows );
    
    selectionModel = tableView.selectionModel()
    def on_removeRow_triggered():
        selectedRows=selectionModel.selectedRows()
        print(selectedRows)
        for row in range(len(selectedRows)):
            print(selectionModel.selectedRows()[0].row())
            model.removeRows(selectionModel.selectedRows()[0].row())
    
    def creatContextMenu():
        menu = QMenu(tableView)
        removeRows=QAction("removeRows",None, triggered=on_removeRow_triggered)
        menu.addAction(removeRows)
        menu.exec_(QCursor.pos())
    
    tableView.setContextMenuPolicy(Qt.CustomContextMenu)
    tableView.customContextMenuRequested.connect(creatContextMenu)
    tableView.show()
    
    sys.exit(app.exec_())
    

    @



  • It would be much easier just to reimplement remove() to use send2trash() and then call it for each index in your selection. The following example reimplements remove(), just right click on a file and click 'Remove' in the menu and it will end up in your trash/recycle bin:

    @
    import sip
    sip.setapi('QString',2)
    sip.setapi('QVariant',2)

    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    from send2trash import send2trash

    class FSM(QFileSystemModel):
    def remove(self, index):
    if not index.isValid(): return False
    path=self.filePath(index)
    try:
    send2trash(path)
    return True
    except OSError: return False

    if name=="main":
    from sys import argv, exit

    class Widget(QWidget):
        def __init__(self, parent=None, **kwargs):
            QWidget.__init__(self, parent, **kwargs)
    
            l=QVBoxLayout(self)
    
            self._model=FSM(self)
            self._tree=QTreeView(
                self,
                contextMenuPolicy=Qt.CustomContextMenu,
                customContextMenuRequested=self.showMenu)
    
            self._tree.setModel(self._model)
            self._tree.setRootIndex(self._model.setRootPath('/'))
    
            l.addWidget(self._tree)
    
        @pyqtSlot(QPoint)
        def showMenu(self, pos):
            index=self._tree.indexAt(pos)
            if not index.isValid(): return
    
            menu=QMenu(self)
            menu.addAction(QAction("Remove", self, triggered=lambda: self._model.remove(index)))
            menu.popup(self._tree.viewport().mapToGlobal(pos))
    
    a=QApplication(argv)
    w=Widget()
    w.show()
    w.raise_()
    exit(a.exec_())
    

    @

    Hope this helps ;o)



  • yes ,it is easy to remove only one row ,but the user may want to remove many rows at the same time ,so I think to reimplement removing many rows will be a good design .I find another way to do this ,the following is my code
    @
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from send2trash import send2trash

    if name == "main":
    app = QApplication(sys.argv)
    model= QFileSystemModel()
    model.setRootPath(r"E:\Project\viviDownloader\Download\finished")

    tableView=QTableView()
    tableView.setModel(model)
    displayedIndex=model.index(r"E:\Project\viviDownloader\Download\finished")
    tableView.setRootIndex(displayedIndex)
    
    tableView.setSelectionBehavior( QAbstractItemView.SelectRows );
    
    selectionModel = tableView.selectionModel()
    def on_removeRow_triggered():
        selectedRows=selectionModel.selectedRows()
        selectedFilePathList=list(map(model.filePath, selectedRows))
        print(selectedFilePathList)
    

    map(send2trash, selectedFilePathList)

        for filePath in selectedFilePathList:
            send2trash(filePath)
    
    def creatContextMenu():
        menu = QMenu(tableView)
        removeRows=QAction("removeRows",None, triggered=on_removeRow_triggered)
        menu.addAction(removeRows)
        menu.exec_(QCursor.pos())
    
    tableView.setContextMenuPolicy(Qt.CustomContextMenu)
    tableView.customContextMenuRequested.connect(creatContextMenu)
    tableView.show()
    
    sys.exit(app.exec_())
    

    @

    I wonder why

    map(send2trash, selectedFilePathList)

    doesn't work this time ?



  • My method would work just as well for multiple rows (sequential or not) as you would simply loop over the list of selected indexes in the same way:

    @
    ...
    map(model.remove, tableView.selectionModel().selectedRows())
    ...
    @

    Anyway, its hair splitting as both work equally well. As to your question, I suspect the reason your map() doesn't work is because filePath() returns a QString object and send2trash() expects a simple python string. You can either reimplement your on_removeRow_triggered() method as follows to cast QString to str:

    @
    def on_removeRow_triggered():
    selectedRows=selectionModel.selectedRows()
    map(lambda x: send2trash(str(model.filePath(x))), selectedRows)
    @

    Or you can set the SIP API to always use str instead of QString by placing the following at the top of the entry point to your program:

    @
    import sip
    sip.setapi('QString',2)
    @

    This will make any Qt method that returns QString return str instead.

    Hope this helps ;o)



  • I am using Python 3 ,I use type() to test the return type of filePath() ,and the result is that filePath() returns str rath2than QString


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.