Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to properly modify QML objects through C++?
QtWS25 Last Chance

How to properly modify QML objects through C++?

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qmlc++widgetsintegrationproperties
2 Posts 2 Posters 408 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    ian28
    wrote on 14 Mar 2024, 16:57 last edited by
    #1

    Hello,
    i am trying to recreate a behaviour in my Widgets application using a QuickWidget and the Image QML type instead of a QLabel.
    The QML file is very small just an image with an additional QObject which the Image binds to and that i want to modify using c++.

    import QtQuick 2.15
    import image
    
    Rectangle {
        id: root
    
        ImageModel {
            id: imageModel
            objectName: "image_model"
        }
    
        Image {
            id: image
            objectName: "image"
            source: imageModel.path
            width: root.width
            height: root.height
            fillMode: Image.PreserveAspectFit
        }
    
    }
    

    To start with, I just wanted to adjust the url path to ensure that the setup works.
    The ImageModel class should just represent the properties that i want to expose to c++:

    class ImageModel : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString path READ path NOTIFY pathChanged)
        QML_ELEMENT
    
    public:
        explicit ImageModel(QObject* parent = nullptr);
        QString path() const;
        void setPath(const QString &newPath);
    
    signals:
        void pathChanged();
    
    private:
        QString m_path;
    };
    
    ImageModel::ImageModel(QObject* parent)
        : QObject(parent), m_path(QString{""}) {}
    
    QString ImageModel::path() const
    {
        return m_path;
    }
    
    void ImageModel::setPath(const QString &newPath)
    {
        if (m_path == newPath)
            return;
    
        qWarning() << "Update image to " + newPath;
        m_path = newPath;
        emit pathChanged();
    }
    

    The setup is in my widgets constructor:

    ImageDisplayQuick::ImageDisplayQuick(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::ImageDisplayQuick)
    {
        ui->setupUi(this);
        _quickWidget = findChild<QQuickWidget*>("quick_widget");
        _loadTimer = new QTimer(this);
        _loadTimer->setTimerType(Qt::PreciseTimer);
    
        connect(_loadTimer, &QTimer::timeout, this, &ImageDisplayQuick::requestNextImage);
    
        _imageModel = _quickWidget->rootObject()->findChild<ImageModel*>("image_model");
        QTimer::singleShot(2000, this, &ImageDisplayQuick::startImageCapture);
    }
    
    void ImageDisplayQuick::startImageCapture()
    {
        _loadTimer->start(1000);
    }
    void ImageDisplayQuick::requestNextImage()
    {
        _currentIndex = (_currentIndex + 1) % 360;
        _imageModel->setPath(QString("file:///D:/_Data/3000x3000_16bit_png/%1.png").arg(_currentIndex, 4, 10, QChar('0')));
    }
    
    

    The app crashes during QString::operator= because of

    std::_Atomic_address_as<long,std::_Atomic_padded<int> >(...) returned 0xFFFFFFFFFFFFFFFF

    and sometimes during doActivate() in qobject.cpp (also read access violation).
    I figured out that I have to get a new pointer to the object before updating the source:

        _imageModel = _quickWidget->rootObject()->findChild<ImageModel*>("image_model");
    

    I assume that I am doing it not the intended way as i always have to get a ref to the element. How am I supposed to modify the GUI or the underlying bindings in c++?

    B 1 Reply Last reply 14 Mar 2024, 18:11
    0
    • I ian28
      14 Mar 2024, 16:57

      Hello,
      i am trying to recreate a behaviour in my Widgets application using a QuickWidget and the Image QML type instead of a QLabel.
      The QML file is very small just an image with an additional QObject which the Image binds to and that i want to modify using c++.

      import QtQuick 2.15
      import image
      
      Rectangle {
          id: root
      
          ImageModel {
              id: imageModel
              objectName: "image_model"
          }
      
          Image {
              id: image
              objectName: "image"
              source: imageModel.path
              width: root.width
              height: root.height
              fillMode: Image.PreserveAspectFit
          }
      
      }
      

      To start with, I just wanted to adjust the url path to ensure that the setup works.
      The ImageModel class should just represent the properties that i want to expose to c++:

      class ImageModel : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(QString path READ path NOTIFY pathChanged)
          QML_ELEMENT
      
      public:
          explicit ImageModel(QObject* parent = nullptr);
          QString path() const;
          void setPath(const QString &newPath);
      
      signals:
          void pathChanged();
      
      private:
          QString m_path;
      };
      
      ImageModel::ImageModel(QObject* parent)
          : QObject(parent), m_path(QString{""}) {}
      
      QString ImageModel::path() const
      {
          return m_path;
      }
      
      void ImageModel::setPath(const QString &newPath)
      {
          if (m_path == newPath)
              return;
      
          qWarning() << "Update image to " + newPath;
          m_path = newPath;
          emit pathChanged();
      }
      

      The setup is in my widgets constructor:

      ImageDisplayQuick::ImageDisplayQuick(QWidget *parent) :
          QWidget(parent),
          ui(new Ui::ImageDisplayQuick)
      {
          ui->setupUi(this);
          _quickWidget = findChild<QQuickWidget*>("quick_widget");
          _loadTimer = new QTimer(this);
          _loadTimer->setTimerType(Qt::PreciseTimer);
      
          connect(_loadTimer, &QTimer::timeout, this, &ImageDisplayQuick::requestNextImage);
      
          _imageModel = _quickWidget->rootObject()->findChild<ImageModel*>("image_model");
          QTimer::singleShot(2000, this, &ImageDisplayQuick::startImageCapture);
      }
      
      void ImageDisplayQuick::startImageCapture()
      {
          _loadTimer->start(1000);
      }
      void ImageDisplayQuick::requestNextImage()
      {
          _currentIndex = (_currentIndex + 1) % 360;
          _imageModel->setPath(QString("file:///D:/_Data/3000x3000_16bit_png/%1.png").arg(_currentIndex, 4, 10, QChar('0')));
      }
      
      

      The app crashes during QString::operator= because of

      std::_Atomic_address_as<long,std::_Atomic_padded<int> >(...) returned 0xFFFFFFFFFFFFFFFF

      and sometimes during doActivate() in qobject.cpp (also read access violation).
      I figured out that I have to get a new pointer to the object before updating the source:

          _imageModel = _quickWidget->rootObject()->findChild<ImageModel*>("image_model");
      

      I assume that I am doing it not the intended way as i always have to get a ref to the element. How am I supposed to modify the GUI or the underlying bindings in c++?

      B Offline
      B Offline
      Bob64
      wrote on 14 Mar 2024, 18:11 last edited by Bob64
      #2

      @ian28 the way you are doing it is how one would implement a new QML component in C++ that would tend to be purely used in QML - i.e. you wouldn't normally interact with it from the C++ side once it is created.

      If you wanted to continue with that sort of approach, it might be better to create the timer in QML and have that update the path of your Image.

      However a better fit might be to expose your "model" via a "singleton instance" (see qmlRegisterSingletonInstance). This is the more modern approach that is advised rather than using the older setContextProperty, but you will probably find more information out there about using setContextProperty. It's not massively different in principle and it might be easier for you to use the older approach in order to get started.

      1 Reply Last reply
      0

      1/2

      14 Mar 2024, 16:57

      • Login

      • Login or register to search.
      1 out of 2
      • First post
        1/2
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved