c++ e ListElement di Qml
-
Buona sera a tutti, chiedo nuovamente il vostro aiuto per capire come potrei risolvere il mio problema.
Quello che sto cercando di fare è provare a integrere C++ in un interfaccia fatta totalmente in Qml. Questo codice visualizza delle immagini caricandole direttamente
da internet tramite una ListElement. Vi posto il modello:ListModel { id: myModel ListElement { display: "One"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2016/07/07/b3d9be-background.png"} ListElement { display: "Two"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2016/04/26/Dots.png"} ListElement { display: "Three"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2016/02/08/sunRising.png" } ListElement { display: "Four"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2015/11/18/garlic_siracha.png" } ListElement { display: "Five"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2015/09/23/Take_OFF.png" } ListElement { display: "Six"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2015/08/20/Sunset_by_Banned.png" } ListElement { display: "Seven"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2015/07/28/splash7.png" } ListElement { display: "Eight"; width0: 280; height0: 180; url: "http://static.simpledesktops.com/uploads/desktops/2015/06/26/Overlap.png" } }
Ciò che vorrei provare a fare è sostituire il modello di sopra con un mio modello realizzato in c++.
Come fare ciò mi è stato spiegato proprio qui sul forum (grazie ancora VRonin). La classe che ho creato è questa:
class ItemViewImage { Q_GADGET Q_PROPERTY(QString display MEMBER m_display) Q_PROPERTY(int width MEMBER m_width) Q_PROPERTY(int height MEMBER m_height) Q_PROPERTY(QImage image MEMBER m_image) public: ItemViewImage(const QString& display,const int& width ,const int& height, const QImage& image) :m_display(display),m_width(width),m_height(height),m_image(image){} ItemViewImage() = default; ItemViewImage(const ItemViewImage& other)=default; ItemViewImage& operator=(const ItemViewImage& other)=default; QString m_display; int m_width; int m_height; QImage m_image; };
e il rimanente codice posso dire che è uguale a quello di questo mio altro post:
[https://forum.qt.io/topic/86374/form-qml-e-classe-in-c/21](link url)Aggiungo ed elimino i componenti in modo corretto ma quello che non riesco a fare è visualizzare le immagini. E' sbagliato passare una QImage a url (ovviamente) ma come posso settare l'immagine passando direttamente QImage?
ps Leggendo in giro ho visto che potrei usare QQuickImageProvider ma non mi è chiarissimo come..
-
Mai banale, eh?!
La risposta di base e' qui. Ad occhio, credo tu debba mettere
PixmapImage
nel delegate ma non sono sicuro tu possa caricare l'immagine dinamica senza provarlo. Purtroppo per un paio di settimane non avro' possibilita' di sperimentare quindi prova a dargli un occhiata, se non riesci ci risentiamo -
Aggiorno il post. Da quello che ho capito non posso passare direttamente una QImage a Qml ma devo passare un Url.
Una delle possibili soluzioni quindi dovrebbe essere quella di utilizzare QQuickImageProvider.
Ancora non ho ben capito come usarlo ma quello che ho fatto finora è:aggiungere l'imageProvaider al Qml.
void Game::inizializzaListaImagTarget() { m_model_imgTarget=new QStandardItemModel(this); m_model_imgTarget->insertColumn(0); QHash<int, QByteArray> roleNames = m_model_imgTarget->roleNames(); roleNames.insert(Qt::UserRole,"imgTarget"); static_cast<QStandardItemModel*>(m_model_imgTarget)->setItemRoleNames(roleNames); this->engine->addImageProvider(QLatin1String("imageprovider"),new ImageProvider(QQuickImageProvider::Image)); }
Creare un signal per passare l'immagine a ImageProvider
Q_SIGNALS: Q_SIGNAL void send_image_to_imageprovaider(const QImage& image, QString name);
Aggiungere uno Slot a ImageProvider:
#ifndef IMAGEPROVIDER_H #define IMAGEPROVIDER_H #include <QQuickImageProvider> #include <QPixmap> #include <QPainter> class ImageProvider : public QQuickImageProvider { public: ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) { } 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); Q_SLOT void receiveImage(QString name, const QImage& image); };
#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); } void ImageProvider::receiveImage(QString name, const QImage &image) { }
Quello che dovrei fare adesso nello slot addimgTarget dovrebbe essere:
- inviare un signal a ImageProvider con il nome dell'immagine e l'immagine stessa
- Aggiungere al modello un nuovo elemento contenente una Qstring (al posto di una QImage) composta da "image://imageprovider/name"
Sapreste dirmi se la strada che sto percorrendo è giusta o ne esistono delle migliori?
Grazie anticipatamente -
Non avevo letto la tua risposta perche forse abbiamo scritto nello stesso istante. Ho continuato il percorso che ho descritto sopra e devo dire che sembra funzionare. Una cosa che ho cambiato è che ripensadoci non aveva senso (nel mio caso) usare signal/slot per passare l'immagine a imageProvaider per come avevo impostato il codice.
Riporto il codice che magari può servire a chi come me sta iniziando ora
#ifndef IMAGEPROVIDER_H #define IMAGEPROVIDER_H #include <QQuickImageProvider> #include <QPixmap> #include <QPainter> #include <QMap> class ImageProvider : public QQuickImageProvider { public: ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) { //QObject::connect(game, &Game::send_image_to_imageprovaider, this, &ImageProvider::receiveImage); } 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); void receiveImage(QString name, const QImage& image); private: QMap<QString, QImage> map; }; #endif // IMAGEPROVIDER_H
QImage ImageProvider::requestImage(const QString& id, QSize* size,const QSize& requestedSize) { QImage result; if (requestedSize.isValid()) { result = map[id].scaled(requestedSize, Qt::KeepAspectRatio); } else { result = map[id]; } *size = result.size(); return result; } void ImageProvider::receiveImage(QString name, const QImage &image) { map.insert(name, image); }
void Game::inizializzaListaImagTarget() { m_model_imgTarget=new QStandardItemModel(this); m_model_imgTarget->insertColumn(0); QHash<int, QByteArray> roleNames = m_model_imgTarget->roleNames(); roleNames.insert(Qt::UserRole,"itemviewimage"); static_cast<QStandardItemModel*>(m_model_imgTarget)->setItemRoleNames(roleNames); this->imageProvaider = new ImageProvider(QQuickImageProvider::Image); this->engine->addImageProvider(QLatin1String("imageprovider"),this->imageProvaider);
e per aggiungere un immagine
QString id = "image://imageprovider/" + QString::number(m_model_imgTarget->rowCount()); Game::addimgTarget(display, width, height, id); imageProvaider->receiveImage(QString::number(m_model_imgTarget->rowCount()-1), image);
-
Ho un dubbio che spero mi possiate chiarire. Se io ho un oggetto con delle Q_PROPERTY e lo Istanzio dentro un altro oggetto, è possibile far vedere queste proprietà a avendo registrato nel main solo l’ogget padre?
Altrimenti posso registrare l’oggetto figlio su Qml ad esempio dentro il costruttore del padre?
Faccio un esempio.. se io dichiaro una classe Programm e la registro su Qml. Poi al suo interno uso l’oggetto del post precedente Game che ha delle proprietà.. posso in qualche modo far vedere queste proprietà a qml senza ricorrere ai signal/slot?