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 .hclass QMProgressBar : public QQuickPaintedItem { Q_OBJECT public: QMProgressBar(QQuickItem *parent = 0); private: QQuickItem* userItem; // void paint(QPainter *painter); };
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) } }
qmlRegisterType<QMProgressBar>("QMProgressBar", 1, 0, "Bar");
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 } }
-
@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
-
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#clearComponentCacheclass 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.
-
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 }
-
@SGaist Hi,
I did that way too, but no success becausewhen 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'
-
This presentation might help.