Qt application with public QML code that user can edit



  • Hello,

    I want to allow users to change visual aspect of my application editing '.qml' files.

    I know this is possible but have no idea how. Can someone put me on the right track please ?

    I found this :

    QML files in the file system

    Files are stored without compression and encryption

    Faster to build but slower to deploy
    Stored without compression so they take more storage space
    Easy to do UI changes on the fly on target (just edit QML and restart) < this is what i need i think
    

    so how to store files without compression and encryption?

    QML files in the resource file

    Resources are compiled to the binary file making the executable file size bigger

    Slower to build but faster to deploy.
    Takes less storage space because resources are compressed by default.
    Because the executable size is bigger the program takes more memory when running.
    You can't do changes to UI without re-compiling
    

    Thx in advance
    LA


  • Lifetime Qt Champion

    Hi,

    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.



  • @SGaist Thx!


  • Lifetime Qt Champion

    Note that this also allows you to do a "reset" if the edits ends breaking something (and you can be sure it will at some point)



  • @SGaist thx again.

    I sublclassed QQuickPaintedItem;

    constructor:

    #include "qmprogressbar.h"
    
    QMProgressBar::QMProgressBar()
    {
    
        QString homeLocation = QStandardPaths::locate(QStandardPaths::DocumentsLocation, QString(), QStandardPaths::LocateDirectory);
        homeLocation.append("QMProgressBar.qml");
        QQmlEngine qengine;
          QFile file(homeLocation);
    
        if( file.exists()){
            qDebug()<< "User file found..."<< homeLocation ;
            QQmlComponent component(&qengine,QUrl::fromUserInput(homeLocation));
            userItem = qobject_cast<QQuickItem*>(component.create());
            qDebug()<< userItem->property("maxValue");
        }
        else{
            homeLocation = ":/QMProgressBar.qml";
                   QFile homefile(homeLocation);
            if(homefile.exists()){
                qDebug()<< "QRC file found..."<< homeLocation;
             QQmlComponent component(&qengine,QUrl::fromUserInput(homeLocation));
                userItem = qobject_cast<QQuickItem*>(component.create());
                qDebug()<< userItem->property("maxValue");
            }
        }
    
        userItem->deleteLater();
    
    }
    
    

    if file exists in writable homeLocation it will be used else
    qrc file is used. This is ok.

    Now could you please tell me how can i display this item on the screen ?

    I saw this exemple http://doc.qt.io/qt-5/qtquick-scenegraph-customgeometry-example.html
    but i can not understand what exactly i have to do ..

    Do i have to implement paint(QPainter *painter) method ?



  • I did this :

    void QMProgressBar::paint(QPainter *painter){
      //test
          painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16); // this works
          
    }
    

    There is a method drawPixmap( x,y,w,h,QPixmap &pm )

    so I'm trying to convert my QMProgressBar.qml to a pixmap :

    void QMProgressBar::paint(QPainter *painter){
      
    QPixmap itemPxMap;
         itemPxMap.load("qrc:///QMProgressBar.qml");
         painter->drawPixmap(50,50,100,100,itemPxMap);   // this will not work : application starts and shows white screen
    
    }
    

    Is it possible to convert a .qml file to QPixmap ? Please tell me what i'm doing wrong here.


  • Lifetime Qt Champion

    What exactly are you trying to achieve ? I thought you wanted to load a QML file and run it live in your application which seems to not be what you are doing.



  • @SGaist hello,
    As i said i'm trying to create a qtQuick app, with .qml files avalabls for the user (user can edit qml files)

    @SGaist said in Qt application with public QML code that user can edit:

    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.

    So I'm trying to subclass QQuickPaintedItem,

     class QMProgressBar :  public QQuickPaintedItem{
    
       // I want to read a .qml file ('user file' if it exists, otherwise the one from the resource)  create the item corresponding that qml code,  show it on the screen
       
    };
    

    then i will register my class : qmlRegisterType<QMProgressBar>("QMProgressBar", 1, 0, "Bar");

    To be able to create QMProgressBar{} in QML.

    So, for the moment in my class I'm able to load the right file, cast it to QQuickItem*, read properties :

     QQmlComponent component(&qengine, QUrl::fromUserInput(homeLocation));
     userItem = qobject_cast<QQuickItem*>(component.create());
     qDebug() << userItem->property("maxValue"); 
    

    Last thing i have to do, is to show that item.

    Thx



  • Like this exemple : http://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html

    except :

    void PieChart::paint(QPainter *painter)
    {
        QPen pen(m_color, 2);
        painter->setPen(pen);
        painter->setRenderHints(QPainter::Antialiasing, true);
      //  painter->drawPie(boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16);
     //instead of  'drawPie()',  i want to drow 'userItem'
    }
    


  • @LeLev said in Qt application with public QML code that user can edit:

    Last thing i have to do, is to show that item.

    Ok, last thing to do was to set the visual parent of my qquickitem ! now is is working.

      userItem->setParentItem(this);
    

    @SGaist thank you very much for help!
    LA


Log in to reply
 

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