user2494298
user2494298

Reputation: 299

Qt Signals and Slots Confusion

I have been reading about Qt signals and slots and I am trying to get this to work, but until now without success. I hope someone can point me in the right direction.
I have two files, homeCommand.cpp and messagelogcommand.cpp. I have a QPlainTextEdit object in messagelogcommand.cpp that I want to update from homeCommand.cpp.
How can I do this using signals and slots? My signal is being called, as my QDebug is being printed out once a second, however the widget does not update.

This is what I am trying to do:

In MessageLogCommand.h

class MessageLogCommand : public QWidget
{
    Q_OBJECT
public:
    explicit MessageLogCommand(QWidget *parent = 0);

    QLabel *homeLabel;
    QPlainTextEdit *messageLog;

public Q_SLOTS:
    void updateWidgets(const QString &text);

};

homeCommand.h

class homeCommand : public QWidget
{
    Q_OBJECT

Q_SIGNALS:
    void textChanged(const QString &text);

public:
    explicit homeCommand(QWidget *parent = 0);

public slots:
    void run(void);
    void getHealthStatusPacket(void);

homeCommand.cpp

homeCommand::homeCommand(QWidget *parent) : QWidget(parent)
{
    ...
    //Timer
    QTimer *timer = new QTimer(this);
    timer->setSingleShot(false);
    connect(timer, SIGNAL(timeout()), this, SLOT(run()));
    timer->start(1000);

    setLayout(layout);
}

void homeCommand::run(void)
{
    getHealthStatusPacket();
}

void homeCommand::getHealthStatusPacket(void)
{
    ...
    Q_EMIT textChanged("ZOMG");
}

In MessageLogCommand.cpp

 MessageLogCommand::MessageLogCommand(QWidget *parent) : QWidget(parent)
 {

    QGridLayout *layout = new QGridLayout;
    QWidget::setFixedHeight(600);

    //Sub-system Label
    homeLabel = new QLabel("GSS Message Log");
    QFont subsystemFont = homeLabel->font();
    subsystemFont.setPointSize(12);
    subsystemFont.setBold(true);
    homeLabel->setFont(subsystemFont);
    layout->addWidget(homeLabel, 0, 0);

    //Event Log
    messageLog = new QPlainTextEdit();
    messageLog->setFixedHeight(500);
    messageLog->setFixedWidth(600);
    layout->addWidget(messageLog, 2,0);

    setLayout(layout);
}

void MessageLogCommand::updateWidgets(const QString &text)
{
    qDebug() << "Here";
    messageLog->appendPlainText(text);
}

In main.cpp

MessageLogCommand s;
homeCommand m;

QObject::connect(&m, SIGNAL(textChanged(QString)), &s, SLOT(updateWidgets(QString)));

Upvotes: 0

Views: 2063

Answers (3)

Kurt Pattyn
Kurt Pattyn

Reputation: 2788

A very basic example is:

class MainClass:public QObject    //class must be derived from QObject!
{
   Q_OBJECT    //this macro must be in the class definition
               //so the moc compiler can generate the necessary glue code

   public:
       void doSomething() {
           ...
           Q_EMIT textChanged(someText);
       }

   Q_SIGNALS:
       void textChanged(const QString &text);
};

class SubClass:public QObject
{
   Q_OBJECT

   public Q_SLOTS:
       void onTextChanged(const QString &text) {    //do not inline
           //do something
       }
};

int main()
{
    QApplication a;

    MainClass m;
    SubClass s;
    QObject::connect(&m, SIGNAL(textChanged(QString)),
                     &s, SLOT(onTextChanged(QString)));  //const and & are removed from
                                                         //the arguments

    return a.exec();    //run the event loop
}

So, there are 2 things important: 1. Signals and slots must be declared in a class derived from QObject 2. The classes containing signals and slots declarations must add the Q_OBJECT macro to the class declaration

To keep it simple for you: always declare your classes containing signals or slots in a header file (never in a .cpp file).

Upvotes: 2

Sharbag
Sharbag

Reputation: 255

I try to explain it.

In main.h you should to declare a signal:

signals:
     void textChanged(const QString& text);

And in messagelog.h you should to declare a slot:

public slots:
     void updateWidgets(const QString& text);

In main.cpp you should emit this signal:

void TheMethod() {
    emit this->textChanged("Your text/value");
}

In messagelog.cpp you should get this value:

// Note: Normalized signal/slot signatures drop the consts and references.
connect(&a, SIGNAL(textChanged(QString)), this, SLOT(updateWidgets(QString)));

void updateWidgets(const QString& text) {
   messageLog = new QPlainTextEdit();
   messageLog->setFixedHeight(500);
   messageLog->setFixedWidth(600);
   messageLog->setPlainText(text)
   layout->addWidget(messageLog, 2,0);
}

I think it should works.

UPDATE: Complete example: https://dl.dropboxusercontent.com/u/29647980/test.zip

Upvotes: -1

Ferenc Deak
Ferenc Deak

Reputation: 35408

A very good starting point for signals and slots is: http://woboq.com/blog/how-qt-signals-slots-work.html but also the official Qt doc does it: http://qt-project.org/doc/qt-4.8/signalsandslots.html

Basically what happens: you declare some special methods (signals and slots), at the compilation phase Qt generates extra CPP files which take care of your methods (moc) then everything is compiled and linked together and at the end when Qt or someone else emits a signal it will go to the corresponding slot.

Upvotes: 0

Related Questions