【问题标题】:Python: How to track ListItems that were drag and dropped from one ListWidget onto another with PyQtPython:如何使用 PyQt 跟踪从一个 QListWidget 拖放到另一个 QListWidget 的列表项
【发布时间】:2014-03-27 22:17:48
【问题描述】:

有两个启用拖放功能的 ListWidgets(示例取自上一篇文章)。 当放置事件发生时,droppedOnA(arg)droppedOnA(arg) 方法被调用。从对话框窗口的“外部”(例如从文件浏览器)拖放到列表小部件上效果很好。但是从一个 listWidget 拖放到另一个 listWidget 不会。因为没有办法跟踪丢弃了哪些项目,因为 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_())

【问题讨论】:

    标签: python pyqt qlistwidget


    【解决方案1】:

    我已经在comment to a previous answer 中建议了如何执行此操作。但无论如何,这是一个稍微粗略的实现,它应该打印一个源列表小部件名称的列表,然后是删除的索引。

    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')
    

    【讨论】:

    • 太棒了!谢谢 Ekhumoro!
    • @Sputnix。在其他地方回答您的 cmets:您为什么关心 drag_info 以获取不会掉落的物品? drag_info 列表只是内部临时存储,每次新拖动都会重置 - 它不打算从外部访问。
    • 我认为 _drag_info 列表变量被用于每个 startDrag 事件来存储“开始拖动”的项目。稍后,此变量用于检索要发送到通过“dropped”信号链接的函数的存储项目。该函数接收 listWidget 的名称(A 或 B)和项目的索引号。它工作得很好。再次感谢分享这项技术!我希望我能做的唯一一件事是:不要将“startDrag()ed”项目记录到 _drag_info 变量中,而是只捕获那些实际被丢弃的项目。
    • 我希望能够捕获/“记录”实际丢弃的项目(而不是 startDraged)的原因是为了避免用户单击项目时开始拖动它的情况... 改变主意并释放拖动(实际上是从最初拖动项目的位置复制 ListWidget 中的项目)或将项目放在其自己的 ListWidget 上。如果在 startDrag 事件上更新了 _drag_info 变量,则项目索引仍会向下发送到函数。这可能会导致代码混乱,因为该项目从未“丢弃”到自己的列表小部件之外。
    • @Sputnix。这是没有意义的。您的原始示例已经允许项在小部件之间和自身上拖放(即可以重新排列项目)。事实上,您在this questionthis question 中特别要求提供这些功能。没有办法“得到被丢弃的物品”。这就是基类dropEvent 方法的作用。您必须编写自己的自定义实现,您想要不同的行为。
    猜你喜欢
    • 1970-01-01
    • 2021-08-12
    • 2021-11-01
    • 2020-12-29
    • 2011-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多