Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Update selected Item(index) after InternalMove in listview



  • I have two listviews, the left shows parent items and the right it's parents children.
    I would like the the children to be able to be rearranged with setDragDropMode(QAbstractItemView.InternalMove). This seems to work as expected. The issue is if I have an item selected and move it, the original row still stays selected. How can I update the moved index to the listview current item? I would expect the selection to move with the InternalMove behavoir.

    I've tried to implement the dropEvent() on the listview, but that was causing duplicate items. when I was using setCurrentIndex().

    I tried to catch the insertedRow signal and try the same thing with similar results. I guess I dont fully understand selections yet. I see the listview has a selectionModel, i have tried to something like
    self.selectionModel().setCurrentIndex(index, QtCore.QItemSelectionModel.Select)
    same results.

    Any help greatly appreciated!

    import sys
    from PySide2.QtCore import Qt, QSize
    from PySide2.QtWidgets import QMainWindow, QApplication, QStyledItemDelegate, QListView, QHBoxLayout, QWidget, QAbstractItemView,QStyle
    from PySide2.QtGui import QStandardItemModel, QStandardItem, QColor, QFont, QFontMetrics
    
    
    
    class CustomDelegate(QStyledItemDelegate):
        def __init__(self, parent=None):
            super(CustomDelegate, self).__init__(parent)
            self.text_title = QColor(109, 210, 240)
            self.text_description = QColor(120, 120, 120)
            self.cell_default = QColor(250, 250, 250)
    
    
        def paint(self, painter, option, index):
            current_item = index.model().itemFromIndex(index)
            value = current_item.text()
            x = option.rect.x()
            y = option.rect.y()
            h = option.rect.height()
            w = option.rect.width()
            painter.save()
            if option.state & QStyle.State_Selected:
                painter.fillRect(option.rect, self.text_description)
                painter.drawText(x+2, y+h-4, value)
    
            elif option.state & QStyle.State_MouseOver:
                painter.fillRect(option.rect, self.text_title)
                painter.drawText(x + 2, y + h -4 , value)
    
            else:
                QStyledItemDelegate.paint(self, painter, option, index)
    
            painter.restore()
    
    
    class MainWindow(QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.task_grp_view = QListView(self)
            self.task_view = QListView(self)
            self.task_view.setDragDropMode(QAbstractItemView.InternalMove)
            self.model = QStandardItemModel(self)
            self.task_grp_view.setModel(self.model)
            self.task_view.setModel(self.model)
            self.task_view.setItemDelegate(CustomDelegate())
            self.h_layout = QHBoxLayout(self)
            self.h_layout.addWidget(self.task_grp_view)
            self.h_layout.addWidget(self.task_view)
            self.cw = QWidget(self)
            self.cw.setLayout(self.h_layout)
            self.setCentralWidget(self.cw)
    
            self.task_grp_view.model().dataChanged.connect(self.update_user_data)
            self.task_grp_view.pressed.connect(self.update_task_view)
    
            self.populate_model()
    
        def populate_model(self):
            stuff = ['zero', 'one', 'two']
            for i, s in enumerate(stuff):
                item = QStandardItem(s)
                for sub in stuff:
                    sub_item = QStandardItem(str(i) + '_' + sub)
                    sub_item.setDropEnabled(False)
                    item.appendRow(sub_item)
                self.model.appendRow(item)
            self.task_grp_view.setCurrentIndex(self.model.index(0, 0))
            self.task_view.setRootIndex(self.task_grp_view.currentIndex())
    
        def update_task_view(self, index):
            self.task_view.setRootIndex(index)
    
        def update_user_data(self):
            pass
            # print('called')
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = MainWindow()
        window.show()
        sys.exit(app.exec_())
    


  • Hmm... im still a bit lost here.
    I've been trying to catch a signal from the view and the selection model after the interalMove.
    the signals from:
    task_view.selectionModel().currentRowChanged
    self.modelmodel.rowsInserted

    both give me a start and end index or to and from ints, but if I call the rowCount() on the parent item it returns one additional NULL row for the children. I'm thinking this is the model in the process of inserting a new row and hasn't updated yet. Regardless I cant seem to use the task_view selection Model to select the index (maybe its invalid?), the selection just stays on the row where the drag started.

    I'm just not sure where to grab the internalMove data and update AFTER the model sorts its self out.


Log in to reply