Search code examples
c++qtsignalsqtablewidgetqtablewidgetitem

Does Removing An Item From QTableWidget Deletes Object(s) Contained by The Item?


Qt 5.15.2 is used with C++ in the project that I am working on. Unfortunately, I could not find the event that triggers the deletion of an object?

What could trigger the lambda function given below?

auto deletionConnection = connect(myCustomQObject, &QWidget::deleted, [myCustomQObject, this, serverName] (){
            communicationDeleted(serverName);
    });

It is clear that when myCustomQObject object is deleted, the program execution enters inside of this lambda function. communicationDeleted(serverName) is another signal. But I couldnt find the event that deletes this myCustomQObject object. The code block that contains this connection is given below.

void myCustomTableWidget::addRow(const QString& serverName)
{
    myCustomQObject* newCustomQObject = new myCustomQObject(this);
    QWidget* newCellWidget = new QWidget();


    QHBoxLayout* rowLayout = new QHBoxLayout(newCellWidget);
    rowLayout->addWidget(myCustomQObject);

    newCellWidget->setLayout(rowLayout);

    m_ui->tableServers->insertRow(m_rowCount);
    m_ui->tableServers->setCellWidget(newCellWidget);

    auto deletionConnection = connect(myCustomQObject, &QWidget::deleted, [myCustomQObject, this, serverName] (){
            communicationDeleted(serverName);
    });

    m_->deletionConnections.pushBack(deletionConnection);
    ...
}

I suspected another slot myCustomTableWidget::deleteRow(qint32) cause deletion of the object. But if I have multiple items on the table and remove lets say three of them, the execution enters the breakpoint set in deleteRow(qint32) three times. Yet, I have seen that later in the process, the lambda is executed. Am I right that, removing a row from a table cause the item object to be deleted? Or should I focus on different place?

void myCustomTableWidget::deleteRow(qint32 rowIndex)
{
    m_ui->tableServers->removeRow(rowIndex);
    m_rowCount--;
}


Solution

  • In Qt's QTableWidget, setCellWidget() internally calls setIndexWidget() of QAbstractItemView. That in turn registers the widget as a 'static editor'.

    When any model items are removed in a Qt item view, the rowsAboutToBeRemoved() slot of QAbstractItemView is called. That in turn calls d->releaseEditor() on the widget. For static editors the releaseEditor() function calls editor->deleteLater() to actually delete the widget.

    All subclasses of QObject have a deleteLater() slot. The reason this exists is the following: suppose your widget is a push button, and you connect that push button's clicked() signal with a slot that removes the row the widget it. If an item view were to then just call delete widget; the widget would be deleted while its own event handler for the clicked() signal is still active. This will likely cause memory corruption, because you shouldn't delete objects that are still being used. Qt avoids these types problems by using deleteLater() in many places: objects are marked to be deleted, but only when control is given back to the event loop (i.e. the current event handler has exited), all objects marked for deletion in this manner are also removed, which is now safe to do, because the objects are no longer being used.

    (Btw. this is the reason why dialog.exec() and/or QApplication::processEvents() can be the cause of weird bugs in some cases.)