PDA

View Full Version : Signal/Slots with PIMPL



kwalle
2nd September 2011, 10:28
I try to use Qts Signal/Slot mechanism with private implementation (PIMPL).

My header file is build like:


class Foo : public QWidget
{
Q_OBJECT
public:
...
private:
class FooPrivate;
FooPrivate *d;
}


My source file is build like:


Foo::FooPrivate : public QWidget
{
public:
...
public slots:
void doSomething();
signals:
void emitSomething();
}


Due to this private implementation, the private signals and slots are declared inside the source file and not recognized by Q_OBJECT.

Is there an other way to use the signal/slot mechanism inside a local class?

Thanks

Kai

high_flyer
2nd September 2011, 10:41
the private signals and slots are declared inside the source file and not recognized by Q_OBJECT.
Did you really meant what you wrote here?
Your code clearly declares the signals/slots of your private class in the header.
And if you add the Q_OBJECT macro to your private class, it should compile as well.

kwalle
2nd September 2011, 11:05
Qt ignores the signals and slotes defined in my source.cpp as they have to be defined in the source.h.

If I add another Q_OBJECT inside Foo::FooPrivate I got a lot of Linker errors.

yeye_olive
2nd September 2011, 11:06
You declared FooPrivate in a source (.cpp) file, which hides it from moc. You have to move it to a header (.h) file. The convention in the Qt sources is to add the "_p" suffix to the file name to denote that it is a private header meant to be parsed by moc but not directly included by the user. In your case you would have e.g. Foo.h, Foo.cpp, and Foo_p.h.

Also I am not sure that moc supports inner classes. You might have to move FooPrivate out of Foo.

high_flyer
2nd September 2011, 11:08
Qt ignores the signals and slotes defined in my source.cpp as they have to be defined in the source.h.
The signals have to be declared in the header.
The slots as well.

The slots have to be defined in the source file.


If I add another Q_OBJECT inside Foo::FooPrivate I got a lot of Linker errors.
Show the errors you get.

EDIT:
Ah, i just now noticed this:

My source file is build like:
The class declaration has to be in a header file.

kwalle
2nd September 2011, 11:14
You declared FooPrivate in a source (.cpp) file, which hides it from moc. You have to move it to a header (.h) file. The convention in the Qt sources is to add the "_p" suffix to the file name to denote that it is a private header meant to be parsed by moc but not directly included by the user. In your case you would have e.g. Foo.h, Foo.cpp, and Foo_p.h.

Also I am not sure that moc supports inner classes. You might have to move FooPrivate out of Foo.

But am I right that I have to deliver Foo_p.h if someone wants to use my Foo.h with Foo.dll???

yeye_olive
2nd September 2011, 11:48
But am I right that I have to deliver Foo_p.h if someone wants to use my Foo.h with Foo.dll???
I believe it would not be necessary to distribute Foo_p.h to the users of the library.

Lykurg
2nd September 2011, 12:43
Well the whole PIMPL approach is a bit senseless if you expose the nature of your private class in the *.h file. You can declare it the cpp file but then add
#include "foo.moc"at the end of the file, that it is recognized by the MOC compiler.

high_flyer
2nd September 2011, 13:26
You can declare it the cpp file but then add
For that you first need to have the moc file, which is generated by the moc compiler...
If you want to use Q_OBJECT you will have first to have this in a header, run moc on it, and then add #include "foo.moc".
AFAIK at least.

Lykurg
3rd September 2011, 22:35
On my side this works perfect:


//main.cpp
#include <QtCore>
#include "outer.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

Outer o;
QTimer::singleShot(1000, &a, SLOT(quit()));

return a.exec();
}



//outer.h
#ifndef OUTER_H
#define OUTER_H

#include <QObject>
class Inner;

class Outer : public QObject
{
Q_OBJECT
public:
explicit Outer(QObject *parent = 0);
public Q_SLOTS:
void mySlot();
private:
Inner* m_inner;
};

#endif // OUTER_H



//outer.cpp
#include "outer.h"

#include <QtCore>


class Inner : public QObject
{
Q_OBJECT
public:
Inner(QObject *p) : QObject(p) {}
Q_SIGNALS:
void mySignal();
public:
void emitMySignal() {Q_EMIT mySignal();}
};

Outer::Outer(QObject *parent) :
QObject(parent)
{
m_inner = new Inner(this);
connect(m_inner, SIGNAL(mySignal()), this, SLOT(mySlot()));
m_inner->emitMySignal();
}

void Outer::mySlot()
{
qWarning() << Q_FUNC_INFO;
}

#include "outer.moc"


And don't forget to rerun qmake...

wysota
4th September 2011, 19:02
Here is a magic trick:

// foo.h
class Foo : public QWidget
{
Q_OBJECT
public:
...
private:
class FooPrivate;
FooPrivate *d;
Q_PRIVATE_SLOT(d, void doSomething());
};

//foo.cpp
#include "foo.h"
class FooPrivate {
public:
void doSomething() { qDebug() << Q_FUNC_INFO; }
};

#include "foo.moc" // this does the magic

Then you can do:

Foo foo;
connect(something, SIGNAL(...), &foo, SLOT(doSomething()));

high_flyer
5th September 2011, 10:17
@Lykurg:

//main.cpp
#include <QtCore>
#include "outer.h"


Ok, now I see what you meant... :-)