Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Alternative signal and slot crashes if there is a widget to update in the slot
Forum Updated to NodeBB v4.3 + New Features

Alternative signal and slot crashes if there is a widget to update in the slot

Scheduled Pinned Locked Moved Solved General and Desktop
4 Posts 3 Posters 553 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • U Offline
    U Offline
    Ucn_
    wrote on last edited by
    #1

    For weeks I have been trying to make qt signal work, however I can only get the following work:
    1-same class (widget to function)
    example:

    connect(button1, &QPushButton::clicked, this, &SecondForm::function1);
    

    2-lambda capture list, same class (widget to function or widget to widget)
    example:

    connect(ui->pushButton, &QPushButton::clicked, [this]() {
         //same class function
         function2();
       //or
         ui->pushButton->setText("Some text");
    
        });
    

    3-lambda capture list (different class, custom event )
    example:

            QObject::connect(ui->label_4, &ClickableLabels::clicked, [this]() {
    
                ui->stackedWidget_2->setCurrentIndex(2);
            });
    

    My problem is I can't get (function to function) work
    for example: I have a signal in class B and slot in class A, I want to emit the signal in class B after a button is clicked or on function execute, so it will execute the slot in class A and update something. Let's consider class A as MainWindow. I have tried all sort of connect, but the signal won't emit except if I place the emit in the main.cpp, however it won't update anything and I wouldn't want to place there. and it doesn't give any error.

    The solution I found, but not worked as expected. I have been looking for solutions and I found this SigSlot (Sigslot is a header-only, thread safe implementation of signal-slots for C++. The main goal was to replace Boost.Signals2. etc). This is easy, while qt signal and slot, connecting two functions from different classes that one happens to be the MainWindow has never worked for me. But SigSlot worked out of the box. The problem with this solution is: If the slot doesn't have anything in the function or it only has something to print like qDebug() it will run. However, if it has a widget to update like ui->pushButton->setText("SomeText") it will crash. I don't understand what is the relation between the signal/slot and the ui, if the emit works and function runs then why not update widget, but crash.

    If someone has knowledge on this I would appreciate any help. I will post a simple example bellow. Thanks

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include "secondform.h"
    #include <QMainWindow>
    #include <QObject>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    public slots:
        void sigRunFunction(QString text);
    
    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);
    
    
    }
    
    void MainWindow::sigRunFunction(QString text){
    
        //uncomment the "ui->pushButton->setText("Some text")" and it will crash,
        //I want to update multiple widgets after the signal is emitted,
        //but it won't update.
    
        //ui->pushButton->setText("Some text");
        qDebug() <<"Signal Received" << text;
    }
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_pushButton_clicked()
    {
        captureWig = new SecondForm(this);
        captureWig->bringfunction();
        QVBoxLayout *sendWig = new QVBoxLayout;
        sendWig = captureWig->getTreeto();
    
        QWidget *w = new QWidget();
        w->setLayout(sendWig);
    
        ui->tabWidget->addTab(w, "Newtab");
    }
    
    

    secondform.h
    signal.hpp file

    #ifndef SECONDFORM_H
    #define SECONDFORM_H
    #include "signal.hpp"
    //#include "qt.hpp"
    #include <QObject>
    #include <QWidget>
    #include <QtWidgets>
    #include <QEvent>
    #include <QLabel>
    
    namespace Ui {
    class SecondForm;
    }
    
    class SecondForm : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit SecondForm(QWidget *parent = nullptr);
        ~SecondForm();
        QVBoxLayout *getTreeto();
        QPushButton *button_first;
    
        void bringfunction(){
    
            multb();
                           }
    
      sigslot::signal<QString> sig;
    
    signals:
    
    private:
        void multb();
        void test();
        Ui::SecondForm *ui;
    };
    
    #endif // SECONDFORM_H
    
    

    secondform.cpp

    #include "secondform.h"
    #include "ui_secondform.h"
    #include "mainwindow.h"
    
    
    
    SecondForm::SecondForm(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::SecondForm)
    {
        ui->setupUi(this);
        
    //   MainWindow *w = new Mainwindow(); It won't run
    //   MainWindow w; It won't run
       MainWindow *w;
       sig.connect(&MainWindow::sigRunFunction, w);
    
    
    }
    
    QVBoxLayout *SecondForm::getTreeto(){
    
        return ui->verticalLayout_6;
    }
    
    void SecondForm::multb(){
    
        for (char letter = 'A'; letter <= 'M'; ++letter) {
    
            std::string s;
            s += letter;
            QString qstr = QString::fromStdString(s);
            button_first = new QPushButton(qstr);
            ui->horizontalLayoutfv->addWidget(button_first);
    
            connect(button_first, &QPushButton::clicked, this, &SecondForm::test);
    
       }
    
     }
    
    void SecondForm::test(){
        QPushButton* buttonSender = qobject_cast<QPushButton*>(sender());
        QString buttonText = buttonSender->text();
        qDebug() << "buttonSender" << buttonText;
        emit sig(buttonText);
    }
    
    SecondForm::~SecondForm()
    {
        delete ui;
    }
    
    

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
    
        QApplication a(argc, argv);
    
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    
    
    

    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>164</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>
            <layout class="QHBoxLayout" name="horizontalLayoutfv"/>
           </item>
           <item>
            <layout class="QVBoxLayout" name="verticalLayout4"/>
           </item>
          </layout>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
     <resources/>
     <connections/>
    </ui>
    
    
    Pablo J. RoginaP 1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      Hi
      The code is a bit confusing.
      You create a SecondForm from your exiting MainWindow

      void MainWindow::on_pushButton_clicked()
      {
          captureWig = new SecondForm(this);
          captureWig->bringfunction();
          QVBoxLayout *sendWig = new QVBoxLayout;
          sendWig = captureWig->getTreeto();
      
          QWidget *w = new QWidget();
          w->setLayout(sendWig);
      
          ui->tabWidget->addTab(w, "Newtab");
      }
      

      But in SecondForm, you seem to try to create yet another mainwindow which is not the one that created SecondForm and
      not shown on screen.

      SecondForm::SecondForm(QWidget *parent) :
          QWidget(parent),
          ui(new Ui::SecondForm)
      {
          ui->setupUi(this);
          
      //   MainWindow *w = new Mainwindow(); It won't run --> it wont be the window u already have but new one
      //   MainWindow w; It won't run -> no as this runs out at scope and get deleted
         MainWindow *w; // this is dangling pointer 
         sig.connect(&MainWindow::sigRunFunction, w);
      }
      

      So do you want to talk to the existing mainwindow or do u really mean to make a new instance that then get the signal.

      If you mean to talk back to the existing window, you MUST use that instance and not go and create new ones.

      A good place would be in

      void MainWindow::on_pushButton_clicked()
      {
          captureWig = new SecondForm(this);
         connect ( SecondForm, THESIGNAL, this, SomeSlot in your MainWindow);
         
      

      if this in what you want.

      the https://github.com/palacaze/sigslot
      is completed not needed.
      Qt has anything you need for this to work. You just need to do it correctly :)

      U 1 Reply Last reply
      4
      • U Ucn_

        For weeks I have been trying to make qt signal work, however I can only get the following work:
        1-same class (widget to function)
        example:

        connect(button1, &QPushButton::clicked, this, &SecondForm::function1);
        

        2-lambda capture list, same class (widget to function or widget to widget)
        example:

        connect(ui->pushButton, &QPushButton::clicked, [this]() {
             //same class function
             function2();
           //or
             ui->pushButton->setText("Some text");
        
            });
        

        3-lambda capture list (different class, custom event )
        example:

                QObject::connect(ui->label_4, &ClickableLabels::clicked, [this]() {
        
                    ui->stackedWidget_2->setCurrentIndex(2);
                });
        

        My problem is I can't get (function to function) work
        for example: I have a signal in class B and slot in class A, I want to emit the signal in class B after a button is clicked or on function execute, so it will execute the slot in class A and update something. Let's consider class A as MainWindow. I have tried all sort of connect, but the signal won't emit except if I place the emit in the main.cpp, however it won't update anything and I wouldn't want to place there. and it doesn't give any error.

        The solution I found, but not worked as expected. I have been looking for solutions and I found this SigSlot (Sigslot is a header-only, thread safe implementation of signal-slots for C++. The main goal was to replace Boost.Signals2. etc). This is easy, while qt signal and slot, connecting two functions from different classes that one happens to be the MainWindow has never worked for me. But SigSlot worked out of the box. The problem with this solution is: If the slot doesn't have anything in the function or it only has something to print like qDebug() it will run. However, if it has a widget to update like ui->pushButton->setText("SomeText") it will crash. I don't understand what is the relation between the signal/slot and the ui, if the emit works and function runs then why not update widget, but crash.

        If someone has knowledge on this I would appreciate any help. I will post a simple example bellow. Thanks

        mainwindow.h

        #ifndef MAINWINDOW_H
        #define MAINWINDOW_H
        #include "secondform.h"
        #include <QMainWindow>
        #include <QObject>
        
        namespace Ui {
        class MainWindow;
        }
        
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
        
        public:
            explicit MainWindow(QWidget *parent = nullptr);
            ~MainWindow();
        
        public slots:
            void sigRunFunction(QString text);
        
        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);
        
        
        }
        
        void MainWindow::sigRunFunction(QString text){
        
            //uncomment the "ui->pushButton->setText("Some text")" and it will crash,
            //I want to update multiple widgets after the signal is emitted,
            //but it won't update.
        
            //ui->pushButton->setText("Some text");
            qDebug() <<"Signal Received" << text;
        }
        MainWindow::~MainWindow()
        {
            delete ui;
        }
        
        
        void MainWindow::on_pushButton_clicked()
        {
            captureWig = new SecondForm(this);
            captureWig->bringfunction();
            QVBoxLayout *sendWig = new QVBoxLayout;
            sendWig = captureWig->getTreeto();
        
            QWidget *w = new QWidget();
            w->setLayout(sendWig);
        
            ui->tabWidget->addTab(w, "Newtab");
        }
        
        

        secondform.h
        signal.hpp file

        #ifndef SECONDFORM_H
        #define SECONDFORM_H
        #include "signal.hpp"
        //#include "qt.hpp"
        #include <QObject>
        #include <QWidget>
        #include <QtWidgets>
        #include <QEvent>
        #include <QLabel>
        
        namespace Ui {
        class SecondForm;
        }
        
        class SecondForm : public QWidget
        {
            Q_OBJECT
        
        public:
            explicit SecondForm(QWidget *parent = nullptr);
            ~SecondForm();
            QVBoxLayout *getTreeto();
            QPushButton *button_first;
        
            void bringfunction(){
        
                multb();
                               }
        
          sigslot::signal<QString> sig;
        
        signals:
        
        private:
            void multb();
            void test();
            Ui::SecondForm *ui;
        };
        
        #endif // SECONDFORM_H
        
        

        secondform.cpp

        #include "secondform.h"
        #include "ui_secondform.h"
        #include "mainwindow.h"
        
        
        
        SecondForm::SecondForm(QWidget *parent) :
            QWidget(parent),
            ui(new Ui::SecondForm)
        {
            ui->setupUi(this);
            
        //   MainWindow *w = new Mainwindow(); It won't run
        //   MainWindow w; It won't run
           MainWindow *w;
           sig.connect(&MainWindow::sigRunFunction, w);
        
        
        }
        
        QVBoxLayout *SecondForm::getTreeto(){
        
            return ui->verticalLayout_6;
        }
        
        void SecondForm::multb(){
        
            for (char letter = 'A'; letter <= 'M'; ++letter) {
        
                std::string s;
                s += letter;
                QString qstr = QString::fromStdString(s);
                button_first = new QPushButton(qstr);
                ui->horizontalLayoutfv->addWidget(button_first);
        
                connect(button_first, &QPushButton::clicked, this, &SecondForm::test);
        
           }
        
         }
        
        void SecondForm::test(){
            QPushButton* buttonSender = qobject_cast<QPushButton*>(sender());
            QString buttonText = buttonSender->text();
            qDebug() << "buttonSender" << buttonText;
            emit sig(buttonText);
        }
        
        SecondForm::~SecondForm()
        {
            delete ui;
        }
        
        

        main.cpp

        #include "mainwindow.h"
        #include <QApplication>
        
        int main(int argc, char *argv[])
        {
        
            QApplication a(argc, argv);
        
            MainWindow w;
            w.show();
        
            return a.exec();
        }
        
        
        

        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>164</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>
                <layout class="QHBoxLayout" name="horizontalLayoutfv"/>
               </item>
               <item>
                <layout class="QVBoxLayout" name="verticalLayout4"/>
               </item>
              </layout>
             </widget>
            </item>
           </layout>
          </widget>
         </widget>
         <resources/>
         <connections/>
        </ui>
        
        
        Pablo J. RoginaP Offline
        Pablo J. RoginaP Offline
        Pablo J. Rogina
        wrote on last edited by
        #3

        @Ucn_ said in Alternative signal and slot crashes if there is a widget to update in the slot:

        : I have a signal in class B and slot in class A, I want to emit the signal in class B after a button is clicked or on function execute, so it will execute the slot in class A and update something.

        The idea with signals and slots is that a class B will emit a signal for whatever a reason, without knowing or caring what other class with make use of such event. Think of the signal as a radio station broadcast, it will broadcast whether there are thousands, one or no radio receivers turned on.

        So for a slot in another class A to be called when the signal is fired, that class A is responsible for making the proper "wiring", i.e. to connect signal from B to its desired slot. BUT for this to happen, class A should have an object B "visible", i.e. within scope.

        So as @mrjj already mentioned, the connect() is wrong placed, you need to make the connection in class MainWindows where the slot is defined and you have a SecondForm object available. Please pay attention to @mrjj suggestion for MainWindow::on_pushButton_clicked() method...

        Upvote the answer(s) that helped you solve the issue
        Use "Topic Tools" button to mark your post as Solved
        Add screenshots via postimage.org
        Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

        1 Reply Last reply
        5
        • mrjjM mrjj

          Hi
          The code is a bit confusing.
          You create a SecondForm from your exiting MainWindow

          void MainWindow::on_pushButton_clicked()
          {
              captureWig = new SecondForm(this);
              captureWig->bringfunction();
              QVBoxLayout *sendWig = new QVBoxLayout;
              sendWig = captureWig->getTreeto();
          
              QWidget *w = new QWidget();
              w->setLayout(sendWig);
          
              ui->tabWidget->addTab(w, "Newtab");
          }
          

          But in SecondForm, you seem to try to create yet another mainwindow which is not the one that created SecondForm and
          not shown on screen.

          SecondForm::SecondForm(QWidget *parent) :
              QWidget(parent),
              ui(new Ui::SecondForm)
          {
              ui->setupUi(this);
              
          //   MainWindow *w = new Mainwindow(); It won't run --> it wont be the window u already have but new one
          //   MainWindow w; It won't run -> no as this runs out at scope and get deleted
             MainWindow *w; // this is dangling pointer 
             sig.connect(&MainWindow::sigRunFunction, w);
          }
          

          So do you want to talk to the existing mainwindow or do u really mean to make a new instance that then get the signal.

          If you mean to talk back to the existing window, you MUST use that instance and not go and create new ones.

          A good place would be in

          void MainWindow::on_pushButton_clicked()
          {
              captureWig = new SecondForm(this);
             connect ( SecondForm, THESIGNAL, this, SomeSlot in your MainWindow);
             
          

          if this in what you want.

          the https://github.com/palacaze/sigslot
          is completed not needed.
          Qt has anything you need for this to work. You just need to do it correctly :)

          U Offline
          U Offline
          Ucn_
          wrote on last edited by Ucn_
          #4

          @mrjj and @Pablo-J-Rogina thanks for the help. This worked.

          void MainWindow::on_pushButton_clicked()
          {
              captureWig = new SecondForm(this);
              QObject::connect(captureWig, &SecondForm::clicked, this, &MainWindow::someSlotW);
          

          You are right about creating at the wrong place and having many instances.

          1 Reply Last reply
          2

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved