QQuickPaintedItem from .qml file



  • Hi,
    I have created a little test application with .qml files avalables for the user so he can edit and change visual aspect of the application.

    I dit that by subclassing 'QQuickPaintedItem' like this :
    // QMProgressBar .h

    class QMProgressBar :  public QQuickPaintedItem
    {
        Q_OBJECT
    public:
        QMProgressBar(QQuickItem *parent = 0);
    
    private:
            QQuickItem* userItem;
           // void paint(QPainter *painter);
    };
    

    //QMProgressBar.cpp

    QMProgressBar::QMProgressBar(QQuickItem *parent):QQuickPaintedItem(parent)
    {
    
        QString homeLocation = QStandardPaths::locate(QStandardPaths::DocumentsLocation, QString(), QStandardPaths::LocateDirectory);
        homeLocation.append("QML_CUSTOM_ITEM/Customizable.qml");
        QQmlEngine qengine;
        QQmlComponent component(&qengine,QUrl::fromUserInput(homeLocation));
        QFile file(homeLocation);
    
        if( file.exists()){
            qDebug()<< "User file found..."<< homeLocation ;
            userItem = qobject_cast<QQuickItem*>(component.create());
            userItem->setParentItem(this)
        }    
    }
    

    //main.cpp

    qmlRegisterType<QMProgressBar>("QMProgressBar", 1, 0, "Bar");
    

    //main.qml

     Bar{
                id:bar
                height: 150
                width: 150
            }
    

    This works but i have at least 1 probleme :

    if 'Customizable.qml' contains just Rectangles/Texts/.. (not dynamic behavior) it will work.

    exemple Customizable.qml:

    Item{
        Rectangle{
            id:r
           color : "red"
           rotation : 45
       }
    }
    

    But if 'Customizable.qml' contains some dynamic behavior, it will not work

    exemple Customizable.qml:

    Item{
        Rectangle{
            id:r
           color : "red"
           rotation : 45
       }
       Timer{
            running:true
            repeat:true
            interval : 500
            onTriggered: r.rotation+=10 // item will not rotate
        }
    }
    

  • Lifetime Qt Champion

    Hi,

    Why not use a Loader ?



  • @SGaist hi,
    after your comment on my previous thread
    https://forum.qt.io/topic/87077/qt-application-with-public-qml-code-that-user-can-edit/2

    "One possible way is to copy the file you want to allow editing from the resource to a suitable writable location (see QStandardPaths).
    Then you have to tell your application to load that file if it exists otherwise the one from the resource.
    "

    I though the best solution was to do this by subclassing 'QQuickPaintedItem' ...

    I will try to do the same thing using Loader, it seems easier in fact.

    Thx!



  • Perfect, i dit it in 10 minutes with Loader !

    
        property Component qrcComponent
        property Component userComponent
    
    
        Component.onCompleted: {
    
            userComponent = Qt.createComponent("file:///C:/Users/userName/Documents/QML_CUSTOM_ITEM/Customizable.qml")
           //qrcComponent = Qt.createComponent("/Customizable.qml")
    
        }
    
        onUserComponentChanged: {
            if(userComponent.status==Component.Ready){
                l.sourceComponent = userComponent
            }
            else{
                qrcComponent = Qt.createComponent("/Customizable.qml")
                if(qrcComponent.status==Component.Ready){
                    l.sourceComponent = qrcComponent
                }
            }
        }
    
    
            Loader{
                id:l
                height: 150
                width: 150
                anchors.centerIn: parent
               // source: "file:///C:/Users/userName/Documents/QML_CUSTOM_ITEM/Customizable.qml" ||  "/Customizable.qml"
            }
    

    Thx



  • @SGaist said in QQuickPaintedItem from .qml file:

    Why not use a Loader ?

    FinalIy i did it with Loader , but is there a way to do the same thing with my QMProgressBar class ?



  • On my Loader exemple, Is it possible to Reload component runtime ?

        Button{
            text:"reload"
            onClicked: { /* RELOADING ? */
                userComponent = Qt.createComponent("file:///C:/Users/lagayev/Documents/QML_CUSTOM_ITEM/Customizable.qml");
            }
        }
    

    If i edit 'Customizable.qml' while application is running, and click this 'reload' button 'Customizable.qml' is unchanged,
    i have to quit and restart my app to see changes. Could you tell me Why ?



  • I tryed to clearComponentCache as it is described here :
    http://doc.qt.io/qt-5/qqmlengine.html#clearComponentCache

    class QmlEngineManager : public QQmlApplicationEngine
    {
        Q_OBJECT
    public:
        QmlEngineManager();
    
        Q_INVOKABLE void clearCache() {
            clearComponentCache();
            qDebug()<<"engine cleared !";
        }
    };
    

    Then in qml :

     Button{
            text:"reload"
            onClicked: { /* RELOADING ? */
                 engineManager.clearCache()
                userComponent = Qt.createComponent("file:///C:/Users/lagayev/Documents/QML_CUSTOM_ITEM/Customizable.qml");
            }
        }
    

    witout success.


  • Lifetime Qt Champion

    What about destroying userComponent before you create the new one ?



  • @SGaist with this code, when i start my app, it will create a component from file:///C:/Users/usr/Documents/QML_CUSTOM_ITEM/Customizable.qml if that file exists, else it will create component from /Customizable.qml

    But when app is running, if i DELETE 'Customizable.qml' file from that path (file:///C:/Users/usr/Documents/QML_CUSTOM_ITEM/Customizable.qml) , and press 'Reload' button, the same .qml file is displayed !

    It looks like content of a given path is calculated only when the application starts..?

    What is the probleme here ?

       signal updateComponents()
        Button{
            text: "Reload"
            onClicked: {
                updateComponents()
            }
        }
        Component.onCompleted:updateComponents()
      
      onUpdateComponents: {
         var tmp =  Qt.createComponent("file:///C:/Users/usr/Documents/QML_CUSTOM_ITEM/Customizable.qml")
         if(tmp.status===Component.Ready){
                     l.sourceComponent = tmp
         }
         else{
                 tmp=Qt.createComponent("/Customizable.qml")
                 if(tmp.status===Component.Ready){
                      l.sourceComponent=tmp
                   }
               }
                delete(tmp)
        }
    
        Loader{
            id:l
            height: 150
            width: 150
            anchors.centerIn: parent
        }
    

  • Lifetime Qt Champion

    I was rather thinking about what is described here.



  • @SGaist Hi,
    I did that way too, but no success because

    when my app calls :

      var component = Qt.createComponent("file:///C:/Users/user/Documents/QML_CUSTOM_ITEM/Destructible.qml")
    

    inside that directory ("file:///C:/Users/user/Documents/QML_CUSTOM_ITEM") another file is created by qt, named

    Destructible.qmlc ( 'c' like copy ? )

    Next call 'Qt.createComponent()' loads that 'Destructible.qmlc'


  • Lifetime Qt Champion

    This presentation might help.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.