How to use methods of an object from a different class?



  • I have a serial object in my mainwindow.cpp in which I can succesfully write and send bytes to an arduino.

    I can open a new window with a keyboard:
    alt text

    This keyboard is ofcourse made in a different class. If I press a button like the 'a'. I want to serial.write("a"); But as you can guess it. I cannot call any serial method because the serial object only exists in the scope of the main window.

    I am happy with 1 of the following 2 solutions: I either want to be able to call serial methods in the keyboard class ór I want to call a function in the mainwindow class from out the keyboard class with which I send a character or string as to be written arguement.

    I do not know how do to any of this. So how can I fix this?



  • The code:
    Keyboard class

    #include "keyboard.h"
    #include "ui_keyboard.h"
    #include <QtSerialPort>
    #include "mainwindow.h"
    
    
    bool caps = true, shift = true;
    
    Keyboard::Keyboard(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Keyboard)
    
    {
        ui->setupUi(this);
    }
    
    Keyboard::~Keyboard()
    {
        delete ui;
    }
    
    void Keyboard::on_a_clicked()
    {
       //  mainwindow::send('a');  //  or
       //  serial.write("a");
    }
    

    MainWindow:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QPixmap>
    #include <QDebug>
    #include <QPalette>
    #include <QtSerialPort>
    #include "keyboard.h"
    QSerialPort *serial;
    void readCommand();
    
    char lettres[5][40][16];     // initializes all to be used variables;
    int index1 = 0;
    int index2 = 0;
    int colom[5];
    int row[5];
    int colorIndex[5];
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        serial = new QSerialPort();
        serial->setPortName("COM4");
        serial->open(QIODevice::ReadWrite);
        serial->setBaudRate(QSerialPort::Baud115200);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::OddParity);
        serial->setStopBits(QSerialPort::OneStop);
        //serial.setFlowControl(QSerialPort::NoFlowControl);
        //serial.open(QIODevice::ReadWrite);
    
        QPixmap logo(":/resources/img/logo.jpg");
        int w = ui->label->width();
        int h = ui->label->height();
        ui->label->setPixmap(logo.scaled(w,h,Qt::KeepAspectRatio));
    
        for(int i=0;i<5;i++) {
            for (int j=0;j<40;j++) {
                for (int k=0;k<16;k++){
                    lettres[i][j][k] =' ';   // initializes the letters array
                }
            }
        }
       connect(serial, &QSerialPort::readyRead, this, &MainWindow::serialReceived);
    }
    
    MainWindow::~MainWindow()
    {
       delete ui;
    }
    
    
    void MainWindow::serialReceived()
    {
        QByteArray b = serial->readAll();
        qDebug() << b;
    }
    
    void MainWindow::send(char c)    // send function which I'd like to call from Keyboard
    {
      serial->write("c");
      qDebug() << c;
    }
    


  • The two classes are unnecessarily tightly coupled, as far as I can see the keyboard class doesn't have to know the main window. Just write a signal in it, emit it in on_button_clicked() and connect it in the mainwindow to the slot mainwindow::send (which of course must be a slot).



  • @Eeli-K said in How to use methods of an object from a different class?:

    Just write a signal in it, emit it in on_button_clicked() and connect it in the mainwindow to the slot mainwindow::send

    ?? and now in English??

    I have this in mainwindow

    void MainWindow::send(char c)
    {
      connect(keyboard, &Keyboard::on_a_clicked(), this &MainWindow::send(c));
      serial->write("c"); // I am aware that this does not send the value of variable c just "c"
      qDebug() << c;
    }
    

    and in Keyboard I do

    void Keyboard::on_a_clicked()
    {
       QString c;
       c = ui->a->text();
       MainWindow::send('a');
    }
    

    in main window I get 2 errors

    C:\Users\sknippels\Documents\GUI\mainwindow.cpp:65: error: cannot call member function 'void Keyboard::on_a_clicked()' without object
       connect(keyboard, &Keyboard::on_a_clicked(), this &MainWindow::send(c));
                                                 ^
    

    and

    C:\Users\sknippels\Documents\GUI\mainwindow.cpp:65: error: invalid operands of types 'MainWindow*' and 'void' to binary 'operator&'
       connect(keyboard, &Keyboard::on_a_clicked(), this &MainWindow::send(c));
                                                                            ^
    

    I understand less than nothing of this vague syntax. And I also never use pointers, I would only use a pointer for use with arrays but because there are those things called for-loops... I just don't do pointers.

    EDIT. I made some changes, I also noticed a typo. I move this line to the constructor (and removed the typo)

    connect(keyboard, &Keyboard::on_a_clicked, this, &MainWindow::send);
    

    and now I have 3 error messages in qobjectdefs_impl.h

    C:\Qt\5.8\mingw53_32\include\QtCore\qglobal.h:732: error: static assertion failed: The slot requires more arguments than the signal provides.
     #define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
                                                   ^
    
    C:\Qt\5.8\mingw53_32\include\QtCore\qglobal.h:732: error: static assertion failed: Signal and slot arguments are not compatible.
     #define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
                                                   ^
    
    C:\Qt\5.8\mingw53_32\include\QtCore\qobjectdefs_impl.h:76: error: no type named 'Car' in 'struct QtPrivate::List<>'
             typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value;
                                                                                                                          ^
    

    For me this is total Chinese :(



  • @bask185
    hi,

    I'll try to help:

    Your custom Keyboard, as it is made in a new class, has to be initialized somewhere.

    I asume something like this in your MainWindow constructor:

    //Something like this
    Keyboard kBoard;
    
    // or
    Keyboard *kBoard = new Keyboard();
    
    // or 
    Keyboard *kBoard = new Keyboard(anyParent);
    

    kBoard is in this case the object.

    in your KeyBorad header you need a SIGNAL

    signals:
    void keyPressed(QString key);
    

    change your on_click function:

    void Keyboard::on_a_clicked()
    {
       QString c;
       c = ui->a->text();
       emit KeyPressed(c);
    }
    

    Move

    connect(keyboard, &Keyboard::on_a_clicked(), this &MainWindow::send(c));
    

    from the SLOT send(c) to right behind the object creation and change it to the following to remove the error:

    Keyboard *kBoard = new Keyboard();
    connect(keyboard, &Keyboard::KeyPressed, this &MainWindow::send);
    

    and you should be done :)



  • @J.Hilk said in How to use methods of an object from a different class?:

    @bask185
    hi,

    I'll try to help:

    Your custom Keyboard, as it is made in a new class, has to be initialized somewhere.

    I asume something like this in your MainWindow constructor:

    //Something like this
    Keyboard kBoard;
    
    // or
    Keyboard *kBoard = new Keyboard();
    
    // or 
    Keyboard *kBoard = new Keyboard(anyParent);
    

    kBoard is in this case the object.

    in your KeyBorad header you need a SIGNAL

    signals:
    void keyPressed(QString key);
    

    change your on_click function:

    void Keyboard::on_a_clicked()
    {
       QString c;
       c = ui->a->text();
       emit KeyPressed(c);
    }
    

    Move

    connect(keyboard, &Keyboard::on_a_clicked(), this &MainWindow::send(c));
    

    from the SLOT send(c) to right behind the object creation and change it to the following to remove the error:

    Keyboard *kBoard = new Keyboard();
    connect(keyboard, &Keyboard::KeyPressed, this &MainWindow::send);
    

    and you should be done :)

    Tnx I am closer but I got one error message left.
    in

    Keyboard *keyboard = new Keyboard();
       connect(keyboard, &Keyboard::KeyPressed, this &MainWindow::send);
    

    I get

    C:\Users\sknippels\Documents\GUI\mainwindow.cpp:52: error: invalid use of member (did you forget the '&' ?)
        connect(keyboard, &Keyboard::KeyPressed, this &MainWindow::send);
                                                                   ^
    

    it complains about the & eventhough it is there.. :/



  • @bask185

    mmh,
    did you declare send as a slot in your mainwindow cpp?

    private slots:
    //public slots:
         void send(QString s);
    

    Edit:

    just noticed, your Send-Function wants a char and you send a QString that will most likly not work.

    change one or the other. I would suggest chaning the Mainwindow::Send to accept QString, makes it easier.


  • Moderators

    @bask185 said in How to use methods of an object from a different class?:

    Keyboard *keyboard = new Keyboard();
    connect(keyboard, &Keyboard::KeyPressed, this &MainWindow::send);

    Aren't you missing a comma?

    Keyboard *keyboard = new Keyboard();
       connect(keyboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    

  • Moderators

    @J.Hilk said in How to use methods of an object from a different class?:

    //Something like this
    Keyboard kBoard;

    Please do NOT do this in the constructor: kBoard would be a local variable and would disappear when the constructor finishes!



  • @jsulm @bask185
    Oh, sorry about that.
    ApparentlyI missed that when I wrote my answer.

    I tried to cover all bases, just in case, but that's an error my from my part.



  • @jsulm said in How to use methods of an object from a different class?:

    Aren't you missing a comma?

    That is what I thought as well, but no. Adding comma will give errors

    @jsulm said in How to use methods of an object from a different class?:

    Please do NOT do this in the constructor: kBoard would be a local variable and would disappear when the constructor finishes!

    at first I used Keyboard *keyboard = new Keyboard(); with those strange pointer things. Now I declare keyboard with the rest of my variables and I initialize it in the constructor.

    @J.Hilk said in How to use methods of an object from a different class?:

    ust noticed, your Send-Function wants a char and you send a QString that will most likly not work

    I also noticed that and changed it already.

    There are a few more things I found out. I was using 'keyboard' at first, but that turns red so it might interfere. I swapped out 'keyboard' for Kboard. But my way of decalaring it in the variable section and initializing it in the constructor suddenly upset the compiler so I went back to the constructor and now I have:

    Keyboard *Kboard = new Keyboard();
       connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
    

    also in keyboard.h I changed private by public because I was getting an error message there at first.

    But I am still having this error in the connect function:

    C:\Users\sknippels\Documents\GUI\mainwindow.cpp:51: error: invalid use of member (did you forget the '&' ?)
        connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
                                                                 ^
    

    how my code looks like atm:

    Keyboard *Kboard = new Keyboard();  // mainwindow.cpp constructor
       connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
    
    void MainWindow::send(QString c)  // send function in mainwindow.ccp
    {
      serial->write("c"); // still does not send the value of c, just "c"
      qDebug() << c;
    }
    
    void Keyboard::on_a_clicked() // push button function in keyboard.cpp
    {
       QString c;
       c = ui->a->text();
       emit KeyPressed(c);
       }
    
    public slots: // keyboard.h
        void KeyPressed(QString c); // also tried KeyPressed(QString); and KeyPressed(); no effect
    }
    
    private slots: //mainwindow.h
        void serialReceived(); // one of many other functions
        void send(QString c);
    
    

    I think we have all the pieces of this strange C++ puzzle now


  • Moderators

    @bask185 You're still missing the comma, please add it as it is needed. And if you then still get an error then please post it here: just saying there is an error does not help.



  • @bask185

    additionally to what @jsulm said,

    
    public slots: // keyboard.h
        void KeyPressed(QString c); // also tried KeyPressed(QString); and KeyPressed(); no effect
    
    

    ought to be a signal

    signals: // keyboard.h
        void KeyPressed(QString c); // also tried KeyPressed(QString); and KeyPressed(); no effect
    
    

    not a slot



  • @jsulm said in How to use methods of an object from a different class?:

    @bask185 You're still missing the comma, please add it as it is needed. And if you then still get an error then please post it here: just saying there is an error does not help.

    Keyboard *Kboard = new Keyboard();
       //connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
       connect(Kboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    

    V

    C:\Users\sknippels\Documents\GUI\mainwindow.cpp:52: error: undefined reference to `Keyboard::KeyPressed(QString)'
    
    C:\Users\sknippels\Documents\GUI\keyboard.cpp:76: error: undefined reference to `Keyboard::KeyPressed(QString)'
    
    C:\Users\sknippels\Documents\build-GUI-Desktop_Qt_5_8_0_MinGW_32bit-Debug\debug\moc_keyboard.cpp:251: error: undefined reference to `Keyboard::KeyPressed(QString)'
    
    collect2.exe:-1: error: error: ld returned 1 exit status
    

  • Moderators

    @bask185 Please read what @J-Hilk wrote



  • @jsulm said in How to use methods of an object from a different class?:

    @bask185 Please read what @J-Hilk wrote

    I did and changed it and I can finally atleast build it. only pressing the 'a' on the keyboard does not do anything.

    I know that void Keyboard::on_a_clicked() gets executed using Qdebug I can also tell c has the correct value.

    But in mainwindow void MainWindow::send(QString c) does not get executed. I added qDebug() << "hello world"; but nothing happens :(


  • Moderators

    @bask185 Can you show the whole code where

    Keyboard *Kboard = new Keyboard();
       //connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
       connect(Kboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    

    is embedded?



  • @jsulm said in How to use methods of an object from a different class?:

    @bask185 Can you show the whole code where

    Keyboard *Kboard = new Keyboard();
       //connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
       connect(Kboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    

    is embedded?
    I don't know what you mean??

    I moved Keyboard *Kboard; to the global variables of mainwindow but it seems that does not make a difference. Button 'a' of the keyboard still does not trigger the send function in the main window


  • Moderators

    @bask185 Can you please post your code? Else I don't know what is wrong.



  • @bask185

    what @jsulm meant, is, can you post the whole content between the brackets {} where

    Keyboard *Kboard = new Keyboard();
       //connect(Kboard, &Keyboard::KeyPressed, this &MainWindow::send);
       connect(Kboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    

    is copied out of.



  • The one with the comma remains ;)

    #include "mainwindow.h" // mainwindow.cpp
    #include "ui_mainwindow.h"
    #include <QPixmap>
    #include <QDebug>
    #include <QPalette>
    #include <QtSerialPort>
    #include "keyboard.h"
    #include "numpad.h"
    QSerialPort *serial;
    void readCommand();
    
    char lettres[5][40][16];     // initializes all to be used variables;
    int index1 = 0;
    int index2 = 0;
    int colom[5];
    int row[5];
    int colorIndex[5];
    char c;
    Keyboard *Kboard;
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        serial = new QSerialPort();
        serial->setPortName("COM4");
        serial->open(QIODevice::ReadWrite);
        serial->setBaudRate(QSerialPort::Baud115200);
        serial->setDataBits(QSerialPort::Data8);
        serial->setParity(QSerialPort::OddParity);
        serial->setStopBits(QSerialPort::OneStop);
        //serial.setFlowControl(QSerialPort::NoFlowControl);
        //serial.open(QIODevice::ReadWrite);
    
        QPixmap logo(":/resources/img/logo.jpg");
        int w = ui->label->width();
        int h = ui->label->height();
        ui->label->setPixmap(logo.scaled(w,h,Qt::KeepAspectRatio));
    
        for(int i=0;i<5;i++) {
            for (int j=0;j<40;j++) {
                for (int k=0;k<16;k++){
                    lettres[i][j][k] =' ';   // initializes the letters array
                }
            }
        }
       connect(serial, &QSerialPort::readyRead, this, &MainWindow::serialReceived);
    
       Kboard = new Keyboard();
       connect(Kboard, &Keyboard::KeyPressed, this, &MainWindow::send);
    }
    
    MainWindow::~MainWindow()
    {
       delete ui;
    }
    
    void MainWindow::serialReceived()
    {
        QByteArray b = serial->readAll();
        qDebug() << b;
    }
    
    void MainWindow::send(QString c)
    {
      serial->write("c");
      qDebug() << "hello world " << c;
    }
    
    #include "keyboard.h" //keyboard.cpp
    #include "ui_keyboard.h"
    #include <QtSerialPort>
    #include "mainwindow.h"
    
    
    bool caps = true, shift = true;
    
    Keyboard::Keyboard(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Keyboard)
    
    {
        ui->setupUi(this);
    }
    
    Keyboard::~Keyboard()
    {
        delete ui;
    }
    
    void Keyboard::on_a_clicked()
    {
       QString c;
       c = ui->a->text();
       emit KeyPressed(c);
       qDebug() << c;
    
       if(caps == true && shift == false){ // disables the effect of the shift key when any lettre has been pressed.
           shift = false;
           on_shift1_clicked();
       }
    }
    
    #ifndef MAINWINDOW_H //main window.h
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "keyboard.h"
    #include "numpad.h"
    
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        void send(QString c);
    
    private:
        Ui::MainWindow *ui;
        Keyboard *keyboard;
        Numpad *numpad;
    };
    
    #endif // MAINWINDOW_H
    
    #ifndef KEYBOARD_H
    #define KEYBOARD_H
    
    #include <QDialog>
    
    namespace Ui {  //keyboard.h
    class Keyboard;
    }
    
    class Keyboard : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Keyboard(QWidget *parent = 0);
        ~Keyboard();
    signals:
        void KeyPressed(QString);
    
    private slots:
        void on_a_clicked();
        
    
    private:
        Ui::Keyboard *ui;
    };
    
    #endif // KEYBOARD_H
    

  • Moderators

    @bask185 One note: why do you use global variables? This is bad habit!
    For example Kboard should be a member variable of your MainWindow class.



  • idk to get it to work I suppose, but I should declare it in the constructor above the connect function??

    In processing I sometimes use global variables because I can acces and modify them in every class I write. In Qt I know very little of what the firetruck I am doing. I do know that in Qt it is a lot more work to get an exact same application than in processing..



  • @bask185 said in How to use methods of an object from a different class?:

    Keyboard *keyboard;

    I think I found the mixup,

    You have Keyboard as a priavte member of your mainwindow.h, as it should be, and as a global Variable too.

    I think the instance of your keyboard, that you show and have input of, is not the one you connected your Signal from.

    Change that.


  • Moderators

    @bask185 said in How to use methods of an object from a different class?:

    void MainWindow::send(QString c)
    {
    serial->write("c");
    qDebug() << "hello world " << c;
    }

    Can you try to comment out serial->write("c"); and try again?
    Also: I guess you want to send the string/character entered by user over serial bus, right?
    In that case you should change

    serial->write("c");
    

    to

    serial->write(c.toLatin1()); // If you only use ASCII characters
    


  • @bask185 I didn't know you know so little about C++ and Qt. It's true that C++ is in many ways a low-level language. Qt takes it a bit higher, but certainly it's still means more work for certain things than many other languages. But on the other hand C++ is on the most popular and used general purpose languages in the world, and unlike with processing, you can call yourself a real programmer if you master C++ and Qt. Every language has its place and has pros and cons. If you want to just get one program done in your life C++ isn't the right language for you, otherwise it pays back what you put into learning it.



  • @J.Hilk said in How to use methods of an object from a different class?:

    @bask185 said in How to use methods of an object from a different class?:

    Keyboard *keyboard;

    I think I found the mixup,

    You have Keyboard as a priavte member of your mainwindow.h, as it should be, and as a global Variable too.

    I think the instance of your keyboard, that you show and have input of, is not the one you connected your Signal from.

    Change that.

    Application Output:  hello world   "a"   // we have a winner!
                         hello world  "A" // < caps works too :D
    

    My thank is great Y'all

    @jsulm said in How to use methods of an object from a different class?:

    I guess you want to send the string/character entered by user over serial bus, right?

    was it that obvious :P?

    In that case you should change
    serial->write("c");

    to
    serial->write(c.toLatin1()); // If you only use ASCII characters

    Application Output:  "\x06\x04\x01""a"  // < proper respons of the arduino for receiving the 'a'. Tnx ;)
    

    sigh though... in processing or arduino or whatever I usually send.. just integers or longs. Vague Qt syntax with & * :: private public and what if I want to send a long variable over serial port would I need to characterize all 10 numbers and send 10 bytes instead of 4????

    @Eeli-K said in How to use methods of an object from a different class?:

    @bask185 I didn't know you know so little about C++ and Qt. It's true that C++ is in many ways a low-level language. Qt takes it a bit higher, but certainly it's still means more work for certain things than many other languages. But on the other hand C++ is on the most popular and used general purpose languages in the world, and unlike with processing, you can call yourself a real programmer if you master C++ and Qt. Every language has its place and has pros and cons. If you want to just get one program done in your life C++ isn't the right language for you, otherwise it pays back what you put into learning it.

    we had a few lessons in C++ in my first year in visual studios but even there we would not use :: privates and publics, (the latter 2 we got with java). And as said before I only learned how to use pointers with arrays and not with functions.

    But regardless, I almost have my bachelor degree in electrical engineering and learning a new programming language from scrap is what we do.


  • Moderators

    @bask185 said in How to use methods of an object from a different class?:

    we had a few lessons in C++ in my first year in visual studios but even there we would not use :: privates and publics

    Then those were not really C++ lessons. public/private (data encapsulation) belong to core concepts in C++ (and any other object oriented programming language).

    "what if I want to send a long variable over serial port would I need to characterize all 10 numbers and send 10 bytes instead of 4" - no.
    From the user you will get a string like "12345".
    Then convert it to int:

    long int number = c.toLong();
    

    And then send the number to Arduino.



  • @bask185 said in How to use methods of an object from a different class?:

    sigh though... in processing or arduino or whatever I usually send.. just integers or longs. Vague Qt syntax with & * :: private public and what if I want to send a long variable over serial port would I need to characterize all 10 numbers and send 10 bytes instead of 4????

    QSerialPort::writeData has a max length of qint64 , long long int and __int64 respectively so you should be fine sending 'long' variables.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.