Как мне ответить на внутреннюю операцию перетаскивания, используя QListWidget? - PullRequest
7 голосов
/ 04 августа 2009

У меня есть приложение Qt4 (использующее привязки PyQt), которое содержит QListWidget, инициализированный так:

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

Я могу добавлять предметы, и это позволяет мне перетаскивать и изменять порядок списка. Но как мне получить уведомление, когда список переупорядочивается пользователем? Я попытался добавить метод dropMimeData(self, index, data, action) в класс, но он никогда не вызывается.

Ответы [ 6 ]

12 голосов
/ 14 ноября 2012

У меня есть более простой способ. :)

На самом деле вы можете получить доступ к внутренней модели списка с помощью myList->model() - и оттуда доступно много сигналов.

Если вас интересует только перетаскивание, подключитесь к layoutChanged. Если у вас есть кнопки перемещения (которые обычно реализуются с помощью функции удаления + добавления), подключитесь также к rowsInserted.

Если вы хотите знать, что двигалось, rowsMoved может быть лучше, чем layoutChanged.

7 голосов
/ 07 октября 2009

Мне просто пришлось иметь дело с этим, и это задница, но вот что нужно сделать:

Вы должны установить eventFilter на свой подкласс ListWidget, а затем наблюдать за событием ChildRemoved. Это событие охватывает перемещения, а также удаление, поэтому оно должно работать для переупорядочения элементов с помощью перетаскивания внутри списка.

Я пишу свой Qt на C ++, но вот версия Pythonification:

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

Если у вас есть какой-то другой класс, содержащий этот список, вы можете переместить туда метод фильтра событий. Надеюсь, это поможет, я знаю, что мне пришлось бороться с этим в течение дня, прежде чем понять это.

5 голосов
/ 01 декабря 2012

Я нашел Ответ Трея Стаута сработал, однако я, очевидно, получал события, когда порядок списка фактически не изменился. Я обратился к ответу Чани , который работает как требуется, но без кода мне потребовалось немного усилий для реализации на 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"

Это проверено в PySide, но не вижу причин, по которым оно не будет работать в PyQt.

1 голос
/ 03 октября 2017

Подход QListWidget.model() казался самым элегантным из предложенных решений, но у меня не работал в PyQt5. Я не знаю почему, но, возможно, что-то изменилось в переходе на Qt5. Подход eventFilter сработал, но есть еще одна альтернатива, которую стоит рассмотреть: переопределение QDropEvent и проверка, является ли event.source self. Посмотрите код ниже, который является MVCE со всеми предложенными решениями, закодированными для проверки в 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_())
1 голос
/ 20 сентября 2012

Я знаю, что это старый, но я смог заставить свой код работать, используя ответ Трея, и хотел поделиться своим решением на python. Это для QListWidget внутри 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
1 голос
/ 05 августа 2009

Не решение, но некоторые идеи:

Вы, вероятно, должны проверить, что возвращается методом оказывает поддержкуDropActions. Возможно, вам нужно перезаписать этот метод, чтобы включить Qt :: MoveAction или Qt :: CopyAction.

У вас есть сигнал QListView :: indexesMoved, но я не уверен, будет ли он излучаться, если вы используете QListWidget. Стоит проверить.

...