How can I emit a signal from another class?

lagoru picture lagoru · Mar 2, 2013 · Viewed 37.6k times · Source

I have a problem with my Qt application. I'm trying to emit a signal from within another class (it is a nested class of the one in which the signal is placed).

I already connected the signal with a slot, which should be fine. But when I try to emit this signal from within this nested class I get the compiler error:

cannot call member function without object

What is wrong? I looked for that in Qt documentation but couldn't find reasonable solution or even explanation.

The simplified class definition looks as follows.

class LogWriter : public QDialog
{   
   Q_OBJECT

public:
   class Log : public QObject
   {
      Q_OBJECT

   public:
      bool print;

      Log(bool _print, QString _color, QObject *obj = NULL)
         : QObject(obj)
      {
         print = _print;
         color = _color;
      }
   };

   LogWriter(QWidget * parent = 0);
   ~LogWriter();

public slots:
   void setMinVal();
   void setMediumVal();
   void setHighVal();
   void cleanWindow();
   void appendText(QString &text);

signals:
   void signalLogAppend(QString);
};

I connect the signal of an instance LOW of the LogWriter in the client code to some slot using the following function call:

connect(&LOW, SIGNAL(signalLogAppend(QString)),
        this, SLOT(appendText(QString&)),
        Qt::DirectConnection);

Answer

leemes picture leemes · Mar 2, 2013

To understand the issue you have to understand how signals are emitted:

They are simply a non-static member function call and thus require an instance to be called on (the "sender"). Typically, this instance is this (if you emit the signal from within another non-static member function of the same class), so the call syntax becomes a normal function call without any (literal) instance. The emit keyword is optional and is simply a macro which expands to nothing. The following four versions are all the same when written in a member function of the same class which contains the signal:

emit this->signalLogAppend("foo");
emit signalLogAppend("foo");
this->signalLogAppend("foo");
signalLogAppend("foo");

If you emit the signal of the outer class from within the inner class, the this pointer refers to an instance of the inner class and thus there is some instance missing for the outer class. It's the same like if you call any other function of the outer class from within the inner class: the compiler doesn't know on which object instance (of the outer class) to call it on. So you have to write something like:

emit someLogWriter->signalLogAppend("foo");

Here, someLogWriter is the instance of LogWriter for which you want to emit the signal.