Зачем щелкать элементы в qlistview, чтобы вернуть их в предыдущее состояние после перетаскивания?

Я реализовал перетаскивание, чтобы изменить порядок элементов в представлении списка, и все мои выходные данные отладки указывают, что это работает должным образом. Однако, когда я снова выбираю элемент, он возвращается к тому, что было раньше в представлении, и когда он становится невыбранным, это изменение также происходит в модели.
Пример:

                       Список представлений показывает Модель показывает
                         а, б, в, да, б, в, д
после перетаскивания b, c, d, ab, c, d, a
щелкнув по первому пункту a, c, d, ab, c, d, a
щелкнув по второму пункту a, b, d, aa, c, d, a
и т.п.

Надеюсь, это имеет смысл. Любые предложения, почему это может происходить? (пример кода сложен, так как это часть большого приложения)

Изменить: это лучшее, что я могу сделать для кода.

Настраиваемое представление списка (у меня есть настраиваемое представление списка, потому что оно должно излучать сигнал, когда элементы перемещаются, а indexesMoved кажется поврежденным):

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import traceback

class ListOrderView(QListView):

    itemMoved = pyqtSignal(int, int, QStandardItem) # Old index, new index, item 

    def __init__(self, parent=None):
        try:
            super(ListOrderView, self).__init__(parent)

            self.setAcceptDrops(True)
            self.setDragEnabled(True)
            self.setDragDropMode(QAbstractItemView.InternalMove)
            self.setDefaultDropAction(Qt.MoveAction)

            self.dragItem = None
            self.dragRow = None
        except:
            Trace2.WriteLine(str(traceback.format_exc())) #writes stuff to a log file

    def dropEvent(self, event): 
        try:
            super(ListOrderView, self).dropEvent(event) 

            self.itemMoved.emit(self.dragRow, self.row(self.dragItem), self.dragItem)
            self.dragItem = None
        except:
            Trace2.WriteLine(str(traceback.format_exc()))

    def startDrag(self, supportedActions): 
        try:
            self.dragItem = self.currentItem() 
            self.dragRow = self.row(self.dragItem) 
            super(ListOrderView, self).startDrag(Qt.MoveAction)
        except:
            Trace2.WriteLine(str(traceback.format_exc()))

    def currentItem(self):
        index = self.currentIndex()
        item = self.model().itemFromIndex(index)
        return item

    def row(self, item):
        index = self.selectedIndexes()[0]
        row = index.row()
        return row

Графический интерфейс, который его использует (просто форма с настраиваемым представлением списка, созданная в Qt Designer):

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from FormsUI.ListOrderControlUI import Ui_ListOrderControl

import traceback

class ListOrderControl(QWidget, Ui_ListOrderControl):
    def __init__(self, parent=None):
        super(ListOrderControl, self).__init__(parent)
        self.setupUi(self)

        self.model = QStandardItemModel()
        self.model.setSupportedDragActions(Qt.MoveAction)
        self.listOrderView.setModel(self.model) #the custom list view
        self.model.dataChanged.connect(self.onDataChanged)

    def addItem(self, string, select=False):
        item = QStandardItem(string)
        item.setDropEnabled(False)
        self.model.invisibleRootItem().appendRow(item)
        if select:
            self.listOrderView.selectionModel().setCurrentIndex(self.model.indexFromItem(item), QItemSelectionModel.ClearAndSelect)

    def setNewItem(self, row, item):
        self.model.setItem(row, item)

    def removeRows(self, row, count):
        self.model.removeRows(row, count)

    # This is here because items are becoming drop enabled when they become unselected.
    # No idea why.
    def onDataChanged(self, topLeft, bottomRight):
        try:
            i = topLeft.row()
            while i <= bottomRight.row():
                item = self.model.item(i)
                item.setDropEnabled(False)
                i+=1
        except:
            Trace2.WriteLine(str(traceback.format_exc()))

    def printModelContents(self):
        Trace2.WriteLine("[LISTCONTROL] item order is:")
        for i in range(self.model.rowCount()):
            Trace2.WriteLine("\t" + str(self.model.item(i).data(Qt.DisplayRole).toString()) + " dropEnabled = " + str(self.model.item(i).isDropEnabled()))

1 ответ

Оказывается, перетаскивание работало нормально. Сначала немного предыстории. Этот вид списка является частью пользовательского виджета, используемого в нескольких местах большого приложения. В этом конкретном месте нажатие на элемент в списке приводит к тому, что некоторые поля в родительском виджете включаются и заполняются информацией об этом элементе. Это делается на основе текущего выбора в представлении списка. Одним из полей является строка редактирования имени элемента. Когда его содержимое изменяется, оно автоматически обновляет имя своего элемента.

Это означает, что когда элемент перетаскивается, а выделение остается позади, содержимое редактирования строки изменяется, обновляя элемент, который теперь находится в том месте, где перетаскиваемый элемент находился в представлении, но не в модели до тех пор, пока через какое-то сигнал / слот вуду.

В конечном счете, это был ответ; заставить модель излучать сигнал со строкой, в которую был отброшен элемент, и обновлять / заполнять поля, основанные на этом, вместо модели выбора.

Другие вопросы по тегам