提问人:willy_j 提问时间:8/8/2023 更新时间:8/9/2023 访问量:48
QTableWidget 单元格小部件在交换后消失
QTableWidget cell widgets dissapear after swap
问:
我有 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);
}
});
但是当我单击upButton时,cellWidgets消失了。
怎么了?
答:
2赞
Atmo
8/9/2023
#1
setCellWidget
记录在您身上的情况是,如果不删除已经存在的小部件,您就无法在单元格上设置小部件。使用调试工具检测这是一件相当棘手的事情,因为删除是在下次执行事件循环时完成的,这要归功于对 的调用,在您的 lambda 已经完成执行很久之后。QObject::deleteLater
没有办法避免正在发生的删除,但是有一些方法可以使删除无害。我看到 2 种方式:
- 放置你的和里面的祭祀小部件。通过在正确的时间重置它们的父级,您可以实现在下一次调用 时仅删除空的祭祀小部件的效果。
protectionWidget
buttons
setCellWidget
- 与上面相同,但您完全停止调用,而只是交换小部件的父级。
setCellWidget
下面的代码演示了你的错误(A和B),第一种方法(C和D)和第二种方法(E和F)。请注意,您需要考虑是否保留 lambda 和/或保持原样,或者将它们转换为受保护/私有方法。createWidget
extractButton
swapParent
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTableWidget t;
t.setRowCount(6);
t.setColumnCount(2);
t.setItem(0, 0, new QTableWidgetItem("Original: A"));
t.setItem(1, 0, new QTableWidgetItem("Original: B"));
t.setItem(2, 0, new QTableWidgetItem("Method 1: C"));
t.setItem(3, 0, new QTableWidgetItem("Method 1: D"));
t.setItem(4, 0, new QTableWidgetItem("Method 2: E"));
t.setItem(5, 0, new QTableWidgetItem("Method 2: F"));
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 swapParent = [](QWidget* from, QWidget* to) -> void
{
auto fromChild = from->findChild<QWidget*>(), toChild = to->findChild<QWidget*>();
from->layout()->removeWidget(fromChild);
to->layout()->removeWidget(toChild);
fromChild->setParent(to);
toChild->setParent(from);
from->layout()->addWidget(toChild);
to->layout()->addWidget(fromChild);
};
auto bA = new QPushButton("A"), bB = new QPushButton("B"),
bC = new QPushButton("C"), bD = new QPushButton("D"),
bE = new QPushButton("E"), bF = new QPushButton("F");
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 "; });
QObject::connect(bE, &QObject::destroyed, []() { qDebug() << "Button E destroyed "; });
QObject::connect(bF, &QObject::destroyed, []() { qDebug() << "Button F destroyed "; });
t.setCellWidget(0, 1, bA);
t.setCellWidget(1, 1, bB);
t.setCellWidget(2, 1, createWidget(bC));
t.setCellWidget(3, 1, createWidget(bD));
t.setCellWidget(4, 1, createWidget(bE));
t.setCellWidget(5, 1, createWidget(bF));
//End of the initialization.
//The next lines simulate the lambdas connected to the button signals with:
// - what not do to: swap A<->B, unprotected
// - method 1: swap C<->D, each protected by a sacrifical widget
// - method 2: reparent E and F instead of literally swapping them
auto b0 = t.cellWidget(0, 1), b1 = t.cellWidget(1, 1),
b2 = t.cellWidget(2, 1), b3 = t.cellWidget(3, 1),
b4 = t.cellWidget(4, 1), b5 = t.cellWidget(5, 1);
//b0 == bA && b1 == bB && b2 == bC && b3 == bD && b4 == bE && b5 == bF
//Incorrect for A and B (see the qDebug messages)
t.setCellWidget(0, 1, b1);
t.setCellWidget(1, 1, b0);
//Method 1
t.setCellWidget(2, 1, createWidget(extractButton(b3)));
t.setCellWidget(3, 1, createWidget(extractButton(b2)));
//Method 2
swapParent(b4, b5);
// The next 2 lines are only to exit cleanly.
t.setCellWidget(0, 1, nullptr);
t.setCellWidget(1, 1, nullptr);
t.show();
return app.exec();
}
不言而喻,但这个演示确实需要大量的指针检查。
评论