[Interest] Some questions on QSettings, qmlRegisterType() and setContextProperty

Jayesh Bhoot mister.bhoot at gmail.com
Sat Aug 10 07:35:32 CEST 2013


Short, but informative reply. :)

>
> 2., but calling init in C++ componentComplete() (derive from
> QQmlParserStatus as well) automatically, taking the input from
> properties set in QML.
>
I want to clarify something here. The C++ OAuth2 class provides the data  
and logic to the OAuth2Browser QML window. It has a structure something  
like this:

class OAuth2 : public QObject
{
     Q_OBJECT
     Q_PROPERTY(QUrl oauthUrl READ oauthUrl)

public:
     explicit OAuth2(QObject *parent = 0);
     explicit OAuth2(QString& appId, QUrl& redirectUrl, QStringList&  
permissions, QObject *parent = 0);

     QUrl oauthUrl() const;

signals:
     void oauthSucceeded(QString userAccessToken);
     void oauthFailed();

public slots:
     void onBrowsingUrlChanged(const QUrl& url);

private:
     QString parseUserAccessToken(const QUrl& url) const; // called by  
onBrowsingUrlChanged()

     static const QString m_oauthEndPoint;
     QString m_appId;
     QUrl m_redirectUrl;
     QStringList m_permissions;
     QString m_userAccessToken;
};

This is how the QML class uses it:

Window {
     id: oauth2Browser
     width: 500
     height: 500

     ColumnLayout {
         anchors.fill: parent

         WebView {
             objectName: "Browser"
             id: browser
             Layout.fillHeight: true
             Layout.fillWidth: true

             url: oauth2.oauthUrl
             onUrlChanged: oauth2.onBrowsingUrlChanged(browser.url)
         }

         Label {
             id: loadingStatus
             Layout.fillWidth: true
             text: browser.loadProgress + "% loaded."
         }
     }
}

Thus, its the C++ class that sets the properties, and not the QML window  
that does it. By your method, I assumes that I would have to derive OAuth2  
 from QQmlParserStatus in order to track properties set by QML window.  
However, its the other way round - QML window takes data from an instance  
of the C++ class.
How should I proceed then?

Also, feel free to point out if my current design is flawed.

> qmlRegisterType is better than setContextProperty, because that way
> the flow is controlled from QML (and a lack of constructor arguments
> is correct for declarative design, you can do additional property
> based initialization in componentComplete). Good QML design has C++
> expose functionality to QML but lets QML control the entire UI flow
> (including window creation/handling).

I agree with preferring qmlRegisterType over setContextProperty. But  
wouldn't your C++ QQmlParserStatus::componentComplete() approach work only  
if the data comes from QML to C++? I think that would be the case most of  
the time. But how should I handle the other way round, like in my case, or  
say, while grabbing data from database or application settings?


>> 1. Is exposing QSettings directly to QML UI a good idea?
>
> Directly? Not a good idea, but possible. The new Qt.labs.settings API
> aims to address this deficiency:
> https://codereview.qt-project.org/#change,59149

I will look forward to using this.



On Sat, 10 Aug 2013 03:34:19 +0530, Alan Alpert <416365416c at gmail.com>  
wrote:

> On Fri, Aug 9, 2013 at 8:12 AM, Jayesh Bhoot <mister.bhoot at gmail.com>  
> wrote:
>> I will try explaining my confusion through the application I am  
>> currently
>> developing.
>>
>> My application (based on Qt5.1 + Qt Quick Controls) interacts with
>> Facebook API to manage a Facebook Page. I am trying to keep the QML code
>> (for UI) as separate as possible from the C++ core.
>>
>> Now, an OAuth2 implementation is required to be able to interact with
>> Facebook API. For that, I have a C++ OAuth2 class, the constructor of
>> which has the following signature:
>>
>> OAuth2::OAuth2(QString appId, QString redirectUrl, QStringList
>> permissions);
>>
>> Now, as the OAuth process requires a browser, I have also implemented an
>> OAuthBrowser.qml, which uses OAuth2 to complete an authorization.
>>
>> I have the following options to expose OAuth2 class to OAuth2Browser:
>>
>> 1. Instantiate OAuth2 and use setContextProperty() to expose the  
>> instance
>> to OAuth2Browser. However, this means my C++ code has to deal with the  
>> UI
>> code. The more baffling issue is that OAuth2Browser is a secondary  
>> window.
>> When a user clicks on a "Authorize" window on the MainWindow, then an
>> AppController C++ object (connected to MainWindow) will launch the
>> OAuth2Browser window. Thus, the instantiation code of OAuth2Browser  
>> would
>> go deep down inside a AppController method. It would have been good if
>> only main.cpp had to deal with the window creation.
>>
>> 2. Use qmlRegisterType(). In this case, I can't pass parameters to the
>> constructor. So, I will have to implement an init() method that would
>> initialize an OAuth2 object. Then, I would call this init() method in
>> OAuth2Browser's Component.onCompleted() method.
>> However, in this approach, I will have to expose QSettings to the UI  
>> code
>> - QML window, so that the required parameters to init() method can be
>> retrieved. I have huge skepticism on whether directly exposing  
>> application
>> settings to QML UI is a good idea.
>>
>> 3. Implicitly use QSettings within the OAuth2 constructor. This way, I
>> won't have to pass any parameters, and I would be able to use
>> qmlRegisterType(). However, this means I am doing some magic stuff  
>> "behind
>> the curtains". Instead of explicitly passing QSettings instance, I am
>> using it wherever the hell I want to, thus hiding the initialization
>> detail from public API.
>>
>> An alternative based on the 3rd option was advised on IRC - use an
>> initFromSettings() type of method to initialize an instance if no
>> parameter is passed to the constructor. That way, the initialization is
>> not hidden, and initFromSettings() can confidently use QSettings within
>> itself. Now, I can happily use qmlRegisterType() to instantiate OAuth2  
>> in
>> QML.
>>
>> So, what is the better approach?
>
> 2., but calling init in C++ componentComplete() (derive from
> QQmlParserStatus as well) automatically, taking the input from
> properties set in QML.
>
>> Also,
>> 1. Is exposing QSettings directly to QML UI a good idea?
>
> Directly? Not a good idea, but possible. The new Qt.labs.settings API
> aims to address this deficiency:
> https://codereview.qt-project.org/#change,59149
>
>> 2. I personally prefer qmlRegisterType() to setContextProperty() - that
>> way, the lifetime of a registered class's instance is maintained solely  
>> by
>> QML. However, the former is less likely to be used due to the lack of
>> support of parameterized constructors, unless some form of init() is  
>> used
>> explicitly for initialization. Is that a good design?
>
> qmlRegisterType is better than setContextProperty, because that way
> the flow is controlled from QML (and a lack of constructor arguments
> is correct for declarative design, you can do additional property
> based initialization in componentComplete). Good QML design has C++
> expose functionality to QML but lets QML control the entire UI flow
> (including window creation/handling).
>
>>
>> I apologise in advance for an excruciatingly long post. But I thought it
>> best to ask here.
>
> Sorry for the excruciatingly short reply ;)
>
> --
> Alan Alpert


-- 
Using Opera's mail client: http://www.opera.com/mail/



More information about the Interest mailing list