Wie kann ich auf einen internen Drag-and-Drop-Vorgang reagieren, um eine QListWidget mit?

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

  •  11-07-2019
  •  | 
  •  

Frage

Ich habe eine Qt4-Anwendung, (unter Verwendung der PyQt-Bindungen), die eine QListWidget enthält, initialisiert wie folgt:

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

Ich kann Elemente hinzufügen, und dies ermöglicht es mir, um die Liste per Drag & Drop neu anordnen. Aber wie bekomme ich Benachrichtigung, wenn die Liste durch den Benutzer neu geordnet wird? Ich habe versucht, eine dropMimeData(self, index, data, action) Methode zur Klasse hinzufügen, aber es wird nie genannt.

War es hilfreich?

Lösung

Ich habe gerade damit umgehen und es ist ein Schmerz im Arsch, aber hier ist was zu tun ist:

Sie haben eine eventFilter auf ListWidget Unterklasse installieren und dann für das ChildRemoved Ereignis zu beobachten. Dieses Ereignis umfasst bewegt sowie die Entfernung, so sollte es für Neuanordnung Elemente per Drag & Drop in einer Liste arbeiten.

Ich schreibe meine Qt in C ++, aber hier ist eine pythonification Version:

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

Wenn Sie eine andere Klasse, die diese Liste enthält, sollten Sie die Ereignisfilter-Methode dort bewegen. Hoffe, das hilft, ich weiß, dass ich mit dieser für einen Tag zu kämpfen hatte, bevor diese aus Bezifferung.

Andere Tipps

Ich habe einen einfacheren Weg. :)

Sie können tatsächlich die interne Modell listwidget Zugriff mit myList->model() -. Und von dort gibt es viele Signale verfügbar

Wenn Sie nur über Drag & Drop sorgen, eine Verbindung zu layoutChanged. Wenn Sie Bewegungstasten haben (die in der Regel mit Entfernen implementiert + hinzufügen) verbindet auch rowsInserted.

Wenn Sie wissen wollen, was bewegt, rowsMoved könnte besser sein, als layoutChanged.

fand ich Trey Stout Antwort aber tat Arbeit, die ich war offensichtlich, Ereignisse, wenn die Liste geändert, um nicht wirklich war. Ich wandte mich an Chani Antwort die Arbeit als erforderlich macht, aber ohne Code es hat mich ein wenig Arbeit in Python zu implementieren.

Ich dachte, ich würde die Code-Schnipsel teilt zukünftige Besucher zu helfen:

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"

Dies ist in pyside getestet, aber keinen Grund sehen, wäre es nicht in PyQt arbeiten.

Nicht eine Lösung, aber einige Ideen:

Sie sollten wahrscheinlich überprüfen, was von supportedDropActions Methode zurückgegeben wird. Es könnte sein, dass Sie diese Methode überschreiben müssen, Qt :: MoveAction oder Qt :: CopyAction aufzunehmen.

Sie haben QListView :: indexesMoved Signal, aber ich bin nicht sicher, ob es wird ausgesendet werden, wenn Sie QListWidget verwenden. Es lohnt sich zu überprüfen.

Ich weiß, das ist alt, aber ich konnte meinen Code an der Arbeit Trey Antwort mit und wollte meine Python-Lösung teilen. Dies ist für eine QListWidget in einem QDialog, nicht eine, die Unter eingestuft ist.

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

Der QListWidget.model() Ansatz schien die eleganteste der vorgeschlagenen Lösungen, aber nicht für mich in PyQt5 arbeiten. Ich weiß nicht, warum, aber vielleicht etwas verändert in Bewegung zu QT5. Der eventFilter Ansatz funktioniert, aber es ist eine weitere Alternative, die eine Überlegung wert: über Reiten das QDropEvent und prüfen, ob event.source Selbst. Sehen Sie den Code unter dem sich ein MVCE mit allen vorgeschlagenen Lösungen zur Überprüfung in PyQt5 codiert:

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_())
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top