c++qtqt5qt-connection

I cannot use the pointer from QMainWindow as argument in connect for QT5


This code creates a thread and connect it to MainWindow in QT.

void UI_handling::create_thread_for_looping_terminal(){
    loop_terminal_thread = new Loop_terminal_thread(mainWindow, &j1939);
    loop_terminal_thread->start();
    mainWindow->connect(loop_terminal_thread, &Loop_terminal_thread::send_ID_and_data_to_looping_terminal, mainWindow, &MainWindow::update_looping_teriminal);
}

This code gives error on ->connect part due to mainWindow argument.

If I would run this code inside the MainWindow class, it would look like this. It will work fine, but as you can see, mainWindow is the issue here.

connect(loop_terminal_thread, &Loop_terminal_thread::send_ID_and_data_to_looping_terminal, this, &MainWindow::update_looping_teriminal);

So why is mainWindow the issue if I have a constructor that look like this

UI_handling::UI_handling(QMainWindow* mainWindow, Ui::MainWindow* ui) : mainWindow(mainWindow), ui(ui){

}

And I call the UI_handling constructor inside the MainWindow class

#include "mainwindow.h"

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

    /* Important handler */
    ui_handling = new UI_handling(this, ui);

So why does the argument this, causing so I don't get right argument?

The error is:

ui_handling.cpp:119:17: error: no matching member function for call to 'connect'
qobject.h:242:43: note: candidate function [with Func1 = void (Loop_terminal_thread::*)(unsigned int, unsigned char *), Func2 = void (MainWindow::*)(unsigned int, unsigned char *)] not viable: cannot convert from base class pointer 'QMainWindow *' to derived class pointer 'const typename QtPrivate::FunctionPointer<void (MainWindow::*)(unsigned int, unsigned char *)>::Object *' (aka 'const MainWindow *') for 3rd argument
qobject.h:222:36: note: candidate function not viable: no known conversion from 'void (Loop_terminal_thread::*)(uint32_t, uint8_t *)' to 'const char *' for 2nd argument
qobject.h:225:36: note: candidate function not viable: no known conversion from 'void (Loop_terminal_thread::*)(uint32_t, uint8_t *)' to 'const QMetaMethod' for 2nd argument
qobject.h:481:41: note: candidate function not viable: no known conversion from 'void (Loop_terminal_thread::*)(uint32_t, uint8_t *)' to 'const char *' for 2nd argument
qobject.h:283:13: note: candidate template ignored: requirement '!QtPrivate::FunctionPointer<void (MainWindow::*)(unsigned int, unsigned char *)>::IsPointerToMemberFunction' was not satisfied [with Func1 = void (Loop_terminal_thread::*)(unsigned int, unsigned char *), Func2 = void (MainWindow::*)(unsigned int, unsigned char *)]
qobject.h:322:13: note: candidate template ignored: requirement 'QtPrivate::FunctionPointer<void (MainWindow::*)(unsigned int, unsigned char *)>::ArgumentCount == -1' was not satisfied [with Func1 = void (Loop_terminal_thread::*)(unsigned int, unsigned char *), Func2 = void (MainWindow::*)(unsigned int, unsigned char *)]
qobject.h:274:13: note: candidate function template not viable: requires 3 arguments, but 4 were provided
qobject.h:314:13: note: candidate function template not viable: requires 3 arguments, but 4 were provided

Minimal example:

First you create the thread header

#ifndef LOOP_TERMINAL_THREAD_H

#define LOOP_TERMINAL_THREAD_H

#include <QThread>
#include <QObject>

class Loop_terminal_thread : public QThread {
    Q_OBJECT
public:
    Loop_terminal_thread(QObject *parent = nullptr);
signals:
    void send_ID_and_data_to_looping_terminal(uint32_t ID, uint8_t data[]);
private:
    bool* start_loop_terminal_thread;
    void run();
};

#endif // LOOP_TERMINAL_THREAD_H

Then you create the thread source

#include "loop_terminal_thread.h"

Loop_terminal_thread::Loop_terminal_thread(QObject *parent) : QThread(parent)  {

}

void Loop_terminal_thread::run(){
    uint8_t data[8] = {0};
    data[1] = 23;
    while(1){
            emit send_ID_and_data_to_looping_terminal(300, data);
        msleep(1000);
    }
}

Then you create the UI_handler class

/* QT includes */
#include "ui_mainwindow.h"
#include <QStandardItemModel>
#include <QIntValidator>
#include <QMainWindow>

/* Project includes */
#include "UI_threads/Loop_terminal_thread/loop_terminal_thread.h"

class UI_handling{
public:
    UI_handling(QMainWindow* mainWindow, Ui::MainWindow* ui);
    void create_thread_for_looping_terminal();

private:
    QMainWindow* mainWindow;
    Ui::MainWindow* ui;

    /* Thread for the looping terminal */
    Loop_terminal_thread* loop_terminal_thread;

};

#endif // UI_HANDLING_H

And you implement the counstructor and the function inside the source file.

UI_handling::UI_handling(QMainWindow* mainWindow, Ui::MainWindow* ui) : mainWindow(mainWindow), ui(ui){

}

void UI_handling::create_thread_for_looping_terminal(){
    loop_terminal_thread = new Loop_terminal_thread(mainWindow, &j1939);
    loop_terminal_thread->start();
    mainWindow->connect(loop_terminal_thread, &Loop_terminal_thread::send_ID_and_data_to_looping_terminal, mainWindow, &MainWindow::update_looping_teriminal);
}

Then lastly you implement this inside your MainWindow constructor

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

    /* Important handler */
    ui_handling = new UI_handling(this, ui);
    ui_handling->create_thread_for_looping_terminal();
}

void MainWindow::update_looping_teriminal(uint32_t ID, uint8_t data[]){

}

The header file of MainWindow class look like this

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

public slots:
    void update_looping_teriminal(uint32_t ID, uint8_t data[]);

Solution

  • The clue is in this part of the error message:

    cannot convert from base class pointer 'QMainWindow *'
    to derived class pointer ... (aka 'const MainWindow *') for 3rd argument
    

    You are connecting to a slot in MainWindow class, therefore you need to provide a pointer to MainWindow. A pointer to QMainWindow is not enough.

    When you run your connect inside MainWindow and pass this, then the type of this argument is MainWindow and it works.

    In order for your code to work you need to change UI_handling class, so that it stores a pointer to MainWindow instead of QMainWindow.