Libor Tomsik
Libor Tomsik

Reputation: 718

Exposing Q_PROPERTY from private member

In the code I'm working on I need to expose Q_PROPERTY from private member(s) through one integrating QWidget. Something like this would be nice:

class MyWidget: public QWidget{
   Q_OBJECT
   Q_PROPERTY(QString headerText MEMBER myLabel.text NOTIFY QLabel::notify)

private:
   QLabel myLabel
}

Is it possible to do so and how? Or do I have to write all the get/set methods manually?

Upvotes: 5

Views: 1986

Answers (2)

pestophagous
pestophagous

Reputation: 4233

The OP wants to avoid the manual boilerplate of getter/setter pairs that would not need to be written if we didn't want to expose a Q_PROPERTY.

I don't have a solution for that, but I am still interested in the "private members" aspect of the question.

In my case, I arrived here because I wanted to hide these required setters from all other code EXCEPT for Qt binding code.

Empirically, using Qt 5.12, the following does work for me:

   class HolderOfSomeInteger : public QObject {
     Q_OBJECT

     Q_PROPERTY(int someInt
                READ GetInt
                NOTIFY someIntChanged)

    signals:
     void someIntChanged();

    private:  // <--- private section
     // My own other classes cannot access this, but 
     // the QML binding works as expected anyhow.
     int GetInt() const { return some_integer; }

     int some_integer = 0;
   };

So, in addition to keeping the int data-member some_integer private, I apparently can simply put the GetInt() getter in the private section as well.

However, as @adrian-maire said in https://stackoverflow.com/a/42348046/10278, "for some versions of Qt, you may find some tricks working, but they may stop working in a following version."

As this Qt Property System documentation looks today, it only says

"A READ accessor function is required if no MEMBER variable was specified. It is for reading the property value. Ideally, a const function is used for this purpose, and it must return either the property's type or a const reference to that type."

It says nothing about whether the accessor function must be public or private.


I dug some more, and I think I found out why the property binding still works with a private getter.

The Q_OBJECT macro declares that your class has methods qt_metacall and qt_static_metacall. Qt's MOC then generates the bodies of these methods.

The property binding is accomplished using those methods. Since those methods are members of your class, they (of course) can call even the private member functions that your class provides.

Upvotes: 1

Adrian Maire
Adrian Maire

Reputation: 14845

You have to write your own getter/setter:

QString getText()const{ return myLabel.text();}
void setText( const QString& s){ myLabel.setText(s);}

And after you may define a Q_PROPERTY for it:

Q_PROPERTY( QString headerText READ getText WRITE setText)

Note: for some versions of Qt, you may found some tricks working, but they may stop working in a following version. For this reason, it is probably better to stick to common/standard behavior.

EDITED:

To add a bit of formalism to this answer, here is a related bug:

https://bugreports.qt.io/browse/QTBUG-47695?jql=text%20~%20%22Q_PROPERTY%20member%22

Summarizing: In Qt<=5.4 it was possible to use structure members in the Q_PROPERTY MEMBER parameter. This feature "Worked by chance" and is not supported from now.

Upvotes: 2

Related Questions