2014-06-24 30 views
1

我遇到了一些試圖爲自定義QListWidgetItem實現拖放操作的poblems。下面是一些示例代碼:拖放子類QListWidgetItem

from PyQt4 import QtGui, QtCore 
import sys, os 


class MyListWidgetItem(QtGui.QListWidgetItem):  
    def __init__(self, label, data, parent=None): 
     super(QtGui.QListWidgetItem, self).__init__(label, parent=parent) 
     self.data = data 

    def GetData(self): 
     return self.data 

class MyListWidget(QtGui.QListWidget): 
    def __init__(self, type, parent=None): 
     super(MyListWidget, self).__init__(parent) 
     self.setDragDropMode(QtGui.QAbstractItemView.DragDrop) 
     self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) 
     self.setAcceptDrops(True) 
     self.viewport().setAcceptDrops(True) 
     self.setDropIndicatorShown(True) 

    def startDrag(self, supportedActions): 
     drag = QtGui.QDrag(self) 
     t = [i.GetData() for i in self.selectedItems()] 
     mimeData = self.model().mimeData(self.selectedIndexes()) 
     mimeData.setText(str(t)) 
     drag.setMimeData(mimeData) 
     if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction: 
      for item in self.selectedItems(): 
       self.takeItem(self.row(item)) 

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

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

    def dropEvent(self, event): 
     if event.mimeData().hasUrls(): 
      event.ignore() 
     if isinstance(event.source(), MyListWidget): 
      event.setDropAction(QtCore.Qt.MoveAction) 
      super(MyListWidget, self).dropEvent(event) 
     else: 
      event.ignore() 

    def dropMimeData(self, index, mimedata, action): 
     super(MyListWidget, self).dropMimeData(index, mimedata, action) 
     return True 

class Test(QtGui.QMainWindow): 
    def __init__(self): 
     super(QtGui.QMainWindow,self).__init__() 
     myQWidget = QtGui.QWidget() 
     myBoxLayout = QtGui.QVBoxLayout() 
     myQWidget.setLayout(myBoxLayout) 
     self.setCentralWidget(myQWidget) 

     self.listWidgetA = MyListWidget(self) 
     self.listWidgetB = MyListWidget(self) 

     for i in range(5): 
      listItemAInstance = MyListWidgetItem(str(i), i, parent=self.listWidgetA) 

     myBoxLayout.addWidget(self.listWidgetA)  
     myBoxLayout.addWidget(self.listWidgetB) 

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

我的自定義類MyListWidgetItem有這在我的真正的程序保存與該項目相關的一些信息的「數據」字段。如果您運行的代碼,並嘗試拖放從上面的列表項的底部有一個一切正常,但如果你再嘗試把他們帶回到頂端列表中,您收到此錯誤:

Traceback (most recent call last): 
    File "C:\Users\Massi\Desktop\t.py", line 23, in startDrag 
    t = [i.GetData() for i in self.selectedItems()] 
AttributeError: 'QListWidgetItem' object has no attribute 'GetData' 

似乎很明顯,默認的拖放行爲會忽略列表項已被分類,所以我想知道哪種方法最適合這種情況。任何幫助真的很感激。 在此先感謝!

+0

不應該是'getData',而不是'GetData'? – neuronet

回答

0

我會用一個QStandardItemModel一個QListView和使用QStandardItemModel.setItemPrototype(MyStandardItem())和定義MyStandardItem類似:

class MyStandardItem(QtGui.QStandardItem): 
    def __init__(self, *__args): 
     super().__init__(*__args) 

    def clone(self): 
     return MyStandardItem() 
0

如果你添加一些調試信息,如下面,你可以找出「我」已經是MyListWidgetItem,所以這不應該是問題。

def startDrag(self, supportedActions): 
     drag = QtGui.QDrag(self) 
     # add the following 2 line debug information 
     for item in self.selectedItems(): 
      print item.__class__.__name__ 
     t = [i.GetData() for i in self.selectedItems() if hasattr(i, "GetData")] 
     mimeData = self.model().mimeData(self.selectedIndexes()) 
     mimeData.setText(str(t)) 
     drag.setMimeData(mimeData) 
     if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction: 
      for item in self.selectedItems(): 
       self.takeItem(self.row(item)) 

輸出

MyListWidgetItem 

的問題是,你不能投的項目類型MyListWidgetItem,如Python不支持類型轉換,所以你需要使用反射機制來調用GetData ()方法,我剛剛嘗試過的代碼,它工作正常!