Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Signal and slot from other class not working



  • I have two classes in my second ui. I'm trying to connect signal and slot emitted in another class on QLabel click event (I promoted this Label) so I can update QLabel->setText("Some texts") from other class. However it does not work, I have been trying to make it sometimes it will run, but the QLabel->setText("Some texts"); won't update on the ui. Here is my code:

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include "secondform.h"
    #include <QMainWindow>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        SecondForm *captureWig;
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    
    void MainWindow::on_pushButton_clicked()
    {
    
        captureWig = new SecondForm(this);
        QVBoxLayout *sendWig = new QVBoxLayout;
        sendWig = captureWig->getTreeto();
    
        QWidget *w = new QWidget();
        w->setLayout(sendWig);
    
        ui->tabWidget->addTab(w, "Newtab");
    }
    

    secondform.h

    
    #ifndef SECONDFORM_H
    #define SECONDFORM_H
    
    #include <QObject>
    #include <QWidget>
    #include <QtWidgets>
    
    class ClickableLabels;
    
    namespace Ui {
    class SecondForm;
    }
    
    class SecondForm : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit SecondForm(QWidget *parent = nullptr);
        ~SecondForm();
        QVBoxLayout *getTreeto();
    
    signals:
    void send_fromMain();
    
    private slots:
        void on_Clickme_clicked();
        void ReceivedFromSecondForm();
    
    private:
        ClickableLabels *upLabText;
        QPushButton *button_first;
        Ui::SecondForm *ui;
    };
    
    
    class ClickableLabels : public QLabel {
    
        Q_OBJECT
    
    public:
        explicit ClickableLabels(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
        ~ClickableLabels();
    
    signals:
        void clicked();
        void SentFromSecondForm();
    
    protected:
        void mousePressEvent(QMouseEvent* event);
    
    private:
    
    };
    
    #endif // SECONDFORM_H
    

    secondform.cpp

    
    #include "secondform.h"
    #include "ui_secondform.h"
    
    SecondForm::SecondForm(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::SecondForm)
    {
        ui->setupUi(this);
    
        upLabText = new ClickableLabels(this);
    
        QObject::connect (upLabText, SIGNAL (SentFromSecondForm()), this, SLOT(ReceivedFromSecondForm()));
    }
    
    void SecondForm::ReceivedFromSecondForm()
    {
        ui->label_4->setText("Received");
        qDebug () << "Emitted: ";
    }
    
    QVBoxLayout *SecondForm::getTreeto(){
    
        return ui->verticalLayout_6;
    }
    
    ClickableLabels::ClickableLabels(QWidget* parent, Qt::WindowFlags f)
        : QLabel(parent) {
    
    }
    
    ClickableLabels::~ClickableLabels() {}
    
    void ClickableLabels::mousePressEvent(QMouseEvent* ) {
    
        emit SentFromSecondForm();
        emit clicked();
        qDebug() << "QLabel clicked clicked";
    
    }
    
    SecondForm::~SecondForm()
    {
        delete ui;
    }
    
    void SecondForm::on_Clickme_clicked()
    {
        ui->label_4->setText("label clicked");
    }
    

    mainwindow.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>657</width>
        <height>663</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QVBoxLayout" name="verticalLayout">
        <item>
         <widget class="QTabWidget" name="tabWidget"/>
        </item>
        <item>
         <widget class="QPushButton" name="pushButton">
          <property name="text">
           <string>add</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>657</width>
         <height>21</height>
        </rect>
       </property>
      </widget>
      <widget class="QToolBar" name="mainToolBar">
       <attribute name="toolBarArea">
        <enum>TopToolBarArea</enum>
       </attribute>
       <attribute name="toolBarBreak">
        <bool>false</bool>
       </attribute>
      </widget>
      <widget class="QStatusBar" name="statusBar"/>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    
    

    secondform.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>SecondForm</class>
     <widget class="QWidget" name="SecondForm">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>765</width>
        <height>508</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Form</string>
      </property>
      <widget class="QWidget" name="verticalLayoutWidget_2">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>30</y>
         <width>279</width>
         <height>137</height>
        </rect>
       </property>
       <layout class="QVBoxLayout" name="verticalLayout_6">
        <item>
         <widget class="QGroupBox" name="groupBox">
          <property name="title">
           <string>GroupBox</string>
          </property>
          <layout class="QVBoxLayout" name="verticalLayout_2">
           <item>
            <widget class="QGroupBox" name="groupBox_2">
             <property name="title">
              <string>GroupBox</string>
             </property>
             <layout class="QHBoxLayout" name="horizontalLayout">
              <item>
               <widget class="QPushButton" name="Clickme">
                <property name="text">
                 <string>ckl</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QPushButton" name="pushButton">
                <property name="text">
                 <string>PushButton</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QPushButton" name="pushButton_4">
                <property name="text">
                 <string>PushButton</string>
                </property>
               </widget>
              </item>
             </layout>
            </widget>
           </item>
           <item>
            <layout class="QHBoxLayout" name="horizontalLayoutfv"/>
           </item>
           <item>
            <widget class="QLabel" name="label_4">
             <property name="text">
              <string>change here</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="ClickableLabels" name="label_5">
             <property name="text">
              <string>click here</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
     <customwidgets>
      <customwidget>
       <class>ClickableLabels</class>
       <extends>QLabel</extends>
       <header location="global">secondform.h</header>
      </customwidget>
     </customwidgets>
     <resources/>
     <connections/>
    </ui>
    
    

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
    
        QApplication a(argc, argv);
    
    //    ClickableLabels sender;
    //    SecondForm receiver;
    
    //    QObject::connect(&sender, SIGNAL(SentFromSecondForm()), &receiver, SLOT(ReceivedFromSecondForm()));
    
    
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    
    

    Thanks



  • @Ucn_

    Hello!

    I have created a simple example to illustrate a clickable label, button and connect using lambdas, so you can simplify your code.

    clickablelabel.h

    #ifndef CLICKABLELABEL_H
    #define CLICKABLELABEL_H
    
    #include <QWidget>
    #include <QLabel>
    #include <QEvent>
    
    class ClickableLabel : public QLabel
    {
        Q_OBJECT
    public:
        using QLabel::QLabel;
    
    signals:
        void clicked();
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
    };
    
    #endif // CLICKABLELABEL_H
    

    clickablelabel.cpp

    #include "clickablelabel.h"
    
    void ClickableLabel::mousePressEvent(QMouseEvent *event)
    {
        emit clicked();
        QLabel::mousePressEvent(event);
    }
    

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    #include <QDialog>
    #include <QVBoxLayout>
    #include "clickablelabel.h"
    
    namespace Ui {
    class Test;
    }
    
    class Test : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Test(QWidget *parent = nullptr);
        ~Test();
    
    private:
        Ui::Test *ui;
    };
    
    #endif // TEST_H
    

    test.cpp

    #include "test.h"
    #include "ui_test.h"
    
    Test::Test(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Test)
    {
        ui->setupUi(this);
        setFixedSize(600, 500);
        setWindowFlags(Qt::Dialog | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
        ClickableLabel *testLabel = new ClickableLabel("This is a test label...", this);
        connect(testLabel, &ClickableLabel::clicked, [testLabel]() {
           testLabel->setText("Some text from mouse click");
        });
        ui->pushButton->setText("Test button");
        connect(ui->pushButton, &QPushButton::clicked, [testLabel]() {
           testLabel->setText("Some text from button click");
        });
    
        QVBoxLayout *testLayout = new QVBoxLayout();
        testLayout->setAlignment(Qt::AlignCenter);
        testLayout->addWidget(testLabel);
        testLayout->addWidget(ui->pushButton);
        setLayout(testLayout);
    }
    
    Test::~Test()
    {
        delete ui;
    }
    

    Screenshot:

    ClickableLabel.gif

    Happy coding!



  • @Ucn_ said in Signal and slot from other class not working:

    QObject::connect (upLabText, SIGNAL (SentFromSecondForm() ()), this, SLOT(ReceivedFromSecondForm()));

    From just looking at your code: There's one "()" too much in your connection (signal part).

    Move your class ClickableLabels to its own header file and try again.



  • @Pl45m4 The "()" was an error while copying, I don't have extra "()" in my actual code. About the QLabel, I click it then emit the signal, where I want to update another QLabel text. The QLabel I click, I promoted because QLabel doesn't have On Clicked attribute. So, I used that custom event for QLabel clicking.


  • Qt Champions 2019

    QObject::connect() returns a boolean to indicate if the connect was successful. Also during runtime you will get a warning when the connect is not valid. To avoid this we suggest to use the new signal slot syntax.
    Do you actually see your debug output from ClickableLabels::mousePressEvent() ? I would guess no. At least not from the one you create to do the connection from since this is not the one from the ui file...



  • The signal and slot connection I commented on the main.cpp fires, but it does not update the Qlabel and it does not emit on button click.


  • Qt Champions 2019

    @Ucn_ But your current code can not work as I already explained - you are connecting to another instance of ClickableLabels than the one you're displaying.



  • @Christian-Ehrlicher I would like to emit from the ClickableLabels class. How do I achieve that? I'm kind of lost.



  • @Ucn_

    Hello!

    I have created a simple example to illustrate a clickable label, button and connect using lambdas, so you can simplify your code.

    clickablelabel.h

    #ifndef CLICKABLELABEL_H
    #define CLICKABLELABEL_H
    
    #include <QWidget>
    #include <QLabel>
    #include <QEvent>
    
    class ClickableLabel : public QLabel
    {
        Q_OBJECT
    public:
        using QLabel::QLabel;
    
    signals:
        void clicked();
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
    };
    
    #endif // CLICKABLELABEL_H
    

    clickablelabel.cpp

    #include "clickablelabel.h"
    
    void ClickableLabel::mousePressEvent(QMouseEvent *event)
    {
        emit clicked();
        QLabel::mousePressEvent(event);
    }
    

    test.h

    #ifndef TEST_H
    #define TEST_H
    
    #include <QDialog>
    #include <QVBoxLayout>
    #include "clickablelabel.h"
    
    namespace Ui {
    class Test;
    }
    
    class Test : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit Test(QWidget *parent = nullptr);
        ~Test();
    
    private:
        Ui::Test *ui;
    };
    
    #endif // TEST_H
    

    test.cpp

    #include "test.h"
    #include "ui_test.h"
    
    Test::Test(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::Test)
    {
        ui->setupUi(this);
        setFixedSize(600, 500);
        setWindowFlags(Qt::Dialog | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
        ClickableLabel *testLabel = new ClickableLabel("This is a test label...", this);
        connect(testLabel, &ClickableLabel::clicked, [testLabel]() {
           testLabel->setText("Some text from mouse click");
        });
        ui->pushButton->setText("Test button");
        connect(ui->pushButton, &QPushButton::clicked, [testLabel]() {
           testLabel->setText("Some text from button click");
        });
    
        QVBoxLayout *testLayout = new QVBoxLayout();
        testLayout->setAlignment(Qt::AlignCenter);
        testLayout->addWidget(testLabel);
        testLayout->addWidget(ui->pushButton);
        setLayout(testLayout);
    }
    
    Test::~Test()
    {
        delete ui;
    }
    

    Screenshot:

    ClickableLabel.gif

    Happy coding!



  • @Cobra91151 Thanks, I will give it a try.



  • @Cobra91151 said in Signal and slot from other class not working:

    connect(ui->pushButton, &QPushButton::clicked, testLabel {
    testLabel->setText("Some text from button click");
    });

    The example works, thank. But, is there a way I can pass functions or widgets created in designer to the lambda capture list? Let's say I want to run a function after QLabel click or change a specific label.


  • Lifetime Qt Champion

    @Ucn_

    Hi
    You can capture "this" to allow to use both
    UI->xxx and member functions

     connect(ui->pushButton, &QPushButton::clicked, [this]() {
        ui->xxxxx;
        });
    


  • @mrjj Thanks, It works. however, I don't understand why it works in one example and in the other says

    'QMetaObject::Connection QObject::connect(const QObject *,const char *,const char *,Qt::ConnectionType) const': cannot convert argument 1 from 'QLabel *' to 'const ClickableLabels *'
    

  • Lifetime Qt Champion

    Because you are using a pointer to a QLabel as first parameter and a signal from your ClickableLabel as second parameter.



  • @SGaist what is the viable solution. Cast?


  • Lifetime Qt Champion

    Ensure your original parameter is a ClickableLabel instance.



  • @SGaist Thanks, I promoted QLabel widget in designer to ClickableLabel and it's working. Is it the correct way?


  • Lifetime Qt Champion

    Since you are using Designer, yes.



  • @SGaist Thanks.



  • I know I marked this as solved, and thanks to everyone who helped me understand what I was missing. I'm able to make it work when is widget to widget or promoted with with custom events. However when there is nothing triggered or clicked like a button I'm not able to connect. For example. Function to function, if one function from another class is executed, connect and execute another function in another class. Where the signal is the first executed function and slot is the function executed after the first was triggered. Thanks



  • @Ucn_

    Set up the connect in your constructor and emit the signal, you connect to, in your function A to execute function B in your second class.



  • @Pl45m4

    This only works when I setup in main.cpp and when it fires in won't update anything in the function except print. When I set up in the constructor and place the emit in the function it does not fire,

    QObject::connect(&timer, SIGNAL(printPerSecond()), &w, SLOT(anotherFuncion()));
    
    emit printPerSecond()
    

  • Qt Champions 2019

    @Ucn_ What is timer in your connect?
    Is there a warning at runtime that connect failed?
    You should use the new connect syntax to get compiler error instead of runtime warning if your connect call is wrong.



  • @jsulm It does not give any warning. I tried different connects, it just won't execute the function.



  • This post is deleted!

  • Qt Champions 2019

    @Ucn_ Without more code I can't tell you what the problem is. One possibility: "timer" is not the same instance from where you emit the signal.



  • @jsulm I have as follow in my MainWindow constructor:

        Someclass send;
        QObject::connect(&send, SIGNAL(valueChanged()), SLOT(someFunction()));
    

    I have this signal in Someclass

    signals:
      void valueChanged();
    

    And this Slot in my MainWindow

    private slots:
        void someFunction();
    

    then I emit from a function

    void Someclass::anotherfunction(){
    
        emit valueChanged();
    }
    

  • Qt Champions 2019

    @Ucn_ said in Signal and slot from other class not working:

    Someclass send;
    QObject::connect(&send, SIGNAL(valueChanged()), SLOT(someFunction()));

    Here send is a local variable and is destroyed as soon as it goes out of scope!



  • @jsulm If I declare Someclass *send = new Someclass(); it gives error:

    mainwindow.cpp:18:14: error: no matching member function for call to 'connect'
    qobject.h:467:41: note: candidate function not viable: no known conversion from 'Someclass **' to 'const QObject *' for 1st argument; remove &
    qobject.h:264:13: note: candidate template ignored: requirement 'int(QtPrivate::FunctionPointer<const char *>::ArgumentCount) >= 0' was not satisfied [with Func1 = const char *, Func2 = const char *]
    qobject.h:304:13: note: candidate template ignored: substitution failure [with Func1 = const char *, Func2 = const char *]: no type named 'Object' in 'QtPrivate::FunctionPointer<const char *>'
    qobject.h:232:43: note: candidate function template not viable: requires at least 4 arguments, but 3 were provided
    qobject.h:273:13: note: candidate function template not viable: requires at least 4 arguments, but 3 were provided
    qobject.h:312:13: note: candidate function template not viable: requires at least 4 arguments, but 3 were provided
    qobject.h:212:36: note: candidate function not viable: requires at least 4 arguments, but 3 were provided
    qobject.h:215:36: note: candidate function not viable: requires at least 4 arguments, but 3 were provided
    

    I handle keypress event in Someclass, but is just an example. I want to emit valueChanged(); when a specific key is pressed or when a function is run, even though I did remove & to:

    Someclass *send = new Someclass()
    QObject::connect(send, SIGNAL(valueChanged()), SLOT(someFunction()));
    

    Still doesn't fire.


  • Qt Champions 2019

    @Ucn_ Don't you have send as class member?
    Regarding error: simply remove & in front of send in connect as send is now already a pointer.

    QObject::connect(send, SIGNAL(valueChanged()), SLOT(someFunction()));
    

Log in to reply