0

I'm trying to use a macro to simplify Qt properties, so I don't need to manually define the reader and writer methods and the notify signal:

#define PROPERTY(type, name, reader, writer)                                    \
public:                                                                         \
    Q_PROPERTY(type name READ reader WRITE writer NOTIFY name ## Changed)       \
                                                                                \
    type reader() const {                                                       \
        return m_ ## name;                                                      \
    }                                                                           \
                                                                                \
public Q_SLOT:                                                                  \
    void writer(type name) {                                                    \
        m_ ## name = name;                                                      \
        emit name ## Changed(name);                                             \
    }                                                                           \
                                                                                \
private:                                                                        \
        type m_ ## name;                                                        \
                                                                                \
Q_SIGNAL:                                                                       \
    void name ## Changed(type name);

Then I use it like:

class Test : public QObject
{
    Q_OBJECT

    PROPERTY(QString, name, name, setName)
}

However, I get errors during linking:

CMakeFiles/weather-desktop.dir/weather/location.o: In function `Weather::Location::setName(QString)':
/home/mspencer/Programs/weather-desktop/src/weather/location.h:37: undefined reference to `Weather::Location::nameChanged(QString)'
collect2: error: ld returned 1 exit status
make[2]: *** [src/weather-desktop] Error 1
make[1]: *** [src/CMakeFiles/weather-desktop.dir/all] Error 2
make: *** [all] Error 2

I think this is because Qt doesn't support multiple signals sections, which is what results from using my macro. What is best way to write and use a macro to simplify Qt Properties?

Edit: After looking at this question and the moc documentation, I think this is because moc doesn't expand #defines. Is there any way to work around this?

Community
  • 1
  • 1
iBelieve
  • 1,502
  • 17
  • 32
  • Change to `Q_SLOTS` and `Q_SIGNALS`. – Alexander Shukaev Apr 19 '13 at 16:07
  • @Haroogan just tried that, doesn't work. Besides, I was using `Q_SLOT`/`Q_SIGNAL` because [the docs](http://qt-project.org/doc/qt-4.8/qobject.html#Q_SIGNAL) says you can use this for just one signal or slot. – iBelieve Apr 19 '13 at 16:10
  • Oh, well, I've missed that you've already found a cause. I don't think there can be any workaround for this. If it doesn't expand them, then it doesn't. The only thing you could do is to preprocess your source files, i.e. run the through preprocessor and then feed these preprocessed sources (with expanded macros) to MOC. But that smells like you'd have to opt for more powerful build system than plain QMake, for example to [WAF](https://code.google.com/p/waf/). Anyway that sounds like overkill for such a minor convenience gain. – Alexander Shukaev Apr 19 '13 at 16:15
  • If you look at the source or the headers for some of the other QWidgets out there that have a lot of built in properties, you can just copy paste, their code. – phyatt Apr 19 '13 at 16:23
  • @Haroogan I'm not using QMake, I'm using CMake, as this is a KDE app. I don't think preprocessing works, since it would also preprocess Qt stuff. What do you mean, just copy and paste their code? The whole point of my macro is to keep from manual copy/paste stuff and mistakes in doing so. – iBelieve Apr 19 '13 at 16:32
  • Of course, you'd have to guard them with other macros. As I said all this is an overkill. – Alexander Shukaev Apr 19 '13 at 16:53

1 Answers1

0

I came up with a simple Python script that will implement whatever you leave out, including the internal variable, the getter, the setter, and the notify signal. The cool thing about how it works instead of my original macro is that I don't need multiple macros if I want to customize how one of the methods work. All I need to is define the method in the class and the script will not generate it.

To use the script, include a special header called <filename>.gen inside the class, like this:

class Test {
    Q_OBJECT

    Q_PROPERTY(int test READ test)

#include "test.gen"
}

Then, you need to run mkprop on it:

mkprop test.h build/test.gen build/test.h

Because moc doesn't search the include path, the source file needs to be in the same directory as the generated header:

cp test.cpp build/test.cpp

build/test.h and build/test.cpp will be the actual code used by moc. Make sure you add build to your list of include directories, and add build/test.cpp to the list of source files.

Note: I'm working on a way to automatically run this in CMake, but I'm having dificulties getting moc to run on the files.

iBelieve
  • 1,502
  • 17
  • 32