PDA

View Full Version : Questions about Q_PROPERTY and Q_OBJECT



zephod
19th April 2012, 03:47
I've have been investigating QtScript and I wrote a little test program which worked. The expression first evaluates false and the second time true.



#include <iostream>

#include <QApplication>
#include <QtScript>
#include <QObject>
#include <QWidget>


class MyClass : public QObject
{
Q_PROPERTY(bool x)
Q_PROPERTY(int y)
};

using namespace std;

int main(int argc, char* argv[])
{
QApplication app(argc, argv);

MyClass mc;

QScriptEngine eng;
QScriptValue scriptClass = eng.newQObject(&mc);
QScriptValue global = eng.globalObject();
global.setProperty("myClass", scriptClass);

const QString expr = "myClass.x == true && myClass.y == 2";

mc.setProperty("x", true);
mc.setProperty("y", 0);
QScriptValue res = eng.evaluate(expr);
cout << "result = " << res.toBoolean() << endl;

mc.setProperty("y", 2);
res = eng.evaluate(expr);
cout << "result = " << res.toBoolean() << endl;

return 0;
}

Then it occurred to me that perhaps it should not have compiled. The documentation for Q_PROPERTY says that
The property name and type and the READ function are required but I didn't have a read function defined so how did that work?

The next thing I wanted to do was to add a slot so I added Q_OBJECT above the Q_PROPERTY line, ran gmake clean, make-qt4 and gmake. I got these linker errors:
main.o: In function `MyClass': undefined reference to `vtable for MyClass'
main.o: In function `~MyClass': undefined reference to `vtable for MyClass'

It's referring to a constructor and destructor I don't have so I tried adding my own empty ones but that didn't help.
Next I though that perhaps I have to define at least one slot or signal so I added one but that didn't help.

Here is where it gets a little weird, at least to me. I took the class definition and put it in a .h file without changing anything apart from adding the #include of course, re-ran everything and now it links OK and I get warnings about the Q_PROPERTY macros not having a read function and that the properties will be invalid. So I added the read functions to the Q_PROPERTY lines, defined the functions and added some private variables.

Cool! now everyting compiles and links without errors and warnings.
Just one problem - the evaluation of the expression is now false in both cases!!!

ChrisW67
19th April 2012, 05:44
The Q_PROPERTY macro does nothing as far as the C++ compiler is concerned, i.e. "bool x" simply disappears. I suspect that dynamic properties may have been created in your version. Your original code example was not having moc run it so the additional code that should have been created was not. By separating the MyObject declaration into a header listed in HEADERS you caused moc to run on it, which is why the warnings were issued. Your QObject sub class still needs a Q_OBJECT macro to make it work though.

Here it is adjusted to work:


#include <iostream>
#include <QApplication>
#include <QtScript>
#include <QObject>
#include <QWidget>

class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(bool x READ x WRITE setX)
Q_PROPERTY(int y READ y WRITE setY)

public:
bool x() { return m_x; }
void setX(bool x) { m_x = x; }
int y() { return m_y; }
void setY(int y) { m_y = y; }

private:
bool m_x;
int m_y;
};

using namespace std;

int main(int argc, char* argv[])
{
QApplication app(argc, argv);

MyClass mc;

QScriptEngine eng;
QScriptValue scriptClass = eng.newQObject(&mc);
QScriptValue global = eng.globalObject();
global.setProperty("myClass", scriptClass);

const QString expr = "myClass.x == true && myClass.y == 2";

mc.setProperty("x", true);
mc.setProperty("y", 0);
QScriptValue res = eng.evaluate(expr);
cout << "result = " << res.toBoolean() << endl;

mc.setProperty("y", 2);
res = eng.evaluate(expr);
cout << "result = " << res.toBoolean() << endl;

return 0;
}
// this line triggers moc to run in single-file programs like this
#include "main.moc"

zephod
19th April 2012, 14:00
Hi ChrisW67,

Thanks for the explanation. That actually makes sense now. In my version that had the class definition in a header file, the reason it was not working was that I was missing the WRITE functions.

alnorte
23rd April 2012, 10:28
Hi, I'm making a custom widget and I used the same structure but now I need hide or show one Q_PROPERTY that depends to another Q_PROPERTY.

Is a button type, and I select the button behavior in a Q_Property with a combo selection. Depends selection I need Q_PROPERTY "a" or Q_PROPERTY "b", and only show one of this two options.

I can do something like that? I know that are dynamically properties but I don't know that are designer time or run time dynamically properties.

thanks.

wysota
23rd April 2012, 12:11
No, you can't "hide" properties of an object. You can only provide an invalid value to a property which should be sufficient for your needs.

alnorte
23rd April 2012, 12:58
I solved my problem using DESIGNABLE function in the Q_PROPERTY. With this function a enabled or disabled the property.