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() {
}
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";
}
Related
I trying to display some text to a textbrowser via: FindChild and it never displays it in the textbrowswer any help would be helpfull..
Here is my mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
namespace Ui
{
class MainWindow;
class TestWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow* GetInstance(QWidget* parent = 0);
signals:
public slots:
void on_pushButton_3_clicked();
void MainWindow_TextBrowser_String(const QString & newText);
private:
Ui::MainWindow *ui;
static MainWindow* mainInstance;
};
Here is my mainwindow.cpp
// Constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
// Destructor
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_3_clicked()
{
TestWindow mwindow;
mwindow.start();
}
MainWindow* MainWindow::mainInstance = 0;
MainWindow* MainWindow::GetInstance(QWidget *parent)
{
if (mainInstance == NULL)
{
mainInstance = new MainWindow(parent);
}
return mainInstance;
}
void MainWindow::MainWindow_TextBrowser_String(const QString & newText)
{
QString TextBrowser_String = QString(newText);
ui->textBrowser->append(TextBrowser_String);
}
I create the testwindow object in the pushbutton send the start function to call the findchild window to send a string to the textbrowser window
Here is my testwindow.cpp
void testwindow::start()
{
// Create a new mainwindow on the heap.
MainWindow* instance = MainWindow::GetInstance();
// Or I can call
// MainWindow instance; then point to findchild
QString Test_Window_String = QStringLiteral("Test Window String");
instance->findChild<QTextBrowser*>("textBrowser")->append(Test_Window_String);
}
I understand that you can use a singal and slot and simply just create a signal that sends the string to the append textbrowser
void testwindow::singalandslot()
{
MainWindow* instance = MainWindow::GetInstance();
connect(this, SIGNAL(TextBrowswer_String(const QString &)), instance , SLOT(MainWindow_TextBrowser_String(QString &)));
}
void testwindow::fireSignal()
{
emit TextBrowswer_String("sender is sending to receiver.");
}
Even with a signal or FindChild it seems that the object is already deleted or i'm doing something wrong.
Can you please share your Ui::MainWindow Class and setupUi implementation to get a clear view?
Hope you have created the instance for QTextBrowser* inside setupUi or in the constructor.
With the below setupUi implementation, both ur usecases are working.
namespace Ui
{
class MainWindow: public QWidget
{
Q_OBJECT
public:
QTextBrowser* textBrowser;
void setupUi(QWidget* parent)
{
setParent(parent);
textBrowser = new QTextBrowser(parent);
textBrowser->setObjectName("textBrowser");
textBrowser->setText("Hello");
}
};
}
I'm new to QT5, and I'm having a very strange problem.
I want to use QTimer to read coordinate from serial device every 0.5 second, but the QTimer won't send timeout signal.
My .h:
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
Ui::MainWindow *ui;
};
My .cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer myTimer(this);
myTimer.setInterval(500);
myTimer.setSingleShot(false);
connect(&myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer.start();
}
void MainWindow::test() {
qDebug() << "Time out";
}
MainWindow::~MainWindow()
{
delete ui;
}
After I started the program, not a single "Time out" shows up...
I added the following codes after "myTimer.start()":
QTime t = QTime::currentTime().addMSecs(550);
while (QTime::currentTime() < t) {
qDebug() << myTimer.remainingTime();
}
And I found that after the remaining time of "myTimer" reduced to 0, it won't refill the remaining time and start once again, it remains at 0.
Q_OBJECT is already added
Anyone got an idea?
Thank you very much!
The problem is here:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer myTimer(this);
myTimer.setInterval(500);
myTimer.setSingleShot(false);
connect(&myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer.start();
}
In the constructor you declared myTimer automatically, so it will be destroyed as soon as constructor returns. This way, by the time when you expect timeout event, myTimer does not exist anymore and thus it cannot send any signals!
The solution is straightforward: myTimer should exist all the time MainWindow object lives, so declare it in the class, not in it's constructor, and allocate it dynamically:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void test();
private:
QTimer *myTimer; // <--- pointer declaration.
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Allocating actual QTimer object:
myTimer = new QTimer(this);
// Calling methods by object pointer:
myTimer->setInterval(500);
myTimer->setSingleShot(false);
connect(myTimer, SIGNAL(timeout()), this, SLOT(test()));
myTimer->start();
}
MainWindow::~MainWindow()
{
// Don't forget to delete after usage.
delete myTimer;
delete ui;
}
myTimer is local.
Make it a class member and use it. It will work.
I wanted to create a simple application where there's triangle generated using OpenGL and three push buttons changing that triangle color. The triangle is generated but unfortunately buttons don't work and I get errors saying:
QObject::connect: No such slot MainWindow::redSlot(OGL) in
..\buttonwidget\mainwindow.cpp:17 QObject::connect: No such slot
MainWindow::greenSlot(OGL) in ..\buttonwidget\mainwindow.cpp:20
QObject::connect: No such slot MainWindow::blueSlot(OGL) in
..\buttonwidget\mainwindow.cpp:23
I have slots definitions:
void MainWindow::redSlot(Widget* w)
{
w->setColor(red);
}
void MainWindow::greenSlot(Widget* w)
{
w->setColor(green);
}
void MainWindow::blueSlot(Widget* w)
{
w->setColor(blue);
}
They are changing variable declared in class Widget that changes color of a generated triangle. Here's class Widget:
class Widget : public QGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
QSize minimumSizeHint() const;
QSize sizeHint() const;
enum color c;
void setColor(enum color color1);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
And then I connect slots to buttons in class MainWindow constructor:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
layout = new QVBoxLayout();
QWidget *w = new QWidget();
setCentralWidget(w);
w->setLayout(layout);
Widget *OGL = new Widget();
//OGL->c=green; - it was a test whether changing value of enum type variable c works
//it works, changing it changes the color of a generated triangle
redButton = new QPushButton(tr("Red"));
connect(redButton, SIGNAL(clicked()), this, SLOT(redSlot(OGL)));
greenButton = new QPushButton(tr("Green"));
connect(greenButton, SIGNAL(clicked()), this, SLOT(greenSlot(OGL)));
blueButton = new QPushButton(tr("Blue"));
connect(blueButton, SIGNAL(clicked()), this, SLOT(blueSlot(OGL)));
layout->addWidget(OGL);
layout->addWidget(redButton);
layout->addWidget(greenButton);
layout->addWidget(blueButton);
}
Here's slot declaration in header:
class MainWindow : public QMainWindow
{
Q_OBJECT
QVBoxLayout *layout;
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QPushButton *redButton;
QPushButton *greenButton;
QPushButton *blueButton;
public slots:
void redSlot(Widget*);
void greenSlot(Widget*);
void blueSlot(Widget*);
};
How should I make them work?
Connects in QT are string-based, that means:
connect(redButton, SIGNAL(clicked()), this, SLOT(redSlot(OGL)));
will not work, since you havent defined a slot "redSlot(OGL)", instead you would have to use
...SLOT(redSlot(Widget*)));
Moreover, it is possible to define a SLOT with less parameter but not with more, therefore your slot/connect has to look like
void redSlot();
connect(redButton, SIGNAL(clicked()), this, SLOT(redSlot()));
if you need a pointer to the "Widget" you have to retrieve it from somewhere else.
Example: Define slot in "Widget"-class and change connect to:
connect(redButton, SIGNAL(clicked()), OGL, SLOT(redSlot()));
I'm connecting a signal/slot but the slot is called multiple times (1, 2, 3...) every time I trigger the option, here are my classes:
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Dialog *dialog;
signals:
void s1(QString s);
private slots:
void on_actionTooo_triggered();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionTooo_triggered()
{
dialog = new Dialog(this);
QString s = "hello";
qDebug() << "CONNECT: " << connect(this, SIGNAL(s1(QString)),
dialog, SLOT(s1(QString)), Qt::UniqueConnection);
emit s1(s);
dialog->show();
}
dialog.h:
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
void s1(QString str);
private:
Ui::Dialog *ui;
};
dialog.cpp:
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::s1(QString str)
{
qDebug() << str << endl;
}
Every time the option is triggered in the main window, I connect the signal (just once), to the new dialog, but when I run, for example two times, it prints two "hello". If I put a disconnect(this, 0, 0, 0); before I connect the signals it works.
It seems odd to me that it maintains the connect even when the object is destroyed. It binds the connect to the same object created before. Is this the expected behavior?
You are creating a new Dialog everytime you call on_actionTooo_triggered(). This Dialog isn't deleted at the end of your function. Therefore with the next call the signal MainWindow::s1(QString) is emitted to the two different Dialogs which results in multiple ouptuts in qDebug.
void MainWindow::on_actionTooo_triggered()
{
dialog = new Dialog(this);
QString s = "hello";
qDebug() << "CONNECT: " << connect(this, SIGNAL(s1(QString)),
dialog, SLOT(s1(QString)), Qt::UniqueConnection);
emit s1(s);
dialog->show();
}
This code creates a new dialog each time it's triggered and sets up a connection between the newly created dialog and the MainWindow. While the connection is specified as "Unique", a new dialog is created each time, so the connection is not unique as the dialog instance is different.
Your code does not show that the dialog is being deleted and even if you close its window, the instance still remains in memory, so multiple objects are receiving the same signal.
Your Dialog is never destroyed in this code. It's not even leaked as you pass this as a parent in the Dialog's constructor, which makes the MainWindow responsible for this Dialog memory.
Thus you permanently create additional Dialog which slot will be triggered, and thus explaining why you see an incrementally increasing repetition of the output.
I'm trying to write a very basic program. The main window contains a label. Pressing the "Add New" button opens a QDialog with a QLineEdit. Changing the text, press "Add" and I would like the QLabel in the main window to be updated with the text from QLineEdit. I can get the signals through but the label is not updating. I understand that connect only works on instances of classes, not classes themselves. The problem seems to be the one class is not aware of the instance of the main window.
What I've tried to do is once the Add button is pressed, a signal is emitted. Once that signal is emitted, the slot in the mainWindow class receives a string to use in QLabel::setText().
I've read countless examples and documentation but the examples seem to be too different from the simple task I'm lost in. Any help is appreciated.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
#include <QLabel>
class QLineEdit;
class QPushButton;
class QLabel;
class addDlg : public QDialog{
Q_OBJECT
public:
addDlg(QWidget *parent = 0);
signals:
void textChanged(const QString &text);
private slots:
void sendText(QWidget *parent);
private:
QPushButton *addButton;
QLineEdit *inputText;
};
class mainWindow : public QWidget{
Q_OBJECT
public:
mainWindow();
QLabel *textLabel;
public slots:
void recvText(const QString &text);
private slots:
void addDlgShow();
private:
QPushButton *addWindow;
addDlg *dialog;
};
#endif // MAINWINDOW_H
MainWindow.cpp
addDlg::addDlg(QWidget *parent)
: QDialog(parent){
inputText = new QLineEdit(tr("enter here"));
addButton = new QPushButton(tr("Accept"));
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(inputText);
vLayout->addWidget(addButton);
setLayout(vLayout);
setWindowTitle(tr("Add new text"));
connect(addButton, SIGNAL(clicked()),
this, SLOT(sendText()));
}
void addDlg::sendText(){
QString text = inputText->text();
emit textChanged(text);
// This connect is where I believe the problem lies.
connect(this, SIGNAL(textChanged(QString)),
mainPtr, SLOT(recvText(QString)));
//mainPtr is uninitialized as I can't seem to point it to the manWindow instance
//I can do mainWindow* mainPtr = new mainWindow but that just creates a new instance.
//How do I pass on the first mainWindow main instance "mainPtr" to this class addDlg?
}
mainWindow::mainWindow()
: QWidget(0){
textLabel = new QLabel(tr("Empty"));
addWindow = new QPushButton(tr("Add New"));
dialog = new addDlg();
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(textLabel);
vLayout->addWidget(addWindow);
setLayout(vLayout);
setWindowTitle(tr("Test 4"));
connect(addWindow, SIGNAL(clicked()),
this, SLOT(addDlgShow()));
}
void mainWindow::addDlgShow(){ dialog->show(); }
void mainWindow::recvText(const QString &text){
QString input = text;
textLabel->clear();
textLabel->setText(input);
textLabel->update();
}
One solution is to put your connect code in mainWindow::mainWindow where you have pointers to both the mainwindow and your newly created dialog. The snippet might change to this:
mainWindow::mainWindow() : QWidget(0) {
// ... existing code ..
// add this
connect(dialog, SIGNAL(textChanged(QString)),
this, SLOT(recvText(QString)));
}