I'm creating a widget to explore and manage files inside my qt application. To construct that, I'm using a QFileSystemModel and a QListView with the IconMode view mode.
It should allow moving files (items) into folders (other items) with the QListView.
My question is how do I implement this?
First, I'm trying to override the supportedDragActions and supportedDropActions functions from ContentFileSystemModel to allow Move and Copy actions. Also, I override the flags function to enable drag and drop. Finally, I override the canDropMimeData and dropMimeData to check if they are running, but it looks like they are not.
The first problem is that the model does not allow to drop an item file into the QListView area once it displays a prohibited icon in the cursor (shown in the image below).
First, I have to set the model to allow the drops of items in folders. After that, I can implement the code to transfer the dragged items into the folder.
Code ready to reproduce the problem:
import sys
import os
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
class ContentFileSystemModel(QFileSystemModel):
def __init__(self):
super(ContentFileSystemModel, self).__init__()
def supportedDragActions(self) -> Qt.DropActions:
print("supportedDragActions")
return Qt.MoveAction | super(ContentFileSystemModel, self).supportedDragActions() | Qt.CopyAction
def supportedDropActions(self) -> Qt.DropActions:
print("supportedDropActions")
return Qt.MoveAction | super(ContentFileSystemModel, self).supportedDropActions() | Qt.CopyAction
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
defaultFlags = super(ContentFileSystemModel, self).flags(index)
if not index.isValid():
return defaultFlags
fileInfo = self.fileInfo(index)
# The target
if fileInfo.isDir():
# Allowed drop
return Qt.ItemIsDropEnabled | Qt.ItemIsDragEnabled | defaultFlags
# The source: should be directory( in that case)
elif fileInfo.isFile():
# Allowed drag
return Qt.ItemIsDropEnabled | Qt.ItemIsDragEnabled | defaultFlags
return defaultFlags
def canDropMimeData(self, data: QMimeData, action: Qt.DropAction,
row: int, column: int, parent: QModelIndex) -> bool:
print("canDropMimeData")
return True
def dropMimeData(self, data: QMimeData, action: Qt.DropAction,
row: int, column: int, parent: QModelIndex) -> bool:
print("dropMimeData")
return True
def main(argv):
app = QApplication(sys.argv)
path = "C:\\Users\\Me\\Desktop"
file_system_model = ContentFileSystemModel()
file_system_model.setRootPath(path)
file_system_model.setReadOnly(False)
lv_file_manager = QListView()
lv_file_manager.setModel(file_system_model)
lv_file_manager.setViewMode(QListView.IconMode)
lv_file_manager.setRootIndex(file_system_model.index(path))
lv_file_manager.setResizeMode(QListView.Adjust)
lv_file_manager.setMovement(QListView.Static)
lv_file_manager.setSelectionMode(QAbstractItemView.ExtendedSelection)
lv_file_manager.setWrapping(True)
lv_file_manager.setAcceptDrops(True)
lv_file_manager.setDragEnabled(True)
lv_file_manager.setDropIndicatorShown(True)
lv_file_manager.setUniformItemSizes(True)
lv_file_manager.setDragDropMode(QAbstractItemView.InternalMove)
lv_file_manager.setFlow(QListView.LeftToRight)
lv_file_manager.show()
app.exec_()
if __name__ == "__main__":
main(sys.argv)

You are setting the wrong movement property, since you're using
Static:When using the
IconMode, that property is automatically set toFree, so you can just remove the following line:The other important implementations are in the model's
canDropMimeData()(which must returnTrueif the target is a writable directory) anddropMimeData()(that will actually move the files).The final step is to override the
dragMoveEvent()to prevent moving icons around the current view.Note that the following changes have also been made:
flags()should not returnItemIsDragEnabledif the target is a file;setAcceptDrops(True)andsetDragEnabled(True)are not required as they are automatically set when the movement is notStatic(which is the case when using theIconModeas explained above);setDragDropMode()is also not required;