Home > Enterprise >  How to get data from a non-member function into a member function in Qt?
How to get data from a non-member function into a member function in Qt?

Time:09-17

I have a Qt project (in Win10) that requires a non-member function in my MainWindow cpp file. It's a callback function that is triggered automatically from an external library when data from an attached sensor arrives. I like to display this data on a MainWindow widget (a plainTextEdit), but of course I cannot access any MainWindow elements from my callback function, and also no signal-slot concept works so far. Below is a minimal example of the problem:

MainWindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMutex>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void displayData();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

MainWindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"

// define global variables
QMutex mutex;
bool new_data_arrived = false;
QString newDataStr;

void newData() {
// This is a callback function triggered when data from a sensor attached via USB arrives
// I want to pass the result as a QString to MainWindow::displayData() to display it on screen 
    mutex.lock();
    new_data_arrived = true;
    newDataStr = "new data";
    mutex.unlock();
};

void MainWindow::displayData()
{
    mutex.lock();
    if (new_data_arrived == true) {
        new_data_arrived = false;
        ui->plainTextEdit->appendPlainText(newDatastr);
    }  
    mutex.unlock();
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

The function MainWindow::displayData() is then running in a loop (but that’s unimportant for my problem, so I removed it from the minimal example above…).

As mentioned, newData() cannot access any elements of MainWindow, which is clear. The only workaround I found so far is to use global variables as shown above, to get data from the non-member function newData() into the member function displayData(). I also included a mutex to avoid possible share violation (no idea if that's necessary, but it doesn't harm...).

Is there a more elegant way? In principle, what I need is either a signal-slot concept, but newData() cannot emit signals of MainWindow, or to get this into the function newData(), so that ui elements can be accessed.

CodePudding user response:

You should use QMetaObject::invokeMethod to call a slot of a QObject from a non QObject slot (your callback funtion).

Here is an example:

class MainWindow : public QMainWindow
{
    Q_OBJECT
    //...
    
public slots:
    void displayData( QString szNewData );
};


//Cpp MainWindow.cpp file
static MainWindow * mainWindowObj = nullptr;

void setMainWindowObj( MainWindow * ptr ){
    mainWindowObj = ptr;
}

void newData() {
    // This is a callback function triggered when data from a sensor attached via USB arrives
    // I want to pass the result as a QString to MainWindow::displayData() to display it on screen 

    if( mainWindowObj == nullptr )
        return;
        
    QMetaObject::invokeMethod( mainWindowObj, //pointer to MainWindow instance (see main.cpp)
                               "displayData", //slot name
                               Qt::QueuedConnection, //connection type
                               Q_ARG( QString, newDataStr ) ); //Param passed to the slot
};

void MainWindow::displayData( QString szNewData )
{
    ui->plainTextEdit->appendPlainText( szNewData );
}


//main.cpp file or where MainWindow instance is initialized

void setMainWindowObj( MainWindow * ptr );

int main( int argc, char *argv[] ){

    //....
    QApplication app(argc, argv);
    
    //....
    MainWindow mainWindow;
    setMainWindowObj ( &mainWindow );
    
    //....
}
  • Related