1

I am trying to connect my Qt application to a database. Since I have a GUI, of course the only way to do this is in a separate thread. I found out that I can do it via QtConcurrent::run. Here is my code:

MainWindow::MainWindow(QWidget *parent) {
  // ...
  QFuture<bool> worker = QtConcurrent::run(this, &MainWindow::connectDatabase);
  QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>;
  connect(watcher, &QFutureWatcher<bool>::finished, this, &MainWindow::databaseConnected);
  watcher->setFuture(worker);
}

bool MainWindow::connectDatabase() {
  QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
  db.setHostName("127.0.0.1");
  db.setUserName("user");
  db.setPassword("pass");
  db.setDatabaseName("mydb");

  return db.open();
}

It works but I am not able (obviously) to get any data out of the process. For example, I would like to know if the connection succeeded and it would be ideal if I could get it through the slot.

I could add the watcher as a member of the class and query it from the slot but this approach would be tedious for many async task I believe.

What should I do?

RAM
  • 2,257
  • 2
  • 19
  • 41
Victor
  • 13,914
  • 19
  • 78
  • 147
  • Can't you emit from `MainWindow::connectDatabase()` – drescherjm Apr 17 '17 at 18:43
  • @drescherjm, the slots affect the UI, one changes the status bar text and the other displays an error message box. According to [this](http://stackoverflow.com/questions/25733142/qwidgetrepaint-recursive-repaint-detected-when-updating-progress-bar), UI changes can only be made from the main thread which will lead to more tedious calls – Victor Apr 17 '17 at 19:50
  • @Victor, He means that you just can emit a signal about the connection at the end of the `connectDatabase()` method but not to affect the UI in the method. – Vladimir Bershov Apr 17 '17 at 19:55
  • @VladimirBershov yeah, I got that, but won't the signal method be executed on the same separate thread, meaning that I can't change the UI there either? – Victor Apr 17 '17 at 20:11
  • 1
    I've edited my answer, you can just use `Qt::QueuedConnection` – Vladimir Bershov Apr 17 '17 at 20:12
  • `Qt::QueuedConnection` is the key to cross thread signals and slots. Although Qt will select the safe connection mode if you did not specify it anyways. – drescherjm Apr 17 '17 at 20:14

1 Answers1

3

You have to make worker a class member (because the local variable will be deleted on exit from the constructor):

MainWindow::MainWindow(QWidget *parent) {
  // ...
  m_worker = QtConcurrent::run(this, &MainWindow::connectDatabase);
  QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>;
  connect(watcher, &QFutureWatcher<bool>::finished, this, &MainWindow::databaseConnected);
  watcher->setFuture(m_worker);
}

Way 2:

MainWindow::MainWindow(QWidget *parent) { 
    connect(this, &MainWindow::mySignalAboutDBOpen, 
        this, &MainWindow::databaseConnected, Qt::QueuedConnection); 

        QtConcurrent::run(this, &MainWindow::connectDatabase);
    }

//and in the connectDatabase:
bool MainWindow::connectDatabase() {
    //...
    bool ret = db.open();
    emit mySignalAboutDBOpen(ret);
    return ret;
}

Please note that the QSqlDatabase db variable also is local and will be deleted on exit of connectDatabase().

See Qt::ConnectionType

Vladimir Bershov
  • 2,701
  • 2
  • 21
  • 51