How to erase specific row from QListWidget

Viewed 47

I have a small ui with 1 QListWidget. In this uithere is a predefined row in the QListWidget called "Add New".

I drag and drop several files from a folder into a QListWidget. So there are all my files plus the "Add New" record.

The "Add Record" is used as a doubleClick to create a New File and store it both in the QListWidget and in the local folder of the computer.

The problem is that when I erase a specific record from the QListWidget, several files are erased together and I don't know why.

See below the steps:

  1. I launch the application:

enter image description here

  1. I drag and drop some files and I right click on the last one to erase it:

enter image description here

  1. As soon as I erase that, several other are also erased as shown below:

enter image description here

Below is the logic I used:

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QAction *remove;
    remove = new QAction(QIcon(":/icons/remove_item.png"), "Remove", this);
    QObject::connect(remove, SIGNAL(triggered()), this, SLOT(on_eraseBtn_clicked()));
    ui->listWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
    ui->listWidget->addAction(remove);
    setAcceptDrops(true);

     ui->listWidget->addItem("Add New");
     ui->listWidget->item(0)->setSelected(true);
}


void MainWindow::on_eraseBtn_clicked()
{
    for(int i = 0; i < ui->listWidget->count(); ++i)
    {
        QString str = ui->listWidget->item(i)->text();
        if (str != "Add New")
            delete ui->listWidget->item(i);
        qDebug() << ui->listWidget->item(i) << str;
    }
}

UPDATE

As proposed by @absolute.madeness, a whileloop could be used too. Not exactly the behavior but close. With the following loop, all the records (or row) of the QListwidget are erased with the exception of the row "Add New"

void MainWindow::on_eraseBtn_clicked()
{
    for(int i = 0; i < ui->listWidget->count(); ++i)
    {
        while(i < ui->listWidget->count() && ui->listWidget->item(i)->text() != "Add New")
            delete ui->listWidget->item(i);
    }
}

What I have done so far is:

  1. on the slot on_eraseBtn_clicked() I just added the line delete ui->listWidget->currentItem(); to see if at least the record was successfully erased. Which it was so I was sure that the slot was properly triggered.

  2. After that I did some research and the best approach was to loop through the all QListWidget and and as soon as the record with the QString Add New is found, please keep it and pass to the next record and erase it. This methodology is also described in this post. But for some reason more then one record is erased.

  3. I tried to do additional research and found this post

  4. I tried to delete by context as explained in this post.

Any other pointers you can suggest?

1 Answers

I originally wrote a for loop that was straightforward but I incurred in the problem to delete item(i) recursively. The next item previously accessed as item(i+1) will decrease by 1, creating a strange effect of erasing several rows unexpectedly. As proposed by @absolute.madeness, below the solution that avoids that. I hope other will benefit from this solution and don't get stuck wondering why a simple loop can create such unexpected issues:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    remove = new QAction(QIcon(":/icons/remove_item.png"), "Remove", this);
    QObject::connect(remove, SIGNAL(triggered()), this, SLOT(on_eraseBtn_clicked()));

// other operations in the constructor....
}


void MainWindow::on_eraseBtn_clicked()
{
    for(auto item: ui->listWidget->selectedItems())
        if(item->text() != "Add New") delete item;
}

This way the user selectively erase single rows in the QListWidget leaving only a specific row.

Related