كيف يمكنني الرد على عملية السحب والإفلات الداخلية باستخدام QListWidget؟

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

  •  11-07-2019
  •  | 
  •  

سؤال

ولقد حصلت على تطبيق QT4 (باستخدام الارتباطات باي كيوت) الذي يحتوي على QListWidget، تهيئة مثل ذلك:

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

ويمكنني أن أضيف البنود، وهذا يتيح لي الفرصة لسحب وإسقاط لإعادة ترتيب القائمة. ولكن كيف يمكنني الحصول على إخطار عندما يحصل على إعادة ترتيب قائمة من قبل المستخدم؟ حاولت إضافة طريقة dropMimeData(self, index, data, action) إلى فئة، لكنه لم يحصل على استدعاء.

هل كانت مفيدة؟

المحلول

وكان لي فقط للتعامل مع هذا وانها الألم في المؤخرة ولكن لماذا تفعل هنا:

لديك لتثبيت eventFilter على فئة فرعية ListWidget الخاصة بك ومن ثم مشاهدة لهذا الحدث ChildRemoved. يغطي هذا الحدث تحركات وكذلك إزالة، لذلك يجب أن تعمل لبنود إعادة ترتيب مع السحب والإسقاط داخل القائمة.

وأنا أكتب لي كيو تي في 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

إذا كان لديك بعض الطبقة الأخرى التي تحتوي على هذه القائمة، قد ترغب في نقل أسلوب تصفية حدث هناك. ويساعد هذا الأمل، وأنا أعلم أن للقتال مع هذا ليوم واحد قبل كشف ذلك.

نصائح أخرى

ولدي طريقة أسهل. :)

ويمكنك الوصول فعلا نموذج الداخلي listwidget مع myList->model() - ومن هناك وهناك الكثير من الإشارات المتاحة

إذا كنت تهتم فقط عن السحب والإسقاط، الاتصال layoutChanged. إذا كان لديك أزرار الخطوة (التي تنفذ عادة مع إزالة + إضافة) الاتصال rowsInserted جدا.

إذا كنت تريد أن تعرف ما انتقلت، قد يكون أفضل من rowsMoved layoutChanged.

ولقد وجدت الجواب تري ستاوت في فعل العمل ولكن أنا كان من الواضح الحصول الأحداث عندما يكون النظام قائمة لم تتغير في الواقع. والتفت إلى شاني في الإجابة حيث يعمل كما هو مطلوب ولكن مع أي رمز استغرق مني بقليل من الجهد لتنفيذ في بيثون.

واعتقدت انني سوف تتقاسم التعليمات البرمجية المتكررة لمساعدة الزوار في المستقبل:

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 ولكن لا أرى أي سبب انها لن تنجح في باي كيوت.

وليس حلا، ولكن بعض الأفكار:

وربما يجب عليك مراجعة ما تم إرجاعها بواسطة طريقة supportedDropActions. قد يكون من أن تحتاج إلى استبدال هذه الطريقة، لتشمل كيو تي :: MoveAction أو كيو تي :: CopyAction.

لديك إشارة QListView :: indexesMoved، لكني لست متأكدا ما إذا كان سيتم المنبعثة إذا كنت تستخدم QListWidget. انها تبلغ قيمته فحص.

وأعرف أن هذا هو القديم، لكني لم اكن قادرة على الحصول على قانون بلدي للعمل باستخدام الجواب تري وأردت أن تشاركونني حل الثعبان. هذا هو ل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

وهذا النهج QListWidget.model() يبدو أكثر أناقة من الحلول المقترحة لكنه لم يعمل بالنسبة لي في PyQt5. أنا لا أعرف لماذا، ولكن تغيرت ربما شيء في الانتقال إلى Qt5. لم النهج eventFilter العمل، ولكن هناك بديل آخر هو تستحق النظر: الإفراط في ركوب QDropEvent والتحقق إذا event.source هو النفس. راجع التعليمات البرمجية أدناه وهو 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_())
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top