0

I am working on a c++/QML with Opencv Project.. I have found that the best way to view the processed image in QMl is to write a custom QML component that extends QQuickPaintedItem in c++ and it is working well:

class ImageView : public QQuickPaintedItem{
 Q_OBJECT
 Q_PROPERTY(QImage image READ image WRITE setImage NOTIFY imageChanged)
 public:
    // I need to pass a pointer of ImageService
  ImageView(QQuickItem *parent = nullptr, ImageService *imageService = nullptr);

  Q_INVOKABLE void updateImage();
  void paint(QPainter *painter);
  QImage image() const;
 signals:
  void imageChanged();
 private:
  QImage m_image;
  ImageService *m_imageService;
};

and I registered this type in C++ like the following :

 qmlRegisterType<ImageView>("opencv.plugin", 1, 0, "ImageView");

My Problem is : I have this class ImageService that does all the work and holds the last version of the image after processing:

class ImageService
  {

   public:
    ImageService();
    bool openImage(const std::string &);
    QImage toQImage();
    bool isValid();

  private:
    std::string m_imagePath;
    cv::Mat m_image;

 };

I need ImageView component to update itself after any operation that ImageService perform using updateImage() function.

I tried : I thought about:

  1. passing a pointer to ImageService to ImageView, But I do not see how.
  2. Making ImageService as Qml Property and pass a QML Image from Qml to the ImageView component,But I do not think that it is a good idea.
Samir N Ahmad
  • 575
  • 6
  • 16
  • 1
    If the number of `ImageView` should be limited you could put them inside another class. If you want "the user" to be able to create as many `ImageView` as they like, you think about making `ImageService` a C++-side singleton, which each `ImageView` registers to when constructed – Amfasis May 04 '20 at 12:19
  • The Singleton class sounds reasonable.. But about the first Idea, I did not get it. ImageView Will be used one time only as the main widget of the application where all the visualization operations happen(May be later I will add the abbility to create more than one viewport but not at this stage if that's what you mean).. – Samir N Ahmad May 04 '20 at 13:52
  • Ok, in case there is only one, you can make an "overarching" C++ model, which has a Q_PROPERTY(ImageView* viewport1 ....), this way you instantiate the `ImageView` yourself and can thus put the `ImageService` pointer in the constructor – Amfasis May 04 '20 at 14:56
  • Sorry, I am new to qml. I do not see how could that help me becuase I would have two instances of "Imageview" first as a `qmlType` and the second as a `QProperty` .do you have any example for that? – Samir N Ahmad May 04 '20 at 15:53

1 Answers1

0

In case you only have one ImageView it is easy to make it a Q_PROPERTY of a model.

class ImageModel : public QObject 
{
    Q_OBJECT
    Q_PROPERTY(ImageView *image1 READ image1 CONSTANT)

  public:
    ImageModel(ImageService *service)
      : service_(service)
      , image1_(new ImageView(/*parent=*/ this, /*service=*/service_)
    { }

    ImageView* image1() const { return image1_; }

  private:
    ImageService *service_;
    ImageView *image1_;
}

Change your main:

...
qmlRegisterUncreatableType<ImageService>(...);
qmlRegisterUncreatableType<ImageView>(...);
qmlRegisterUncreatableType<ImageModel>(...);

QQmlEngine engine;
ImageService theService;
ImageModel coreModel(&theService);
QQmlContext *context = new QQmlContext(engine.rootContext());
context->setContextProperty("images", &coreModel);

The in qml you can use:

<imageproperty>: images.image1
Amfasis
  • 3,932
  • 2
  • 18
  • 27