[英]How to correctly use Qt QML Image Provider
我正在开发一个跨平台应用程序,该应用程序通过C ++端的REST API接收图像,然后通过ImageProvider将它们发送到QML,这似乎会导致内存泄漏。 内存泄漏的速度与图像的大小和更新间隔成正比。
我尝试禁用QML Image的缓存,但没有改变。 我还尝试通过在图像更新上运行gc()来强制进行垃圾收集,但是仍然没有运气。
为了完全确定这不是由我的错误编码等引起的。我创建了一个最小演示,它基于以下Qt示例: http : //doc.qt.io/qt-5/qquickimageprovider.html
唯一的补充是我增加了图像大小,并实现了将红色图像替换为黄色图像的方法。 一旦运行该应用程序,图像将每秒更改颜色,并且内存将不断增加。 图片的尺寸为10000x10000,因此您可以清楚地看到它的增加。 即使图像是10x10或任何其他大小,仍然会发生内存泄漏。
我设法在Android手机,Macbook以及运行Fedora的PC上复制了此问题。
如果您发现发生这种情况的任何原因,并且如果是错误,请告诉我,可以使用哪种解决方法将图像发送到QML。 我需要在通过REST API接收到这些图像后立即发送这些图像,因此通常在30FPS左右。
任何帮助将不胜感激! 完整的解决方案如下。 Image和Pixmap提供程序都引起相同的问题。 如果要测试原始的Qt代码,请在main.cpp中更改QQuickImageProvider :: Image QQuickImageProvider :: Pixmap。
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QThread>
#include "imageProvider.h"
class MyThread : public QThread
{
public:
MyThread(QObject* object) : m_object(object)
{
}
virtual void run()
{
QVariant colour = "red";
while (isRunning())
{
QMetaObject::invokeMethod(
m_object, "updateViewport", Q_ARG(QVariant, colour));
if (colour == "red")
{
colour = "yellow";
}
else
{
colour = "red";
}
QThread::sleep(1);
}
}
private:
QObject* m_object;
};
int main(int argc, char* argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.addImageProvider(QLatin1String("imageprovider"),
new ImageProvider(QQuickImageProvider::Image));
QQmlComponent component(&engine, "qrc:/main.qml");
QObject* object = component.create();
MyThread* myThread = new MyThread(object);
myThread->start();
return app.exec();
}
imageProvider.h
#ifndef IMAGE_PROVIDER_H
#define IMAGE_PROVIDER_H
#include <QQuickImageProvider>
#include <QPixmap>
#include <QPainter>
class ImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
explicit ImageProvider(ImageType type, Flags flags = 0);
QPixmap requestPixmap(const QString& id,
QSize* size,
const QSize& requestedSize);
QImage requestImage(const QString& id,
QSize* size,
const QSize& requestedSize);
};
#endif // IMAGE_PROVIDER_H
imageProvider.cpp
#include "imageProvider.h"
using namespace std;
ImageProvider::ImageProvider(ImageType type, Flags flags)
: QQuickImageProvider(type, flags)
{
}
QPixmap ImageProvider::requestPixmap(const QString& id,
QSize* size,
const QSize& requestedSize)
{
int width = 10000;
int height = 10000;
if (size)
{
*size = QSize(width, height);
}
QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
requestedSize.height() > 0 ? requestedSize.height() :
height);
pixmap.fill(QColor(id).rgba());
QPainter painter(&pixmap);
QFont f = painter.font();
f.setPixelSize(20);
painter.setFont(f);
painter.setPen(Qt::black);
if (requestedSize.isValid())
painter.scale(requestedSize.width() / width,
requestedSize.height() / height);
painter.drawText(QRectF(0, 0, width, height), Qt::AlignCenter, id);
return pixmap;
}
QImage ImageProvider::requestImage(const QString& id,
QSize* size,
const QSize& requestedSize)
{
return QImage(10000, 10000, QImage::Format_ARGB32);
}
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("MemoryLeakDemo")
function updateViewport(colour) {
image.source = "image://imageprovider/" + colour;
}
Image {
id: image
cache: false
}
}
memoryLeakDemo.pro
QT += qml quick
CONFIG += c++11
SOURCES += main.cpp \
imageProvider.cpp
RESOURCES += qml.qrc
DEFINES += QT_DEPRECATED_WARNINGS
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += imageProvider.h
Qt已经确认这是一个错误,因此希望它将尽快得到解决:
https://bugreports.qt.io/browse/QTBUG-62600
同时,您可以尝试应用补丁并从源代码编译框架:
https://codereview.qt-project.org/#/c/200715/
希望这可以帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.