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

QListWidget index of last inserted row



  • Hi,

    I have a simple list with plain text entries and I'd like to offer the ability to add, remove end edit entries in that list. For these simple features, I don't really like to create a QListView with a complex model. Instead, I'd like to use a QListWidget.

    When the user clicks the Add-Button, a new list entry is created with a default text. The aim now is, that this recently added item should immediatelly change to edit mode to allow renaming of the item.

    This is my code:

    this->lwNames = new QListWidget;
    this->lwNames->setSelectionMode(QAbstractItemView::SingleSelection);
    this->lwNames->setSortingEnabled(false);
    
    connect(this->lwNames, &QListWidget::currentRowChanged, [this]() -> void {
    this->pbRemove->setEnabled(this->lwNames->currentRow() >= 0);
    this->pbEdit->setEnabled(this->lwNames->currentRow() >= 0); return;});
    
    connect(this->cbSortMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this->cbSortMode, [this]() -> void {
    if(this->cbSortMode->currentIndex() > 0)
        this->lwNames->sortItems(this->cbSortMode->currentIndex() == 1 ? Qt::AscendingOrder : Qt::DescendingOrder);
    this->lwNames->setSortingEnabled(this->cbSortMode->currentIndex() > 0); return;});
    
    connect(this->pbAdd, &QPushButton::clicked, this->lwNames, [this]() -> void {
    this->lwNames->addItem(">>new item<<");
    this->lwNames->item(this->lwNames->count() - 1)->setFlags(this->lwNames->item(this->lwNames->count() - 1)->flags() | Qt::ItemIsEditable);
    this->lwNames->setCurrentRow(this->lwNames->count() - 1);
    this->lwNames->editItem(this->lwNames->currentItem()); return;});
    
    connect(this->pbRemove, &QPushButton::clicked, this->lwNames, [this]() -> void {
    delete this->lwNames->takeItem(this->lwNames->currentRow()); return;});
    
    connect(this->pbEdit, &QPushButton::clicked, this->lwNames, [this]() -> void {
    this->lwNames->editItem(this->lwNames->currentItem()); return;});
    

    This stuff works well if No sorting is selected in the QComboBox (not shown in the code above). But if the user chooses sorting (e. g. ascending order), the recently added item is, due to its default value, automatically reordered elsewhere, so the code above edits the wrong item (it always edits the last item in the list).

    So, I was looking for a possibility to catch the index to the last row that was inserted. My google research linked me to QAbstractItemView::rowsInserted(const QModelIndex&, int, int), but there is one ugly problem: it is a protected member!

    So my question is: Is there still any way to get this information of the last inserted row by using a QListWidget or do I really have to use a complete Model/View approach with subclassing QListView just to get access to this function?

    Thank you in anticipation!
    Binary


  • Qt Champions 2019

    @Binary91-0 said in QListWidget index of last inserted row:

    This stuff works well if No sorting is selected in the QComboBox (not shown in the code above). But if the user chooses sorting (e. g. ascending order), the recently added item is, due to its default value, automatically reordered elsewhere, so the code above edits the wrong item (it always edits the last item in the list).

    Sadly it's not written in the QListWidget doc but in the other convenience class: QTableWidget

    Disable sorting, add item, do your stuff, re-enable sorting. Or use a proper own model.



  • I'm not sure the newly inserted index is the correct one after sorting, but if you only want the index from QAbstractItemView::rowsInserted, I think you can get it from QAbstractItemModel::rowsInserted.
    It is a signal, hence not protected. (Actually the QAbstractItemView::rowsInserted is usually connected to, or we can say triggered by, QAbstractItemModel::rowsInserted)
    You should be able to get a QAbstractItemModel pointer from QListWidget::model().



  • Thank you for your fast reply!

    @Christian-Ehrlicher Good to know, thank you for this hint.
    @Bonnie Oh nice! You are totally right, connecting my lambda to the model's rowsInserted signal is possible.

    I'm not sure the newly inserted index is the correct one after sorting
    

    It works fine! I could imagine that internally, QListWidget's insert-method checks if sorting is enabled or not and depending on that, the insertion is done. So the rowsInsertedsignal has the correct range data.

    If someone is interested in my approach:

    connect(this->lwNames->model(), &QAbstractItemModel::rowsInserted, this->lwNames->model(), [this] (const QModelIndex &index, int iStart, int iEnd) -> void {
    this->lwNames->item(iStart)->setFlags(this->lwNames->item(iStart)->flags() | Qt::ItemIsEditable);
    this->lwNames->setCurrentRow(iStart);
    this->lwNames->editItem(this->lwNames->item(iStart)); return;});
    

    I'm interested in any improvement suggestions.

    Thank you for your help.
    Binary


  • Qt Champions 2019

    @Binary91-0 said in QListWidget index of last inserted row:

    I'm interested in any improvement suggestions.

    It seems to work but you're relying on Qt internals so it may not work with other Qt versions.



  • @Christian-Ehrlicher You mean that in future versions, QListWidget may handle this in a different way so it may for example return an invalid or wrong row index for example? So you'd recommend to bether stop sorting for the moment of interaction? As I can't see any disadvantages, I think I'll do that and stop/restart sorting while inserting the row.


Log in to reply