c++ image qt qml qtquick2

Interoperabilidad de imagen QML y C++



qt qtquick2 (1)

Era posible hacerlo en QtQuick1 pero esa funcionalidad se eliminó en QtQuick2.

La solución que se me ocurrió permite tener la misma imagen en QML y C ++ mediante la implementación de un QQuickImageProvider que básicamente funciona con QPixmap * que se convierte en cadena y luego vuelve a un tipo de puntero (suena un poco inseguro pero ha demostrado para trabajar bastante bien).

class Pixmap : public QObject { Q_OBJECT Q_PROPERTY(QString data READ data NOTIFY dataChanged) public: Pixmap(QObject * p = 0) : QObject(p), pix(0) {} ~Pixmap() { if (pix) delete pix; } QString data() { if (pix) return "image://pixmap/" + QString::number((qulonglong)pix); else return QString(); } public slots: void load(QString url) { QPixmap * old = 0; if (pix) old = pix; pix = new QPixmap(url); emit dataChanged(); if (old) delete old; } void clear() { if (pix) delete pix; pix = 0; emit dataChanged(); } signals: void dataChanged(); private: QPixmap * pix; };

La implementación del elemento Pixmap es bastante sencilla, aunque la inicial fue un poco limitada, ya que el nuevo mapa de píxeles se asignó exactamente a la misma dirección de memoria, la cadena de data era la misma para diferentes imágenes, lo que hace que el componente de imagen QML no se actualice , pero la solución fue tan simple como eliminar el antiguo mapa de píxeles solo después de que se haya asignado el nuevo. Aquí está el proveedor de imágenes real:

class PixmapProvider : public QQuickImageProvider { public: PixmapProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) { qulonglong d = id.toULongLong(); if (d) { QPixmap * p = reinterpret_cast<QPixmap *>(d); return *p; } else { return QPixmap(); } } };

Registro:

//in main() engine.addImageProvider("pixmap", new PixmapProvider); qmlRegisterType<Pixmap>("Test", 1, 0, "Pixmap");

Y así es como lo usas en QML:

Pixmap { id: pix } Image { source: pix.data } // and then pix.load(path)

TAMBIÉN Tenga en cuenta que en mi caso no hubo una modificación real del mapa de píxeles que necesitaba actualizarse en QML. Esta solución no actualizará automáticamente la imagen en QML si se cambia en C ++, porque la dirección en la memoria seguirá siendo la misma. Pero la solución para esto es igual de sencilla: implementar un método update() que asigne un new QPixmap(oldPixmap) : usará los mismos datos internos pero le dará un nuevo acceso con una nueva dirección de memoria, lo que activará el Imagen QML para actualizar sobre cambios. Esto significa que el método ofrecido para acceder al pixmap será a través de la clase Pixmap , no directamente de QPixmap * ya que necesitará la clase Pixmap para activar el cambio de data , así que solo agregue un accesorio para pix , y en caso de que sea complejo o cosas enhebradas, es posible que desee usar QImage en QImage lugar y agregar un mutex para que los datos subyacentes no se cambien en QML mientras se cambian en C ++ o al revés.

Revisé la documentación y también lo que pude encontrar en Internet, pero no parece que sea posible acceder a una imagen QML desde C ++.

¿Hay alguna manera de evitar eso?