4

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?

Delgan
  • 18,571
  • 11
  • 90
  • 141
Libor Tomsik
  • 668
  • 7
  • 24

2 Answers2

2

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.

Adrian Maire
  • 14,354
  • 9
  • 45
  • 85
  • I hoped there is some standard way without having to re-implement all getters and setters. – Libor Tomsik Feb 21 '17 at 07:36
  • There is room for improvement, I agree: for example, I miss also Q_PROPERTY of custom type (struct/class) and Q_PROPERTY accessing members of a struct/class. – Adrian Maire Feb 21 '17 at 09:03
  • @AdrianMaire You can use `Q_PROPERTY` with custom types. _"Custom types used by properties need to be registered using the Q_DECLARE_METATYPE() macro so that their values can be stored in QVariant objects. This makes them suitable for use with both static properties declared using the Q_PROPERTY() macro in class definitions and dynamic properties created at run-time."_ – Benjamin T Feb 22 '17 at 10:04
  • @BenjaminT: To my knowledge, you may use QVariant, but not a custom struct. Also, QtCreator will not understand your type. If I am wrong, please, provide me an example, it would be very useful. – Adrian Maire Feb 22 '17 at 10:14
  • 2
    @AdrianMaire if you have `struct MyStruct {...};` just add `Q_DECLARE_METATYPE(MyStruct)` and then you can write `Q_PROPERTY(MyStruct myProp READ myProp WRITE setMyProp NOTIFY myPropChanged)`. You might need to add a call to `qRegisterMetaType()` if you do more advanced stuff. – Benjamin T Feb 22 '17 at 10:42
  • @BenjaminT: Good to know. thanks. Not very useful still as not understood by QtDesigner. – Adrian Maire Feb 22 '17 at 11:03
  • @AdrianMaire Qt Designer it not the only use for Qt properties. For instance one could use custom type properties with QML or with qpropertybrowser. – Benjamin T Feb 22 '17 at 13:14
0

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.

pestophagous
  • 4,069
  • 3
  • 33
  • 42