2017-01-11 1 views
3

현재 Python 프로그램에서 드래그 앤 드롭으로 항목을 한 QListWidget에서 다른 항목으로 이동하려고합니다.QListWidgets 사이의 Drag'N'Drop 사용자 정의 위젯 항목

나는 이것을 thread으로 읽고 설명 된대로 끌어서 놓기를 구현했습니다. 표준 QListWidgetItems와 함께 작동합니다. 문제는, QListWidgetItems 내에서이 사용자 정의 위젯을 수행하고, 설명 된대로 here으로 1 개의 QListWidgetItem에 아이콘과 여러 줄을 저장하고 싶습니다.

그래서 항목을 다른 목록으로 끌어다 놓으면 ItemWidget없이 QListWidgetItem을 이동/복사하는 것처럼 보이기 때문에 항목이 비어 있습니다.

Heres는 예제 코드 :

from PyQt4 import QtGui, QtCore 
    import sys, os 

    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) 


    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.myQListWidget = ThumbListWidget(self) 

      myBoxLayout.addWidget(self.myQListWidget) 

      for index, name, icon in [ 
       ('No.1', 'Meyoko', 'icon.png'), 
       ('No.2', 'Nyaruko', 'icon.png'), 
       ('No.3', 'Louise', 'icon.png')]: 
       # Create QCustomQWidget 
       myQCustomQWidget = QCustomQWidget() 
       myQCustomQWidget.setTextUp(index) 
       myQCustomQWidget.setTextDown(name) 
       myQCustomQWidget.setIcon(icon) 
       # Create QListWidgetItem 
      myQListWidgetItem = QtGui.QListWidgetItem(self.myQListWidget) 
      # Set size hint 
      myQListWidgetItem.setSizeHint(myQCustomQWidget.sizeHint()) 
      # Add QListWidgetItem into QListWidget 
      self.myQListWidget.addItem(myQListWidgetItem) 
      self.myQListWidget.setItemWidget(myQListWidgetItem, myQCustomQWidget) 

     self.listWidgetB = ThumbListWidget(self) 
     myBoxLayout.addWidget(self.listWidgetB) 


class QCustomQWidget (QtGui.QWidget): 
    def __init__ (self, parent = None): 
     super(QCustomQWidget, self).__init__(parent) 
     self.textQVBoxLayout = QtGui.QVBoxLayout() 
     self.textUpQLabel = QtGui.QLabel() 
     self.textDownQLabel = QtGui.QLabel() 
     self.textQVBoxLayout.addWidget(self.textUpQLabel) 
     self.textQVBoxLayout.addWidget(self.textDownQLabel) 
     self.allQHBoxLayout = QtGui.QHBoxLayout() 
     self.iconQLabel  = QtGui.QLabel() 
     self.allQHBoxLayout.addWidget(self.iconQLabel, 0) 
     self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1) 
     self.setLayout(self.allQHBoxLayout) 
     # setStyleSheet 
     self.textUpQLabel.setStyleSheet(''' 
      color: rgb(0, 0, 255); 
     ''') 
     self.textDownQLabel.setStyleSheet(''' 
      color: rgb(255, 0, 0); 
     ''') 

    def setTextUp (self, text): 
     self.textUpQLabel.setText(text) 

    def setTextDown (self, text): 
     self.textDownQLabel.setText(text) 

    def setIcon (self, imagePath): 
     self.iconQLabel.setPixmap(QtGui.QPixmap(imagePath)) 


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

그래서 기본적인 질문은 : 드래그 앤 드롭을 사용하는 동안 내가 항목 ItemWidget을 전송할 수있는 방법.

QListView를 이런 식으로 사용하는 것이 더 좋을까요?

+1

이 작업을 수행 할 수 없습니다. 드래그 앤 드롭 중에 Item의 데이터와 플래그를 직렬화해야하며'QWidget'을 직렬화 할 방법이 없습니다 ([Qt 데이터 유형 직렬화] (https://doc.qt.io/qt-4.8/ 참조). datastreamformat.html)). [이 관련 질문] (http://stackoverflow.com/q/40413221/984421)도 참조하십시오. – ekhumoro

+0

대답은 내가 원했던 것이지만 기대했던 것이었다. :) QWidget을 목록에서 다시 읽지 못했습니다. 지금은 드래그 앤 드롭 한 항목을 다시 만들었습니다. 내일 QListView를 사용해 보겠습니다. – JohnnyKonfetti

+1

'QListWidget' 클래스 **는 ** QListView입니다. 따라서 아무런 차이가 없습니다. 끌어서 놓기 메커니즘은 Qt에서 동일하므로 동일한 제한이 적용됩니다. 왜 항목에 데이터로 위젯을 저장해야합니까? 왜 위젯에 대한 참조를 보유하고있는 사전에 키를 저장하지 않는가? – ekhumoro

답변

2

위의 주석에서 설명한 것처럼 위젯을 직렬화 할 방법이 없으므로 드래그 앤 드롭을 통해 전송할 수 없습니다. 그러나 항목의 setData 메서드를 사용하여 항목의 위젯을 다시 만드는 데 필요한 데이터를 저장할 수 있습니다. 구현하기가 훨씬 간단합니다. 목록 위젯 모델의 rowsInserted 신호를 사용하여 항목이 삽입 될 때마다 자동으로 새 위젯을 추가 할 수 있기 때문입니다.

아래에 표시된 스크립트는 각 목록 위젯으로 여러 항목 끌어서 놓기를 처리 할 수 ​​있습니다. 드래그/드롭 * 이벤트 메소드는 더 이상 필요하지 않으며 더 이상 사용자 정의 위젯을 명시 적으로 설정할 필요가 없습니다.

from PyQt4 import QtGui, QtCore 
import sys, os 

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.setDefaultDropAction(QtCore.Qt.MoveAction) 
     self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) 
     self.setAcceptDrops(True) 
     self.model().rowsInserted.connect(
      self.handleRowsInserted, QtCore.Qt.QueuedConnection) 

    def handleRowsInserted(self, parent, first, last): 
     for index in range(first, last + 1): 
      item = self.item(index) 
      if item is not None and self.itemWidget(item) is None: 
       index, name, icon = item.data(QtCore.Qt.UserRole) 
       widget = QCustomQWidget() 
       widget.setTextUp(index) 
       widget.setTextDown(name) 
       widget.setIcon(icon) 
       item.setSizeHint(widget.sizeHint()) 
       self.setItemWidget(item, widget) 

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.myQListWidget = ThumbListWidget(self) 

     myBoxLayout.addWidget(self.myQListWidget) 

     for data in [ 
      ('No.1', 'Meyoko', 'icon.png'), 
      ('No.2', 'Nyaruko', 'icon.png'), 
      ('No.3', 'Louise', 'icon.png')]: 
      myQListWidgetItem = QtGui.QListWidgetItem(self.myQListWidget) 
      # store the data needed to create/re-create the custom widget 
      myQListWidgetItem.setData(QtCore.Qt.UserRole, data) 
      self.myQListWidget.addItem(myQListWidgetItem) 

     self.listWidgetB = ThumbListWidget(self) 
     myBoxLayout.addWidget(self.listWidgetB) 

class QCustomQWidget (QtGui.QWidget): 
    def __init__ (self, parent = None): 
     super(QCustomQWidget, self).__init__(parent) 
     self.textQVBoxLayout = QtGui.QVBoxLayout() 
     self.textUpQLabel = QtGui.QLabel() 
     self.textDownQLabel = QtGui.QLabel() 
     self.textQVBoxLayout.addWidget(self.textUpQLabel) 
     self.textQVBoxLayout.addWidget(self.textDownQLabel) 
     self.allQHBoxLayout = QtGui.QHBoxLayout() 
     self.iconQLabel  = QtGui.QLabel() 
     self.allQHBoxLayout.addWidget(self.iconQLabel, 0) 
     self.allQHBoxLayout.addLayout(self.textQVBoxLayout, 1) 
     self.setLayout(self.allQHBoxLayout) 
     # setStyleSheet 
     self.textUpQLabel.setStyleSheet(''' 
      color: rgb(0, 0, 255); 
     ''') 
     self.textDownQLabel.setStyleSheet(''' 
      color: rgb(255, 0, 0); 
     ''') 

    def setTextUp (self, text): 
     self.textUpQLabel.setText(text) 

    def setTextDown (self, text): 
     self.textDownQLabel.setText(text) 

    def setIcon (self, imagePath): 
     self.iconQLabel.setPixmap(QtGui.QPixmap(imagePath)) 

if __name__ == '__main__': 

    app = QtGui.QApplication(sys.argv) 
    dialog_1 = Dialog_01() 
    dialog_1.show() 
    dialog_1.resize(480,320) 
    app.exec_() 
+0

예를 들어 주셔서 감사합니다. 그것은 매력처럼 작동합니다! 그러나, 빠른 노트 : Python 2에서는 "handleRowsInserted"함수의 QVariant를 .toPyObject()를 사용하여 PyObject로 변환하여 원본 데이터를 가져와야합니다. 그렇지 않으면 예외를 던집니다 "QVariant not iterable" – JohnnyKonfetti

+0

그리고 다시, 도와 줘서 고마워! – JohnnyKonfetti