2016-12-22 16 views
0

qt 레이블로 이미지를 표시하고 있습니다. 아래 코드는 다음과 같습니다.Pixmap을 얻는 것은 함수를 호출 할 때 null pixmap입니다.

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()을 구현하고 거기에 모든 예외를 catch해야합니다.

위의 코드에서 오류가 발생하지 않습니다. 누군가가 해결 방법을 알려주시겠습니까?

답변

0

확실한 누수는 qnam_push_button_clicked_show_image = new QNetworkAccessManager(this);입니다. 어느 곳에서도 균형 잡힌 삭제가 없습니다. QNAM은 일반적으로 한 번 생성 된 다음 단일 요청으로 생성되지 않고 응용 프로그램의 수명 동안 재사용되어야합니다. 따라서 qnam_push_button_clicked_show_image를 클래스 멤버 (ui와 동일)로 설정하면 누수를 모두 수정하고 코드의 효율성을 향상시킬 수 있습니다.

그렇다면 QPixmap 오류의 원인이라고 생각하지 않습니다. X11에서이 코드를 실행하면 QPixmap은 다양한 요소 (소프트웨어 및 하드웨어)로 제한되는 X Pixmap 리소스에 의해 백업됩니다. 코드에서 분명한 누출은 없지만 큰 픽스맵을 반복적으로 할당하면 X로 관리되는 메모리 풀을 조각화 된 픽스맵에 충분한 크기의 블록을 할당 할 수없는 지점까지 천천히 조각 낸 다음 오류를 유발할 수 있습니다 . 또는 그래픽 스택의 어딘가에서 드라이버 버그 일 수 있습니다. 크기 조정 된 크기를 변경하면 끊기 시작하기 전에 한도를 늘리거나 줄이려고 시도 했습니까? 그렇다면 QImage로 전환하면 X에 대한 압력을 완화하는 데 도움이 될 수 있습니다.

그 외에도 코드는 일부 정리, 특히 불필요한 QEventLoop 사용을 사용할 수 있습니다. 새로운 이미지가로드 될 때까지 버튼을 여러 번 클릭하지 못하도록하는 방법을 추측하고 있지만 중첩 된 이벤트 루프가 결합되어 있으므로 이미지를 다운로드하는 동안 button.setEnabled (false)를 사용하여 구현하는 것이 좋습니다. 네트워크 이벤트를 사용하면 수많은 재진입 문제를 해결할 수 있으며 충돌/버그를 디버그하기가 어렵습니다. 그들이 정말로 무엇을 의미하면서

가 나는 또한 size은이 후 바로 삭제됩니다 특히, 힙에 할당, 그들이 if (size->isValid())으로 이해 될 수있다 이러한 if (size)은 정말 혼란 이유에 대한 혼란 스러워요은 꽤입니다, if (size != nullptr)입니다 그 라인에서 OOM을 얻을 확률이 매우 낮습니다. (결국 메모리가 부족한 경우 위의 readAll() 또는 loadFromData() 호출에서 발생할 가능성이 높습니다.

PS : 누출을 고정하는 것이 도움이 있다면 행운이 버튼을 다른 500 번을 누르면 확인)

+0

오 당신이) 초기 onPushButtonClickedRequestCompleted (QNetworkReply * 회신'에서 반환하고 다른 작은 누수가''경우에있다 회신'에 오류가 있습니다. 이 경우에는'reply-> deleteLater();를 호출하지 않으면 응답이 누출됩니다. 일반적으로 그 슬롯에서 제일 먼저 호출하는 것이고, 슬롯이 종료 될 때까지 응답이 실제로 삭제되지 않으므로 안전합니다. 그래서 마지막에 호출 할 필요가 없습니다. –