user2440074
user2440074

Reputation:

Call Qt object method from another std::thread

I have simple Qt form which represents main window of my app. It has method:

void gui_popup::on_pushButton_clicked()
{
    QString text = ui->MainText->toPlainText();
    text = "1\n" + text;
    ui->MainText->setText(text);
}

Also I have some code, running in another thread, created like this:

std:thread* core_thread = new thread(&Init); //void Init()...

Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:

void test_callback(void* object_ptr)
{
    auto this_object = (gui_popup*)object_ptr;
    this_object->on_pushButton_clicked();
}

In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?

UPDATE: I've solved it this way:

void test_callback(void* object_ptr)
{
    QMetaObject qtmo;
    qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}

it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.

Upvotes: 2

Views: 2420

Answers (1)

Marti Nito
Marti Nito

Reputation: 814

I usually solve it like this:

class Foo : public QObject
{
   Q_OBJECT

     Foo()
     {
       // connect to own signal to own slot and hence "translate" it
       connect(this, SIGNAL(some_signal(QString)),
               this, SLOT(some_slot(QString)));
     }

   signals:
     void some_signal(QString s);

   protected slots:
     void some_slot(QString s)
     {
        // do something with your gui
     }
   public: 
     void callback_proxy(std::string s)
     {
        emit some_signal(QString::fromUtf8(m_string.c_str()));
     }
};

and then the tread does not need to know about QT:

void thread_run_function(Foo* foo)
{
    foo->callback_proxy("Hello from Thread!");
}

As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.

HtH Martin

Edits: Some more info on default parameter and this link as reference: See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum

Upvotes: 4

Related Questions