TransWikia.com

pyqt5のQListViewでDrag&Drop機能を追加したい

スタック・オーバーフロー Asked on September 1, 2021

Pyqt5のQListViewを使って作ったアイテムモデルでDrag&Dropの機能を追加したいです。

txtファイルをドロップできるようにコードを書いて見たつもりなのですが、ファイルをドロップできません。

どうすればよいのでしょうか。


表示されるGUI

画像

ソースコード

import sys
from PyQt5 import QtGui,QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class ListView(QListView):
    def __init__(self, parent=None):
        super(ListView,self).__init__(parent)
        self.setAcceptDrops(True) 
        self.setParent(parent)
        self.win=parent
        
    def dragEnterEvent(self, e):
        print("a")
        mimeData = e.mimeData()

        # パスの有無で判定
        if mimeData.hasUrls():
            print("b")
            e.accept()
        else:
            print("c")
            e.ignore()
            #e.accept()

    def dropEvent(self, e):
        print("d")
        # ファイルから画像読込
        urls = e.mimeData().urls()
        urllength=len(urls)        

        for file in range(0,urllength):
            textpath=urls[file].toLocalFile()
            root, ext=os.path.splitext(textpath)
            if ext==".txt" or ext==".text":
                print(urls[file].toLocalFile())
            else:
                pass

class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self):
        QtCore.QAbstractItemModel.__init__(self)
        #self.nodes = ['node0', 'node1', 'node2', "node4", "node5"]

    def index(self, row, column, parent):
        return self.createIndex(row, column, nodes[row])

    def parent(self, index):
        return QtCore.QModelIndex()

    def rowCount(self, index):
        if index.internalPointer() in nodes:
            return 0
        return len(nodes)

    def columnCount(self, index):
        return 1

    def data(self, index, role):
        if role == 0: 
            return index.internalPointer()
        else:
            return None

    def supportedDropActions(self): 
        return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction         

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.ItemIsEnabled
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | 
               QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled        

    def mimeTypes(self):
        return ['text/xml']

    def mimeData(self, indexes):
        mimedata = QtCore.QMimeData()
        mimedata.setData('text/xml', 'mimeData')
        return mimedata

    def dropMimeData(self, data, action, row, column, parent):
        print ('dropMimeData %s %s %s %s' % (data.data('text/xml'), action, row, parent))
        return True


class MainForm(QWidget):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        self.treeModel = TreeModel()
        
        self.view = ListView()
        self.view.setModel(self.treeModel)
        self.view.activated.connect(self.viewClicked2)#ダブルクリックでの動作
        self.view.clicked.connect(self.viewClicked)
        
        self.btn=QPushButton("index0")
        self.btn.clicked.connect(self.change_index)
        
        layout = QHBoxLayout(self)
        layout.addWidget(self.view)
        layout.addWidget(self.btn)

        self.setLayout(layout)

        self.show()
        
    def viewClicked(self, indexClicked):
        print('index of proxy row', indexClicked.row())
        
    def viewClicked2(self, index):
        print(index.row())
        
    def change_index(self):
        index = self.view.model().createIndex(0, 0)
        self.view.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)


def main():
    app = QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    nodes=['node0', 'node1', 'node2', "node4", "node5"]
    main()

One Answer

dragMoveEventを追加する必要があるみたいですね。
https://kiwamiden.com/drag-and-drop-files-to-qlistview
を参考にしました。以下は修正したコードです。

import sys
from PyQt5 import QtGui,QtCore, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import os

class ListView(QListView):
    def __init__(self, parent=None):
        super(ListView,self).__init__(parent)
        self.setAcceptDrops(True) 
        self.setParent(parent)
        self.win=parent
        
    def dragEnterEvent(self, e):
        mimeData = e.mimeData()

        # パスの有無で判定
        if mimeData.hasUrls():
            e.accept()
        else:
            e.ignore()
            #e.accept()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
             
        else:
            pass

    def dropEvent(self, e):
        urls = e.mimeData().urls()
        urllength=len(urls)        

        for file in range(0,urllength):
            textpath=urls[file].toLocalFile()
            root, ext=os.path.splitext(textpath)
            if ext==".txt" or ext==".text":
                print(urls[file].toLocalFile())
            else:
                pass

class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self):
        QtCore.QAbstractItemModel.__init__(self)
        #self.nodes = ['node0', 'node1', 'node2', "node4", "node5"]

    def index(self, row, column, parent):
        return self.createIndex(row, column, nodes[row])

    def parent(self, index):
        return QtCore.QModelIndex()

    def rowCount(self, index):
        if index.internalPointer() in nodes:
            return 0
        return len(nodes)

    def columnCount(self, index):
        return 1

    def data(self, index, role):
        if role == 0: 
            return index.internalPointer()
        else:
            return None

    def supportedDropActions(self): 
        return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction         

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.ItemIsEnabled
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | 
               QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled        

    def mimeTypes(self):
        return ['text/xml']

    def mimeData(self, indexes):
        mimedata = QtCore.QMimeData()
        mimedata.setData('text/xml', 'mimeData')
        return mimedata

    def dropMimeData(self, data, action, row, column, parent):
        print ('dropMimeData %s %s %s %s' % (data.data('text/xml'), action, row, parent))
        return True


class MainForm(QWidget):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        self.treeModel = TreeModel()
        
        self.view = ListView()
        self.view.setModel(self.treeModel)
        self.view.activated.connect(self.viewClicked2)#ダブルクリックでの動作
        self.view.clicked.connect(self.viewClicked)
        
        self.btn=QPushButton("index0")
        self.btn.clicked.connect(self.change_index)
        
        layout = QHBoxLayout(self)
        layout.addWidget(self.view)
        layout.addWidget(self.btn)

        self.setLayout(layout)

        self.show()
        
    def viewClicked(self, indexClicked):
        print('index of proxy row', indexClicked.row())
        
    def viewClicked2(self, index):
        print(index.row())
        
    def change_index(self):
        index = self.view.model().createIndex(0, 0)
        self.view.selectionModel().select(index, QItemSelectionModel.ClearAndSelect)


def main():
    app = QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    nodes=['node0', 'node1', 'node2', "node4", "node5"]
    main()

Correct answer by toma on September 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP