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?