c++qtqthreadqtconcurrentqfuture

How I can close dialog, from another thread? Qt


I want to handle my button in this way:

  1. Change text on label (somethink like "Please wait...")
  2. Download some data from database
  3. When downloading is done, close dialog where is this button.

When I do this:

void LoadingDialog::on_pushButton_clicked()
{
m_ui->labelStatus->setText("Pobieranie wysyłek...");

if(m_methodToDo == MethodToDo::LoadShipment)
{
    if(DataManager::getManager()->loadShipments())
    {
        this->close();
    }
}
}

the label hasn't changed text, is few second of lag (is downloading few k records) and dialog is closing.

When I try this:

void LoadingDialog::changeStatus(QString status)
{
m_ui->labelStatus->setText(status);
}

bool LoadingDialog::load()
{
if(m_methodToDo == MethodToDo::LoadShipment)
{
    if(DataManager::getManager()->loadShipments())
    {
        this->close();
    }
}
}

void LoadingDialog::on_pushButton_clicked()
{
QFuture<void> future3 = QtConcurrent::run([=]() {
    changeStatus("Pobieranie wysyłek..."); // "Downloading.."
});

QFuture<void> future = QtConcurrent::run([=]() {
    load();
});
}

the label has change text - it's ok is few second of lag - it's ok but dialog isn't closed, and my application throws exception :

Cannot send events to objects owned by a different thread. Current thread 229b1178. Receiver 'Dialog' (of type 'LoadingDialog') was created in thread 18b00590

Any suggestion?


Solution

  • First, changeStatus is not blocking, so do not run it on another thread. On the other hand if you want to invoking a slot from another thread you can use QMetaObject::invokeMethod():

    bool LoadingDialog::load()
    {
        if(m_methodToDo == MethodToDo::LoadShipment)
            if(DataManager::getManager()->loadShipments())
                QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
    }
    
    void LoadingDialog::on_pushButton_clicked()
    {
        changeStatus("Pobieranie wysyłek..."); // "Downloading.."
    
        QFuture<void> future = QtConcurrent::run([=]() {
            load();
        });
    }