【问题标题】:Deleting a widget from QTableView从 QTableView 中删除一个小部件
【发布时间】:2016-12-12 06:58:40
【问题描述】:

我的表格视图每一行的最后一列都有一个删除按钮(QPushButton)。我正在创建这些按钮并直接将它们设置在视图中。由于我已经动态分配了内存,我希望释放这些内存,但我没有在任何地方存储这些按钮的指针,所以我试图在清理和删除它们时获取小部件。

SDelegate* myDelegate;
myDelegate = new SDelegate();
STableModel* model = new STableModel(1, 7, this);
myWindow->tableView->setModel(model);
myWindow->tableView->setItemDelegate(myDelegate);
for(int i = 0; i < no_of_rows; ++i) {
    QPushButton* deleteButton = new QPushButton();
    myWindow->tableView->setIndexWidget(model->index(i, 6), deleteButton);
}
exec();

// Cleanup
for(int i = 0; i < no_of_rows; ++i) {
    // code works fine on removing this particular section
    QWidget* widget = myWindow->tableView->indexWidget(model->index(i, 6));
    if (widget)
        delete widget;
}
delete model;
delete myDelegate;

我在 qt5cored.dll 中遇到崩溃(未处理的异常),并且应用程序在 qcoreapplication.h 中崩溃,代码如下:

#ifndef QT_NO_QOBJECT
inline bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{  if (event) event->spont = false; return self ? self->notifyInternal(receiver, event) : false; }

在调试时,删除这些小部件没有问题,但之后代码在其他某个时间点崩溃。我正在为继承了 QAbstractTableModel 的模型使用 QTableView 和自定义类。

【问题讨论】:

  • 如果您正确设置了您不需要(或不想)手动删除小部件的父级。家长会替你处理的。您可能在这里造成了双重删除。编辑:实际上删除您出于相同原因发布的代码示例中的所有删除!
  • 你试过在调试器下运行吗?异常发生时的调用栈是什么样的?
  • @drescherjm 代码在删除删除小部件语句时工作得非常好。由于我使用 new 来分配内存,我认为我需要自己删除它。如何确认分配给按钮的内存稍后被释放?
  • @rustyx 是的,我在调试器下尝试过,所有代码都来自最近调用堆栈中的不同 DLL,我已经发布了 qcoreappliation 崩溃的代码段
  • 您不需要删除任何内容。这是 2016 年。让编译器处理对象的生命周期。按值保存对象,而不是按指针。

标签: c++ qt


【解决方案1】:

有一个 Qt 错误,表现如下:如果有任何索引小部件,并且您在视图上调用 setModel(nullptr),它将在 qtableview.cpp:1625 中的 visualRow != -1 断言中崩溃(在 Qt 5.6.0 )。据推测,当以其他方式删除模型时也会触发此错误。

但是我不能仅仅通过破坏模型实例来重现它。所以我怀疑它在这里是否相关,除非你得到同样的断言失败。

鉴于您的代码风格,您更有可能在其他地方遇到内存错误。如果你认为上面的代码崩溃了,你应该有一个自包含的测试用例来演示崩溃。你的模型或代表应该受到责备吗?不使用委托会崩溃吗?使用库存模型会崩溃吗?

您的代码摘录似乎很好,如果大多数情况下是不必要的。您可以在本地分配委托和模型。按钮归视图所有:一旦不再需要按钮,例如当模型更改行数或消失时,它们就会被适当地删除。所以你不必自己删除它们,它是安全的但完全没有必要。

这是一个示例,说明在所有情况下,当模型被破坏或视图被破坏时,按钮将被释放,以先到者为准。在 Qt 中跟踪对象的生命周期非常简单:保留一组对象,并使用附加到对象的 destroyed 信号的函子将它们从集合中删除。在 Qt 4 中,您将使用带插槽的辅助类。

// https://github.com/KubaO/stackoverflown/tree/master/questions/model-indexwidget-del-38796375
#include <QtWidgets>

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QSet<QObject*> live;
   {
      QDialog dialog;
      QVBoxLayout layout{&dialog};
      QTableView view;
      QPushButton clear{"Clear"};
      layout.addWidget(&view);
      layout.addWidget(&clear);

      QScopedPointer<QStringListModel> model{new QStringListModel{&dialog}};
      model->setStringList(QStringList{"a", "b", "c"});
      view.setModel(model.data());
      for (int i = 0; i < model->rowCount(); ++i) {
         auto deleteButton = new QPushButton;
         view.setIndexWidget(model->index(i), deleteButton);
         live.insert(deleteButton);
         QObject::connect(deleteButton, &QObject::destroyed, [&](QObject* obj) {
            live.remove(obj); });
      }
      QObject::connect(&clear, &QPushButton::clicked, [&]{ model.reset(); });
      dialog.exec();
      Q_ASSERT(model || live.isEmpty());
   }
   Q_ASSERT(live.isEmpty());
}

【讨论】:

    【解决方案2】:

    查看QObject::deleteLater(),它通常有助于解决有关删除 QObjects / QWidgets 的问题。

    【讨论】:

    • 这就是货物崇拜编码的定义。你需要能够论证这个立场。
    • 你说得对,我会在睡一会后编辑我的帖子并提供更多详细信息。 . . :)
    猜你喜欢
    • 1970-01-01
    • 2018-06-15
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 2020-04-09
    相关资源
    最近更新 更多