0

我在 qt 标签中显示图像。下面是我的代码:

void MyClass::onPushButtonClicked(QString myurl)
{
    this->setCursor(Qt::WaitCursor);
    ui.qtImageLabel->clear();
    qDebug()<<QTime::currentTime()<<"MyClass: onPushButtonClicked";
    QNetworkAccessManager *qnam_push_button_clicked_show_image;
    QNetworkReply *reply;
    QNetworkRequest request;
    request.setHeader( QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded" );
    QUrl url(myurl);
    request.setUrl(url);
    qnam_push_button_clicked_show_image = new QNetworkAccessManager(this);
    if(qnam_push_button_clicked_show_image)
    {
        QObject::connect(qnam_push_button_clicked_show_image, SIGNAL(finished(QNetworkReply*)),
                         this, SLOT(onPushButtonClickedRequestCompleted(QNetworkReply*)));
        reply = qnam_push_button_clicked_show_image->post(request, url.encodedQuery());
        QEventLoop loop;
        QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();
    }
}

void MyClass::onPushButtonClickedRequestCompleted(QNetworkReply *reply)
{
    qDebug()<<QTime::currentTime()<<"MyClass: onPushButtonClickedRequestCompleted request completed";
    if (reply->error() != QNetworkReply::NoError)
    {
        qDebug() << "Error in" << reply->url() << ":" << reply->errorString();
        this->setCursor(Qt::ArrowCursor);
        return;
    }
    QByteArray data = reply->readAll();
    QPixmap pixmap;
    pixmap.loadFromData(data);
    int width;
    int height;
    //application size can be changed
    QRect rec = QApplication::desktop()->screenGeometry();
    height = rec.height();
    width = rec.width();
    qDebug()<<QTime::currentTime()<<width<<","<<height;
    QSize *size = new QSize(width,height);
    if(size)
    {
        QPixmap scaledPixmap = pixmap.scaled(*size);
        ui.qtImageLabel->setPixmap(scaledPixmap);
    }
    if(size)
    {
        delete size;
        size = NULL;
    }
    data.clear();
    this->setCursor(Qt::ArrowCursor);
    reply->deleteLater();
    return;
}

单击按钮时,它将向服务器发送请求,并显示从服务器接收到的不同图像。如果它不超过 500 次,它工作正常。如果它超过第一个,则显示此错误

QPixmap::scaled: Pixmap is a null pixmap

它不显示图像。然后,如果有人再次发送图像请求,则会显示以下错误:Qt 已捕获从事件处理程序引发的异常。Qt 不支持从事件处理程序中抛出异常。您必须QApplication::notify()在那里重新实现并捕获所有异常。

我没有得到上面代码中的错误。有人可以告诉我如何解决这个问题吗?

4

1 回答 1

1

明显的泄漏是qnam_push_button_clicked_show_image = new QNetworkAccessManager(this);,它在任何地方都没有平衡删除。QNAM 通常应该创建一次,然后在应用程序的整个生命周期内重复使用,而不是为单个请求创建。因此,通过在类成员(与 ui 相同)中打开 qnam_push_button_clicked_show_image,您将修复泄漏并提高代码效率。

也就是说,我认为这不是导致您的 QPixmap 错误的原因。如果您在 X11 上运行此代码,则 QPixmap 由 X Pixmap 资源支持,该资源受各种因素(软件和硬件)的限制。即使从您的代码中没有明显的泄漏,也可能是重复分配大像素图会缓慢地分割由 X 管理的内存池,直到它无法为缩放的像素图分配足够大的块,然后触发错误. 或者它可能是图形堆栈中某处的驱动程序错误。您是否尝试过更改缩放大小是否会在限制开始突破之前增加或减少限制?如果是这样,切换到 QImage 可能有助于缓解 X 的压力。

除此之外,代码可以使用一些清理,尤其是多余的 QEventLoop 使用。我猜这是一种防止按钮被多次点击的方法,直到新图像被加载,但我更愿意在图像下载时使用 button.setEnabled(false) 来实现这一点,因为嵌套的事件循环结合了网络事件是无数重入问题和难以调试崩溃/错误的秘诀。

我也对为什么size在堆上分配感到困惑,尤其是当它被立即删除时,这些if (size)确实令人困惑,因为它们可以理解为if (size->isValid())它们真正的意思是if (size != nullptr),这几乎可以保证获得那条线上的OOM非常低。(如果您最终确实耗尽了内存,我猜它可能会发生在上面的 readAll() 或 loadFromData() 调用中)。

ps:祝你好运,再按该按钮 500 次以检查修复泄漏是否有帮助;)

于 2016-12-22T08:37:16.933 回答