获取 Pixmap 是调用函数 500 次时的空像素图

Posted

技术标签:

【中文标题】获取 Pixmap 是调用函数 500 次时的空像素图【英文标题】:Getting Pixmap is a null pixmap on calling a function 500 times 【发布时间】:2017-05-07 16:07:53 【问题描述】:

我在 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() 并在那里捕获所有异常。

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

【问题讨论】:

【参考方案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-&gt;isValid()),而它们真正的意思是if (size != nullptr),这几乎可以保证,因为在那条线上获得 OOM 的机会非常低。 (如果你最终确实耗尽了内存,我猜它可能会发生在上面的 readAll() 或 loadFromData() 调用中)。

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

【讨论】:

哦,当您从onPushButtonClickedRequestCompleted(QNetworkReply* reply) 提早返回时,还有另一个小泄漏,以防reply 出现错误。在这种情况下,您通过不调用 reply-&gt;deleteLater(); 来泄露回复。通常这是我在此类插槽中调用的第一件事,这是安全的,因为直到插槽退出后才会实际删除回复,因此无需仅在最后调用它。

以上是关于获取 Pixmap 是调用函数 500 次时的空像素图的主要内容,如果未能解决你的问题,请参考以下文章

当我从数据库 Web Api .Net 中获取数据时的空列表

获取表单信息,进行对比时的空指针错误

异步调用的空闭包

从 QLabel 获取 QPixmap

AWS.ApiGatewayManagementApi.postToConnection() 调用一次时执行两次

为啥我调用一次时会打印无限值?