绘图时Qt崩溃,即使在GUI线程中

时间:2016-07-26 08:26:27

标签: qt qtwidgets

我认为我遇到了与Qt crash when redrawing Widget类似的问题,并切换到Qt::QueuedConnection解决了问题。但是,就我而言,信号发射器和接收器总是在同一个线程(主线程)中。

我有一个带有入口行的QAbstractItemModel和一个用于过滤的QSortFilterProxyModel。由于模型可能非常大,我想在过滤时制作进度条。更新过滤器基本上是在连接到QAction::toggled信号的插槽中执行此操作:

m_ProgressBar = new QProgressBar(); // Put into status bar etc.
auto connection = connect(m_filteredModel, SIGNAL(filterProgressChanged(int)), m_ProgressBar, SLOT(setValue(int)), Qt::QueuedConnection);
m_filteredModel->UpdateFilter();
delete m_ProgressBar;
disconnect(connection);

UpdateFilter基本上做了一些内务处理,然后调用invalidate,使每个行的过滤器模型重新查询filterAcceptsRow。 然后,过滤器模型在filterProgressChanged(int)内发出filterAcceptsRow信号(通过递增计数器并除以源模型的行计数,并且仅在实际的int进度值更改时发出)。 过滤完成后UpdateFilter返回。在此之前(已验证),进度条不会被删除,因此在我看来工作。不删除进度条会导致每次调用都获得一个新进度,但崩溃仍然是相同的。

一切都在主线程中完成:创建进度条,调用UpdateFilter,发出filterProgressChanged信号。但是,当连接创建为Qt::AutoConnection(即直接)时,它会在重新绘制进度条时崩溃(仅在禁用过滤器时出于某种原因)。当我直接在我自己的事件处理程序中调用setValue时也会发生同样的情况,这是我在切换到当前代码之前所做的。

现在我有一个有效的解决方案,但我不明白为什么原始代码不起作用。我认为DirectConnection只会在信号的发送方和接收方处于不同的线程中时产生实际的差异,但它们并非如此。您可以在堆栈跟踪中轻松地看到所有内容都发生在同一个线程中,对于排队连接,情况也是如此。

那么,原始代码出了什么问题?有什么我错过的吗?有没有办法从实际崩溃中获取更多信息?

我只发现在void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)中,state()返回0,代码假定它永远不会返回0,这是直接崩溃的原因,但可能不是原因。堆栈跟踪指向绘画作为问题区域,这是我在调试时所看到的。

我在Windows上使用Qt 5.4.2(也尝试过5.7),以及使用MSVC 2013,如果有任何重要的话。

编辑:根据code_fodder的要求,我添加了UpdateFilter并发出代码(actualFilterFunction执行实际过滤,但与信号或GUI或其他任何东西无关)。

void MyModel::UpdateFilter() {
    m_filterCounter = 0;
    m_lastReportedProgress = -1;
    invalidate();
}

bool MyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
    m_filterCounter++;
    int progress = (100 * m_filterCounter) / m_sourceModel->rowCount();
    if (progress != m_lastReportedProgress) {
        emit filterProgressChanged(m_lastReportedProgress = progress);
    }
    return actualFilterFunction();
}

0 个答案:

没有答案