QTableWidget 单元格小部件在交换后消失

问题描述 投票:0回答:1

我有 3 列的 QTableWidget。第一列包含带有行名称的 QTableWidgetItem,另外两列包含两个单元格小部件。

我尝试使用以下代码交换表行:

connect(upButton, &QPushButton::clicked, this, [this, protectionWidget]()
    {
        int index = m_protectionWidgets->indexOf(protectionWidget);
        int upperIndex = index - 1;
        if (upperIndex >= 0)
        {
            QTableWidgetItem *nameItem = m_protectionsTable->takeItem(index, 0);
            ProtectionWidget *protectionWidgetCopy = protectionWidget;
            QWidget *buttons = m_protectionsTable->cellWidget(index, 2);

            QTableWidgetItem *upperNameItem = m_protectionsTable->takeItem(upperIndex, 0);
            ProtectionWidget *upperProtectionWidget = m_protectionWidgets->at(upperIndex);
            QWidget *upperButtons = m_protectionsTable->cellWidget(upperIndex, 2);

            m_protectionsTable->setItem(upperIndex, 0, nameItem);
            m_protectionsTable->setCellWidget(upperIndex, 1, protectionWidgetCopy);
            m_protectionsTable->setCellWidget(upperIndex, 2, buttons);

            m_protectionsTable->setItem(index, 0, upperNameItem);
            m_protectionsTable->setCellWidget(index, 1, upperProtectionWidget);
            m_protectionsTable->setCellWidget(index, 2, upperButtons);

            m_protectionWidgets->removeAt(index);
            m_protectionWidgets->insert(upperIndex, 1, protectionWidget);
        }
    });

但是当我单击向上按钮时,cellWidgets 消失了。

怎么了?

qt qwidget qtablewidget
1个回答
0
投票

您遇到的情况,记录为

setCellWidget
,您无法在不删除已存在的小部件的情况下在单元格上设置小部件。通过调试来检测这是一件相当棘手的事情,因为删除是在事件循环的下一次执行时完成的,这要归功于对
QObject::deleteLater
的调用,所以在你的 lambda 完成执行之后。

没有办法删除你的小部件,但有一种方法可以阻止 Qt 删除你的按钮。您所要做的就是放置例如

protectionWidget
在另一个可牺牲的小部件中。当您需要交换元素时,检索
protectionWidget
,删除可牺牲的小部件并将
protectionWidget
放入另一个可牺牲的小部件中。

下面的代码演示了该方法。请注意

createWidget
/
extractButton
如何协同工作以防止按钮
bA
bB
被删除,而
bC
bD
立即被销毁。我将它们创建为 lambda,以便拥有更短的独立代码,但您应该考虑创建受保护或私有方法。

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    QTableWidget t;
    t.setRowCount(4);
    t.setColumnCount(2);

    t.setItem(0, 0, new QTableWidgetItem("OK-A"));
    t.setItem(1, 0, new QTableWidgetItem("OK-B"));
    t.setItem(2, 0, new QTableWidgetItem("KO-C"));
    t.setItem(3, 0, new QTableWidgetItem("KO-D"));

    auto createWidget = [](QPushButton* button) -> QWidget*
    {
        QWidget* result = new QWidget();
        QLayout* l = new QVBoxLayout(result);
        l->setContentsMargins(QMargins());
        l->addWidget(button);
        button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        return result;
    };

    auto extractButton = [](QWidget* widget) -> QPushButton*
    {
        QPushButton* result = widget->findChild<QPushButton*>();
        result->setParent(nullptr);
        return result;
    };

    auto bA = new QPushButton("A"), bB = new QPushButton("B"),
         bC = new QPushButton("C"), bD = new QPushButton("D");
    QObject::connect(bA, &QObject::destroyed, []() { qDebug() << "Button A destroyed "; });
    QObject::connect(bB, &QObject::destroyed, []() { qDebug() << "Button B destroyed "; });
    QObject::connect(bC, &QObject::destroyed, []() { qDebug() << "Button C destroyed "; });
    QObject::connect(bD, &QObject::destroyed, []() { qDebug() << "Button D destroyed "; });
    t.setCellWidget(0, 1, createWidget(bA));
    t.setCellWidget(1, 1, createWidget(bB));
    t.setCellWidget(2, 1, bC);
    t.setCellWidget(3, 1, bD);
    //This point marks the end of the initialization   
    //The next lines demonstrate what to do (swap A<->B, each protected in a sacrificable widget) 
    //and not do (swap C<->D, unprotected) in the lambda connected to the button signals.
    auto b0 = extractButton(t.cellWidget(0, 1)), b1 = extractButton(t.cellWidget(1, 1));
    auto b2 = t.cellWidget(2, 1), b3 = t.cellWidget(3, 1);
    //bA == bX && b1 == bB && b2 == bC && b3 == bD

    t.setCellWidget(0, 1, createWidget(b1));
    t.setCellWidget(1, 1, createWidget(b0));
    //The next 2 lines are what destroys bC and bD (and if commented, the following 2 lines need to be commented too).
    t.setCellWidget(2, 1, b3);
    t.setCellWidget(3, 1, b2);

    // Next 2 lines are only to exit cleanly.
    t.setCellWidget(2, 1, nullptr);
    t.setCellWidget(3, 1, nullptr);

    t.show();
    return app.exec();
}
© www.soinside.com 2019 - 2024. All rights reserved.