xcimo
xcimo

Reputation:

Qt signal to specific object's slot

I would like to know which of the following is the proper way of doing thing with signal/slot in Qt.

I need a way to have multiple instance of a Dialog, i.e: A and B. And I need to tell A to print "A" and B to print "B" from a different thread. So I believe I need something like either:

OPTION 1) A->print("A") and B->print("B")

or is it better to do:

OPTION 2) emit print("A") and emit print("B") and use a way that I don't know so only A catch the "A" and only B catch the "B".

I got the option 1 working like this:

class myClass : public QMainWindow
{
    Q_OBJECT

public:
    myClass (QWidget *parent = 0, Qt::WFlags flags = 0);
    ~myClass ();
    void doPrint(char* text)
    {
         emit mySignal(text);
    }
private:
    Ui::myClass ui;

public slots:
    void newLog(char* msg);

signals:
     void mySignal(char* msg);
};

myClass::myClass(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
    ui.setupUi(this);
    connect(this, SIGNAL(mySignal(char*)), this, SLOT(newLog(char*)));
}

void myClass::newLog(char* msg)
{
    ui.textEdit->append(msg);
}

and then all I have to do is:

myClass* instanceA = new myClass();
myClass* instanceB = new myClass();
instanceA->doPrint("A");
instanceB->doPrint("B");

is this right?

Thanks!

Upvotes: 4

Views: 4376

Answers (2)

pandacrunch1337
pandacrunch1337

Reputation: 31

Since your slot is in another thread, you have to use the Meta-Object System to invoke the method asynchronously. The proper way to do this is to use QMetaObject::invokeMethod

DO NOT subclass QThread and override the run method. For details on this see: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong

void otherClass::printTo(myClass* instance, char* text)
{
    QMetaObject::invokeMethod(instance,        // pointer to a QObject
                              "doPrint",       // member name (no parameters here)
                              Qt::QueuedConnection,     // connection type
                              Q_ARG(char*, text));     // parameters
}

void myClass::doPrint(char* text)
{
    ui.textEdit->append(text);
}

myClass* instanceA = new myClass();
myClass* instanceB = new myClass();
printTo(instanceA, "A");
printTo(instanceB, "B");

If the char* type hasn't been registered with the Meta-Object System yet, do so with Q_DECLARE_METATYPE(char*);

then:

qRegisterMetaType<char*>("charPtr");

Upvotes: 3

Caleb Huitt - cjhuitt
Caleb Huitt - cjhuitt

Reputation: 14941

In this simplified example, I think you are on the correct path with option 1. However, it would be even better if you didn't need the doPrint() method, which would also eliminate the need for the mySignal signal (at least in myClass). Instead, I would suggest inheriting your threads from QThread if the aren't already, and doing something like this:

class myThread : public QThread
{
    Q_OBJECT

public:
    myThread (QWidget *parent = 0 ) : QThread(parent) {}
    ~myThread () {}
    void run(char* text)
    {
         emit mySignal(text);
    }

signals:
     void mySignal(char* msg);
};

Then you need to do something like this:

myClass* instanceA = new myClass();
myThread* threadA = new myThread();
connect(threadA, SIGNAL(mySignal(char*)), instanceA, SLOT(newLog(char*)), Qt::QueuedConnection);
threadA->run( "A" );

Obviously, in most non-example code, you'd not pass the string into run, but rather generate strings to be run as threadA is running. The advantage is that this keeps the thread considerations out of myClass, and you only need to think about them where they are connected. On the flip side, you introduce fewer dependencies into the threads, since they don't need to know about myClass to be able to log.

Upvotes: 0

Related Questions