【问题标题】:PySide: Drag and drop files into QListWidgetPySide:将文件拖放到 QListWidget
【发布时间】:2014-10-25 12:33:11
【问题描述】:

这是我在这里的第一个条目,对于任何新手的错误,我们深表歉意。在发布之前,我在这里和谷歌都搜索过,但都没有运气。

我希望能够通过从文件浏览器中拖放来将图像添加到 QListWidget。在列表小部件上放置一个有效文件还需要触发我的应用程序主类中的一个函数,并将图像路径传递给它。

我发现 this code 正是这样做的,但对于 PyQt4。在触发拖放事件时,从 PySide 而不是 PyQt4 导入 QtCore 和 QtGui 会产生分段错误。没有错误消息。

我想我已经找到了一种处理信号的旧方式,并尝试使用here 描述的新的、更 Python 的方式。我似乎无法让它工作,但仍然在类之间传递一个 URL 列表。

任何帮助将不胜感激!

import sys
import os
from PyQt4 import QtGui, QtCore

class TestListView(QtGui.QListWidget):
    def __init__(self, type, parent=None):
        super(TestListView, self).__init__(parent)
        self.setAcceptDrops(True)
        self.setIconSize(QtCore.QSize(72, 72))

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

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

    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.ignore()

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

        self.view = TestListView(self)
        self.connect(self.view, QtCore.SIGNAL("dropped"), self.pictureDropped)
        self.setCentralWidget(self.view)

    def pictureDropped(self, l):
        for url in l:
            if os.path.exists(url):
                print(url)                
                icon = QtGui.QIcon(url)
                pixmap = icon.pixmap(72, 72)                
                icon = QtGui.QIcon(pixmap)
                item = QtGui.QListWidgetItem(url, self.view)
                item.setIcon(icon)        
                item.setStatusTip(url)        

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

if __name__ == '__main__':
    main()

【问题讨论】:

    标签: python drag-and-drop pyqt pyside qlistwidget


    【解决方案1】:

    了解 PySide 信号最终是如何工作的。这是上面的 PyQt4 代码,移植到 PySide。我很想知道是否有更好的解决方案。

    import sys
    import os
    from PySide import QtGui, QtCore
    
    class TestListView(QtGui.QListWidget):
    
        fileDropped = QtCore.Signal(list)
    
        def __init__(self, type, parent=None):
            super(TestListView, self).__init__(parent)
            self.setAcceptDrops(True)
            self.setIconSize(QtCore.QSize(72, 72))
    
        def dragEnterEvent(self, event):
            if event.mimeData().hasUrls:
                event.accept()
            else:
                event.ignore()
    
        def dragMoveEvent(self, event):
            if event.mimeData().hasUrls:
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
            else:
                event.ignore()
    
        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.fileDropped.emit(links)
            else:
                event.ignore()
    
    class MainForm(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainForm, self).__init__(parent)
    
            self.view = TestListView(self)
            self.view.fileDropped.connect(self.pictureDropped)
            self.setCentralWidget(self.view)
    
        def pictureDropped(self, l):
            for url in l:
                if os.path.exists(url):
                    print(url)                
                    icon = QtGui.QIcon(url)
                    pixmap = icon.pixmap(72, 72)                
                    icon = QtGui.QIcon(pixmap)
                    item = QtGui.QListWidgetItem(url, self.view)
                    item.setIcon(icon)        
                    item.setStatusTip(url)        
    
    def main():
        app = QtGui.QApplication(sys.argv)
        form = MainForm()
        form.show()
        app.exec_()
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

    • 嗨@thimic 我知道这篇文章很旧,但这对我来说效果很好,但我不太明白它是如何工作的,你知道我可以通过的很好的解释视频或文档吗更好地理解它?
    • 嗨@JodyStocks,这里有一个PySide 和信号和槽的例子:zetcode.com/gui/pysidetutorial/eventsandsignals 或者如果你有什么特别的问题,我会尽力帮助回答。
    • 嗨@thimic 所以我一直在努力更好地理解这一点,但我有点挣扎。我正确触发了 Drop 事件,但是当它触发时,我的 QListWidget 中的项目的实际移动没有移动。如果我将我的表变量设置为普通的 QListWidget() ,那么项目会移动并更新位置。有没有办法像点击按钮一样触发事件?
    • 嗨@JodyStocks,我不太确定QListWidget 中的项目不动是什么意思。您是否希望能够从外部将文件拖到小部件上并在内部重新排列小部件中的项目?
    • @JodyStocks,至于另一个问题,有两个概念在起作用。事件是一个,信号和插槽是另一个。 Qt 中的交互会触发事件,这些事件可以通过实现某些方法来处理,例如 dropEvent()。另外,可以使用信号和插槽设置小部件之间的通信,例如“fileDropped”和“clicked”。这个答案更详细地解释了差异:stackoverflow.com/a/3794944/3996477
    【解决方案2】:

    对我来说,这很好用(在 PySide2 和 PyQt5 上测试过)。 这不是丢弃信号,而是当 QListWidget 的行被移动时的信号。就我而言,这总是在掉落后发生。

    self.window.my_list_widget.model().rowsMoved.connect(self.my_method)
    

    【讨论】:

      【解决方案3】:

      我对@thimic 的代码做了一些修改,让它可以在我的电脑上运行:

      import sys
      import os
      from PyQt5.QtWidgets import *
      from PyQt5.QtGui import *
      from PyQt5.QtCore import *
      
      class TestListView(QListWidget):
      
      
          def __init__(self, type, parent=None):
              super(TestListView, self).__init__(parent)
              self.setAcceptDrops(True)
              self.setIconSize(QtCore.QSize(72, 72))
      
          def dragEnterEvent(self, event):
              if event.mimeData().hasUrls:
                  event.accept()
              else:
                  event.ignore()
      
          def dragMoveEvent(self, event):
              if event.mimeData().hasUrls:
                  event.setDropAction(Qt.CopyAction)
                  event.accept()
              else:
                  event.ignore()
      
          def dropEvent(self, event):
              if event.mimeData().hasUrls:
                  event.setDropAction(Qt.CopyAction)
                  event.accept()
                  links = []
                  for url in event.mimeData().urls():
                      links.append(str(url.toLocalFile()))
                  print('Has drop Event! ')
              else:
                  event.ignore()
      
      class MainForm(QMainWindow):
          def __init__(self, parent=None):
              super(MainForm, self).__init__(parent)
      
              self.view = TestListView(self)
              self.view.fileDropped.connect(self.pictureDropped)
              self.setCentralWidget(self.view)
      
          def pictureDropped(self, l):
              for url in l:
                  if os.path.exists(url):
                      print(url)
                      icon = QtGui.QIcon(url)
                      pixmap = icon.pixmap(72, 72)
                      icon = QtGui.QIcon(pixmap)
                      item = QtGui.QListWidgetItem(url, self.view)
                      item.setIcon(icon)
                      item.setStatusTip(url)
      
      def main():
          app = QApplication(sys.argv)
          form = MainForm()
          form.show()
          app.exec_()
      
      if __name__ == '__main__':
          main()
      

      【讨论】:

      • 如果您解释一下您需要更改的内容和原因,将会对社区有所帮助。
      猜你喜欢
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 2016-12-06
      • 2020-10-10
      • 2016-08-05
      • 2014-01-04
      • 1970-01-01
      • 2011-10-21
      相关资源
      最近更新 更多