我有 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 消失了。
怎么了?
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();
}