Python:如何在PyQt中跟踪从一个ListWidget拖放到另一个的ListItem

1 投票
1 回答
1017 浏览
提问于 2025-04-18 00:14

这里有两个可以拖放的列表控件(这个例子是从之前的帖子中拿来的)。当发生放置事件时,会调用 droppedOnA(arg)droppedOnA(arg) 这两个方法。从对话框外部(比如从文件浏览器)拖放到列表控件上是可以正常工作的。但是,从一个列表控件拖放到另一个列表控件就不行了。因为没有办法追踪到底放置了哪些项目,因为 droppedOnA(arg)droppedOnA(arg) 这两个方法没有接收到任何参数(这和从对话框外部拖放时的情况不同)。在我开始用一些复杂的方法来解决这个问题之前,我想确认一下是否还有其他的解决办法。有没有呢?

from PyQt4 import QtGui, QtCore
import sys, os

class MyClassItem(QtGui.QListWidgetItem):
    def __init__(self, parent=None):
        super(QtGui.QListWidgetItem, self).__init__(parent)       


class ThumbListWidget(QtGui.QListWidget):
    def __init__(self, type, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setIconSize(QtCore.QSize(124, 124))
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            super(ThumbListWidget, self).dragEnterEvent(event)

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            super(ThumbListWidget, self).dragMoveEvent(event)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            links = []
            for url in event.mimeData().urls():
                links.append(str(url.toLocalFile()))
            self.emit(QtCore.SIGNAL("dropped"), links)
        else:
            event.setDropAction(QtCore.Qt.MoveAction)
            super(ThumbListWidget, self).dropEvent(event)
            self.emit(QtCore.SIGNAL("dropped"))


class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()
        self.listItems={}

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidgetA = ThumbListWidget(self)
        self.listWidgetB = ThumbListWidget(self)

        for i in range(3):
            listItemAInstance=MyClassItem()
            name='A'+'%04d'%i
            listItemAInstance.setText(name)
            listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
            if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)

            icon=self.getIcon(name)
            listItemAInstance.setIcon( icon ) 

            self.listWidgetA.addItem(listItemAInstance) 

            listItemBInstance=MyClassItem()
            name='B'+'%04d'%i
            listItemBInstance.setText(name)
            icon=self.getIcon(name)
            listItemBInstance.setIcon( icon )

            if i%2: listItemBInstance.setBackgroundColor(QtCore.Qt.lightGray)
            self.listWidgetB.addItem(listItemBInstance) 

        myBoxLayout.addWidget(self.listWidgetA)      

        myBoxLayout.addWidget(self.listWidgetB)   
        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.droppedOnA)
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)

        Button_01 = QtGui.QPushButton("Print Dropped Items")
        Button_01.clicked.connect(self.printWhatItemsWereDropped)
        myBoxLayout.addWidget(Button_01)


    def printWhatItemsWereDropped(self):
        print "List of items dropped: "


    def getThumbPath(self, name):
        thumb_dirpath=os.path.expanduser("~")+'/thumbs/' +name+'/'+name+'.jpg'
        return thumb_dirpath

    def getIcon(self, name):
        thumbpath=self.getThumbPath(name)

        if not thumbpath: return
        color='black'
        if os.path.exists( os.path.dirname( thumbpath ) ) == False: os.makedirs( os.path.dirname( thumbpath ) )

        img = QtGui.QImage(64, 64, QtGui.QImage.Format_RGB32)
        img.fill(QtGui.QColor(96,96,96))     

        painter = QtGui.QPainter(img)
        font = painter.font()
        font.setBold(True)
        font.setPointSize(48)

        filename, fileExtension = os.path.splitext( os.path.basename( thumbpath ) )  

        text=filename.upper()
        font.setPointSize(18)        

        painter.setPen(QtGui.QColor(color))
        painter.setFont(font)
        painter.drawText(img.rect(), QtCore.Qt.AlignCenter, text)
        painter.end()
        img.save(thumbpath, 'JPG')

        icon = QtGui.QIcon( thumbpath )
        pixmap = icon.pixmap(64, 64)
        icon = QtGui.QIcon(pixmap)
        return icon


    def droppedOnA(self, arg=None):
        print '\n\t droppedOnA', arg

    def droppedOnB(self, arg=None):
        print '\n\t droppedOnB', arg


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(720,480)
    sys.exit(app.exec_())

1 个回答

2

我之前在一个回答的评论里提到过怎么做这个。不过无论如何,这里有一个稍微简单粗糙的实现,它会打印出源列表控件的名称,后面跟着被放下的索引。

class ThumbListWidget(QtGui.QListWidget):
    _drag_info = []

    def __init__(self, type, name, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setObjectName(name)
        ...

    def startDrag(self, actions):
        self._drag_info[:] = [str(self.objectName())]
        for item in self.selectedItems():
            self._drag_info.append(self.row(item))
        super(ThumbListWidget, self).startDrag(actions)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            ...
        elif self._drag_info:
            event.setDropAction(QtCore.Qt.MoveAction)
            super(ThumbListWidget, self).dropEvent(event)
            self.emit(QtCore.SIGNAL("dropped"), list(self._drag_info))

    ...

    self.listWidgetA = ThumbListWidget(self, 'A')
    self.listWidgetB = ThumbListWidget(self, 'B')

撰写回答