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 send2trashclass 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 Falseif name=="main":
from sys import argv, exitclass 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 send2trashif 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