9
votes

Comment réagir à une opération interne de glisser-déposer à l'aide d'un QListWidget?

J'ai une application Qt4 (à l'aide des liaisons PYQT) qui contient un qlistwidget , initialisé comme: xxx

Je peux ajouter des éléments, et ceci Permet de faire glisser et déposer pour réorganiser la liste. Mais comment puis-je obtenir une notification lorsque la liste est réorganisée par l'utilisateur? J'ai essayé d'ajouter un dropmimedata (auto, index, données, action) méthode à la classe, mais elle n'est jamais appelée.


2 commentaires

La réponse de @chani (pas la réponse actuellement acceptée) est la solution la plus facile à cela.


Possible, je fais quelque chose de mais la réponse de @chani n'a pas fonctionné dans mon exemple pour PyqT5. La réponse acceptée a fonctionné de même que QdroPevent comme dans ma réponse ci-dessous


6 Réponses :


1
votes

Pas une solution, mais quelques idées:

Vous devriez probablement vérifier ce qui est renvoyé par la méthode supportée en prenant en charge. Il se peut que vous ayez besoin de remplacer cette méthode, d'inclure QT :: MOVEaction ou QT :: Copyaction.

Vous avez le signal QListView :: indexesMoved, mais je ne suis pas sûr que cela soit émis si vous utilisez qlistwidget. Ça vaut la peine de vérifier.


1 commentaires

Il existe un bogue connu dans Qt 4.5.x que le signal QListView :: indexesMoved ne tire jamais. Vous êtes obligé d'installer un evirfilter et de le gérer vous-même.



7
votes

Je viens de faire face à cela et que c'est une douleur dans le cul, mais voici quoi faire:

Vous devez installer un EventFilter code> sur votre listwidget code> Sous-classe et ensuite surveiller le événement code> enfant. Cet événement couvre des mouvements ainsi que la suppression, il devrait donc fonctionner pour réorganiser des éléments avec glisser-déposer dans une liste. P>

J'écris mon QT en C ++, mais voici une version Pythonification: P>

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


1 commentaires

Merci pour cela, j'ai mis en place le code dans Pyside et travaille bien.



1
votes

Je sais que c'est vieux, mais j'ai pu obtenir mon code pour travailler à l'aide de la réponse de Trey et je voulais partager ma solution Python. Ceci est pour un qlistwidget code> à l'intérieur d'un qdialog code>, pas celui qui est sous-classé.

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


0 commentaires

15
votes

J'ai un moyen plus facile. :)

Vous pouvez réellement accéder au modèle interne de ListWidget avec myList-> modèle () - et de là, il y a beaucoup de signaux disponibles.

Si vous ne vous souciez que de glisser-déposer, connectez-vous à layoutChanged . Si vous avez des boutons de déplacement (qui sont généralement implémentés avec Supprimer + Add), connectez-vous à RowinsERTED aussi.

Si vous voulez savoir ce que proposé, rowsmoved peut être meilleur que layoutchanged .


3 commentaires

Bienvenue sur Stackoverflow. Veuillez prendre quelques minutes pour savoir comment utiliser Mise en forme . Cela vous permettra de formater le code de code dans votre réponse et de rendre plus lisible pour tous les autres.


Les rowsmoved () ne peuvent pas émettre le signal ... J'ai testé ici, il ne saisit jamais la fente lorsque je déplace l'élément par glisser / goutte. mais article obtenez le changement de changement


Notez que le signal de cette réponse vous indique quels éléments ont été déplacés et où, tandis que le qevent.childremoved EventFilter dans la réponse acceptée ne le fait pas.



5
votes

J'ai trouvé La réponse de Trey STOUT a fonctionné cependant que j'avais évidemment des événements lorsque la commande de liste n'avait pas réellement changé. Je me suis tourné vers La réponse de Chani qui fonctionne comme requise mais sans code, il m'a fallu un peu de travail pour mettre en œuvre dans Python. < P> Je pensais que je partagerais l'extrait de code pour aider les futurs visiteurs: xxx

ceci est testé en pyside mais ne vois aucune raison pour laquelle il ne fonctionnerait pas dans Pyqt.


1 commentaires

J'ai testé cela dans Pyqt5, et sauf si je fais quelque chose de mal, cette approche ne fonctionne pas, voir la réponse ci-dessous



1
votes

Le qlistwidget.model () code> L'approche semblait le plus élégant des solutions proposées mais ne fonctionnait pas pour moi dans PYQT5. Je ne sais pas pourquoi, mais peut-être que quelque chose a changé en mouvement vers Qt5. L'approche EventFilter CODE> fonctionnait, mais une autre alternative mérite d'être envisagée: surmonter le QDropEvent et la vérification si l'événement est-il. Voir le code ci-dessous qui est un MVCE avec toutes les solutions proposées codées pour vérifier dans PYQT5:

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_())


0 commentaires