qlistwidget을 사용하여 내부 드래그 앤 드롭 작업에 어떻게 응답합니까?

StackOverflow https://stackoverflow.com/questions/1224432

  •  11-07-2019
  •  | 
  •  

문제

QT4 응용 프로그램 (PYQT 바인딩 사용)이 포함되어 있습니다. QListWidget, 그렇게 초기화 :

class MyList(QtGui.QListWidget):
    def __init__(self):
        QtGui.QListWidget.__init__(self)
        self.setDragDropMode(self.InternalMove)

항목을 추가 할 수있어서 목록을 다시 주문하기 위해 드래그 앤 드롭 할 수 있습니다. 그러나 사용자가 목록을 재정렬 할 때 알림을 얻으려면 어떻게해야합니까? 나는 추가를 시도했다 dropMimeData(self, index, data, action) 수업에 대한 방법이지만 결코 호출되지 않습니다.

도움이 되었습니까?

해결책

나는 단지 이것을 다루어야했고 그것은 엉덩이의 고통이지만 여기에해야 할 일이 있습니다.

당신은 설치해야합니다 eventFilter 너의 ListWidget 서브 클래스를 지켜보고 ChildRemoved 이벤트. 이 이벤트는 이동뿐만 아니라 제거를 다루므로 목록 내부에 드래그 앤 드롭이있는 항목을 다시 조절하는 데 작동해야합니다.

QT를 C ++로 작성하지만 여기에는 파이터 화 버전이 있습니다.

class MyList(QtGui.QListWidget):
    def __init__(self):
        QtGui.QListWidget.__init__(self)
        self.setDragDropMode(self.InternalMove)
        self.installEventFilter(self)

    def eventFilter(self, sender, event):
        if (event.type() == QEvent.ChildRemoved):
            self.on_order_changed()
        return False # don't actually interrupt anything

    def on_order_changed(self):
        # do magic things with our new-found knowledge

이 목록이 포함 된 다른 클래스가있는 경우 이벤트 필터 메소드를 이동할 수 있습니다. 이것이 도움이되기를 바랍니다. 나는 이것을 알아 내기 전에 하루 동안 이것과 싸워야한다는 것을 알고 있습니다.

다른 팁

더 쉬운 방법이 있습니다. :)

실제로 ListWidget의 내부 모델에 액세스 할 수 있습니다. myList->model() - 그리고 거기에서 많은 신호가 있습니다.

드래그 앤 드롭에 관심이 있다면 layoutChanged. 이동 버튼이있는 경우 (일반적으로 제거+추가로 구현 됨) 연결 rowsInserted 도.

무슨 일이 있었는지 알고 싶다면 rowsMoved 보다 낫다 layoutChanged.

나는 찾았다 Trey Stout의 답변 그러나 일을했지만 목록 순서가 실제로 변경되지 않았을 때 분명히 이벤트를 받고있었습니다. 나는 돌렸다 Chani의 대답 필요에 따라 작동하지만 코드가 없으면 Python에서 구현하는 데 약간의 작업이 필요했습니다.

미래의 방문객을 돕기 위해 코드 스 니펫을 공유 할 것이라고 생각했습니다.

class MyList(QListWidget):
    def __init__(self):
        QListWidget.__init__(self)
        self.setDragDropMode(self.InternalMove)
        list_model = self.model()
        list_model.layoutChanged.connect(self.on_layout_changed)

    def on_layout_changed(self):
        print "Layout Changed"

이것은 파이 사이드에서 테스트되지만 PYQT에서는 작동하지 않을 이유가 없습니다.

해결책이 아니라 일부 아이디어 :

supportedDropactions 메소드로 반환 된 내용을 확인해야 할 것입니다. qt :: moveaction 또는 qt :: 복사를 포함시키기 위해 해당 메소드를 덮어 쓰야 할 수도 있습니다.

qlistView :: IndexSmoved Signal이 있지만 QlistWidget을 사용하는 경우 방출되는지 확실하지 않습니다. 확인하는 가치가 있습니다.

나는 이것이 오래된 것을 알고 있지만 Trey의 답변을 사용하여 코드를 작동시킬 수 있었고 파이썬 솔루션을 공유하고 싶었습니다. 이것은 a입니다 QListWidget 내부 a QDialog, 하위 클래스가 아닌 것은 아닙니다.

class NotesDialog(QtGui.QDialog):
    def __init__(self, notes_list, notes_dir):
        QtGui.QDialog.__init__(self)
        self.ui=Ui_NotesDialog()
        # the notesList QListWidget is created here (from Qt Designer)
        self.ui.setupUi(self) 

        # install an event filter to catch internal QListWidget drop events
        self.ui.notesList.installEventFilter(self)

    def eventFilter(self, sender, event):
        # this is the function that processes internal drop in notesList
        if event.type() == QtCore.QEvent.ChildRemoved:
            self.update_views() # do something
        return False # don't actually interrupt anything

그만큼 QListWidget.model() 접근 방식은 제안 된 솔루션 중 가장 우아한 것처럼 보였지만 PYQT5에서는 저에게 효과가 없었습니다. 왜 그런지 모르겠지만 아마도 QT5로 이동할 때 무언가가 바뀌었을 것입니다. 그만큼 eventFilter 접근 방식은 효과가 있었지만 고려해야 할 또 다른 대안이 있습니다. PYQT5를 확인하기 위해 코딩 된 모든 제안 된 솔루션이있는 MVCE의 아래 코드를 참조하십시오.

import sys
from PyQt5 import QtGui, QtWidgets, QtCore


class MyList(QtWidgets.QListWidget):
    itemMoved = QtCore.pyqtSignal()

    def __init__(self):
        super(MyList, self).__init__()
        self.setDragDropMode(self.InternalMove)
        list_model = self.model()
        # list_model.layoutChanged.connect(self.onLayoutChanged)  # doesn't work
        # self.installEventFilter(self)  # works
        self.itemMoved.connect(self.onLayoutChanged)  # works

    def onLayoutChanged(self):
        print("Layout Changed")

    def eventFilter(self, sender, event):
        """
        Parameters
        ----------
        sender : object
        event : QtCore.QEvent
        """
        if event.type() == QtCore.QEvent.ChildRemoved:
            self.onLayoutChanged()
        return False

    def dropEvent(self, QDropEvent):
        """
        Parameters
        ----------
        QDropEvent : QtGui.QDropEvent
        """

        mime = QDropEvent.mimeData()  # type: QtCore.QMimeData
        source = QDropEvent.source()

        if source is self:
            super(MyList, self).dropEvent(QDropEvent)
            self.itemMoved.emit()


app = QtWidgets.QApplication([])
form = MyList()
for text in ("one", "two", "three"):
    item = QtWidgets.QListWidgetItem(text)
    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
    item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
    item.setCheckState(QtCore.Qt.Checked)
    form.addItem(item)

form.show()
sys.exit(app.exec_())
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top