c++qtqt5qt-signalsqt-slot

A warning message "No matching signal for" when executing my application


When executing my application some warning messages appear:
QMetaObject::connectSlotsByName: No matching signal for on_actionUndo_triggered(), QMetaObject::connectSlotsByName: No matching signal for on_actionRedo_triggered()

I have implemented the rule void on_objectName_signalName(signalParameters); to the signal and slot that I have created and I don't know why that messages appear, note that the signal and slot work fine.

Declaration:

class Widget : public QWidget {
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
    QAction *actionUndo;
    QAction *actionRedo;

private slots:
    void on_actionUndo_triggered();
    void on_actionRedo_triggered();
};

Definition:

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);   
    QVBoxLayout *layout = new QVBoxLayout(this);
    QMenuBar *menuBar = new QMenuBar();
    QMenu *editMenu = new QMenu("&Edit");
    menuBar->addMenu(editMenu);

    this->actionUndo = new QAction("&Undo", editMenu);
    this->actionUndo->setShortcut(QKeySequence::Undo);
    QObject::connect(this->actionUndo, SIGNAL(triggered()), this, SLOT(on_actionUndo_triggered()));

    this->actionRedo = new QAction("&Redo", editMenu);
    this->actionRedo->setShortcut(QKeySequence::Redo);
    QObject::connect(this->actionRedo, SIGNAL(triggered()), this, SLOT(on_actionRedo_triggered()));

    editMenu->addAction(this->actionUndo);
    editMenu->addAction(this->actionRedo);

    this->layout()->setMenuBar(menuBar);
}

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


void Widget::on_actionUndo_triggered() {

}

void Widget::on_actionRedo_triggered() {

}

Solution

  • The warning arises because within the function setupUi calls the function connectSlotsByName.

    void setupUi(QWidget *Widget)
    {
        [...]
        QMetaObject::connectSlotsByName(Widget);
    }
    

    According to the documentation:

    void QMetaObject::connectSlotsByName(QObject * object)

    Searches recursively for all child objects of the given object, and connects matching signals from them to slots of object that follow the following form:

    void on_<object name>_<signal name>(<signal parameters>);

    Then this function looks for objects actionUndo and actionRedo and does not find them because they are not created, a simple solution is to create them before setupUi and pass a name with setObjectName:

    actionUndo = new QAction("&Undo", this);
    actionUndo->setObjectName("actionUndo");
    actionRedo = new QAction("&Redo", this);
    actionRedo->setObjectName("actionRedo");
    ui->setupUi(this);
    

    With this configuration you will no longer need to make the connections, ie you do not need to implement the next line.

    QObject::connect(this->actionUndo, SIGNAL(triggered()), this, SLOT(on_actionUndo_triggered()));
    QObject::connect(this->actionRedo, SIGNAL(triggered()), this, SLOT(on_actionRedo_triggered()));
    

    complete code:

    .h

    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
    
    private slots:
        void on_actionUndo_triggered();
        void on_actionRedo_triggered();
    
    private:
        Ui::Widget *ui;
        QAction *actionUndo;
        QAction *actionRedo;
    };
    

    .cpp

    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        actionUndo = new QAction("&Undo", this);
        actionUndo->setObjectName("actionUndo");
        actionUndo->setShortcut(QKeySequence::Undo);
    
        actionRedo = new QAction("&Redo", this);
        actionRedo->setObjectName("actionRedo");
        actionRedo->setShortcut(QKeySequence::Redo);
    
        ui->setupUi(this);
    
        setLayout(new QVBoxLayout);
    
        QMenuBar *menuBar = new QMenuBar(this);
        QMenu *editMenu = new QMenu("&Edit");
    
        menuBar->addMenu(editMenu);
        editMenu->addAction(actionUndo);
        editMenu->addAction(actionRedo);
    
        layout()->setMenuBar(menuBar);
    
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    
    void Widget::on_actionUndo_triggered()
    {
        qDebug()<<"undo";
    }
    
    void Widget::on_actionRedo_triggered()
    {
        qDebug()<<"redo";
    }