I have a text editor like program which is a QMainWindow inherited class. There, when I click Find, the connection,
connect(actionFind,SIGNAL(triggered()),this,SLOT(actionFindTriggered()));
Activates. And the defination of that function is
void MainWindow::actionFindTriggered() {
new Find(this);
}
My Find class is
class Find : public QDialog, public Ui::Dialog
{
public:
Find(QWidget *parent=0);
private:
Ui::Dialog *ui;
public slots:
void buttonFindTriggered();
};
And the definition is
Find::Find(QWidget *parent)
: QDialog(parent)
{
ui = new Ui::Dialog;
ui->setupUi(this);
show();
this->
connect(ui->buttonClose, SIGNAL(clicked()), this, SLOT(close()));
connect(ui->buttonFind, SIGNAL(clicked()), this, SLOT(buttonFindTrigddgered()));
}
void Find::buttonFindTriggered() {
qDebug() << "FIND ACTIVATED";
}
What is the problem
When I clicked find from the main window, find window works successfully but could not make the connection. And I get the following msg on console,
Object::connect: No such slot QDialog::buttonFindTriggered() // Edited
Object::connect: (sender name: 'buttonFind')
Object::connect: (receiver name: 'Dialog')
Edited due to a typo...!
You forgot the Q_OBJECT macro.
Also - consider using this notation for getting slot auto-connection (setupUI will automatically connect these slot for you).
void on_buttonFind_clicked();
void on_buttonClose_clicked();
As the error message states, it can't find the slot:
buttonFindTrigddgered()
because it should be:
buttonFindTriggered()
Related
I am making a simple game and want to send a signal from my Game class to my MainWindow. My signal and slot share the same parameter but I can't connect them. I have tried sending very simple signals with a dummy variable but failed to connect. The code is as follows.
game.h
class Game : public QObject
{
Q_OBJECT
public:
Game();
signals:
void test(int l);
MainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void testSlot(int l);
game.cpp
void someFunction(){
emit test(2);
}
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
g{new Game()}
{
ui->setupUi(this);
g->gameLoop();
connect(g,&Game::test,this,&MainWindow::testSlot);
}
How can I get the signals and slots to connect properly? Thank you in advance.
I think the problem may be in the fact that you have g->gameLoop(); BEFORE the connect. If your someFunction is called from the gameLoop, then the connect is performed only after the game has finished and after the execution returns from the gameLoop(). But of course it's just guessing. I wouldn't expect to see 'gameLoop' called from the Window's constructor so.. it looks odd as well. Other than that, it looks fine, so if my guess is not correct, then probably the problem lies elsewhere in the code we don't see.
I create a new QWidget object and I want to know when the close button is pressed.
I have tried the following code:
pWindow = new QWidget();
connect(pWindow , SIGNAL(triggered()), this, SLOT(processCloseButtonWindowsClicked()));
but it give an error:
no signal triggered of pWindow
How to achieve this?
Cause
QWidget does not have a triggered signal.
Solution
I would suggest you to:
Subclass QWidget and reimplement QWidget::closeEvent
Check QEvent::spontaneous to differentiate between a click of the close button and the call to QWidget::close
According to your app's logic either call QWidget::closeEvent(event); to close the widget, or QEvent::ignore to leave it open
Example
I have prepared an example for you of how to implement the proposed solution:
#include <QMainWindow>
#include <QCloseEvent>
#include <QPushButton>
class FooWidget : public QWidget
{
Q_OBJECT
public:
explicit FooWidget(QWidget *parent = nullptr) :
QWidget(parent) {
auto *button = new QPushButton(tr("Close"), this);
connect(button, &QPushButton::clicked, this, &FooWidget::close);
resize(300, 200);
setWindowTitle("Foo");
}
protected:
void closeEvent(QCloseEvent *event) override {
if (event->spontaneous()) {
qDebug("The close button was clicked");
// do event->ignore();
// or QWidget::closeEvent(event);
} else {
QWidget::closeEvent(event);
}
}
};
class MainWindow : public QMainWindow
{
Q_OBJECT
FooWidget *pWindow;
public:
explicit MainWindow(QWidget *parent = nullptr) :
QMainWindow(parent),
pWindow(new FooWidget()) {
pWindow->show();
}
};
void QWidget::closeEvent(QCloseEvent *event) will be the possible way I would go with.
You can read the documentation here.
Before, check if Qt has a class for what you want to do. Maybe you want to use QDialog instead of QWidget for what you want to achieve.
The following code: suppose you want to delete the widget when the X is clicked and you just want to know when to do something.
Try connecting the signal from the base class QObject of your widget when it is Destroyed:
-Your Widget
-attribute setted to destroy your widget after X(closebotton is clicked) or the close() handler is triggered
-connect the destroyed() signal to whatever slot you want to do something before it is destroyed
pWindow = new QWidget();
pWindow->setAttribute(Qt::WA_DeleteOnClose,true);
connect(pWindow , SIGNAL(destroyed()), this,SLOT(processCloseButtonWindowsClicked()));
for more info:
https://doc.qt.io/qt-5/qwidget.html#close
https://doc.qt.io/qt-5/qobject.html#destroyed
I connected the clicked(bool) event from QPushButton to a private slot mySlot() of my own Widget. But the slot is never called (I placed a breakpoint in mySlot()). I'm using c++ and Qt5.
I wrote a minimal version of my code:
MyLayout.h
class MyLayout : public QWidget
{
Q_OBJECT
public:
MyLayout(QWidget* parent = NULL);
private:
QPushButton *next;
private slots:
void mySlot();
}
MyLayout.cpp
MyLayout::MyLayout(QWidget* parent) : QWidget(parent)
{
next = new QPushButton("Next Step");
QObject::connect(next, SIGNAL(clicked(bool)), this, SLOT(mySlot()));
}
void MyLayout::mySlot() { /* do something */ }
Any ideas?
You created a parentless button and never showed it. Start by giving it parent (this), so it gets shown together with your widget:
next = new QPushButton("Next Step", this);
Then learn how to use layouts.
What I simply want to do is connect a signal inside a thread to a slot in the main thread to handle UI changes.
This is basically the current state of my thread, nothing fancy but it's just for testing purposes atm:
// synchronizer.h
class Synchronizer : public QObject
{
Q_OBJECT
public:
Synchronizer();
signals:
void newConnection(std::wstring id);
private:
QTimer timer;
private slots:
void synchronize();
}
// synchronizer.cpp
Synchronizer::Synchronizer()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(synchronize()));
timer.start();
}
void Synchronizer::synchronize()
{
emit newConnection(L"test");
}
And here's how my MainWindow looks:
// mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Synchronizer synchronizer;
private slots:
void addConnection(std::wstring id);
}
// mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&synchronizer, SIGNAL(newConnection(std::wstring)),
this, SLOT(addConnection(std::wstring)));
QThread *thread = new QThread;
// The problems starts here?
synchronizer.moveToThread(thread);
thread->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addConnection(std::wstring id)
{
// Add a new connection to QListWidget
ui->connectionList(QString::fromStdWString(id));
}
If I remove there lines:
synchronizer.moveToThread(thread);
thread->start();
everything seems to work as expected, that is a new item is added every second to a QListWidget but as soon as I move the synchronizer object to thread it simply stops working. I'd presume it has something to do with the connect context but I'm not really sure how something like this should be achieved as I'm quite new to Qt.
It seems that the in this case was simply the fact that I am using std::wstring as an argument in the signal without registering the type first and after adding the following line qRegisterMetaType<std::wstring>("std::wstring"); to the code, everything worked as expected.
If I would have read the output console more carefully I would have solved the problem without too much hassle as it was clearly stated that:
QObject::connect: Cannot queue arguments of type 'std::wstring'
So simply speaking, read the compiler output and don't be stupid like me :)
I am trying to connect signals send by buttons in one class with slots of both child and parent classes. Here is an example that reproduces the problem:
ErrorClass.cpp
#include "errorclass.h"
ErrorClass::ErrorClass(QPushButton *button) : QObject()
{
this->button = button;
}
void ErrorClass::makeConnectHappen()
{
connect(button, SIGNAL(pressed()), this, SLOT(exampleSlot()));
}
//SLOT
void ErrorClass::exampleSlot()
{
qDebug() << "ExampleSlot was here";
}
ErrorClassChild.cpp
#include "errorclasschild.h"
ErrorClassChild::ErrorClassChild(QPushButton *button) : ErrorClass(button)
{
makeConnectHappen();
}
void ErrorClassChild::makeConnectHappen()
{
ErrorClass::makeConnectHappen();
connect(button, SIGNAL(released()), this, SLOT(exampleChildSlot()));
}
//SLOT
void ErrorClassChild::exampleChildSlot()
{
qDebug() << "exampleChildSlot was here";
}
and finally standard MainWindow.cpp with a QPushButton
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "errorclasschild.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ErrorClassChild ecc(ui->pushButton);
}
MainWindow::~MainWindow()
{
delete ui;
}
Where makeConnectHappen() is a virtual function in ErrorClass.h which is inherited and expanded by ErrorClassChild. I hope this will be clear.
When I compile and run the program there is Apllication Message
QObject::connect: No such slot ErrorClass::exampleChildSlot() in ../QListWidgetProblem/errorclasschild.cpp:11
QObject::connect: (sender name: 'pushButton')
Now, when I put exampleChildSlot() in the parent as a pure virtual slot the error disappears but no qDebug() message is shown.
How make the connect with parents and children slots at the same time? Or is my idea completaly wrong?
Q_OBJECT is not a property, it is a macro, so it is cannot be inherited. So if you would like to use signals-slots in your class (even if it is derived from class, where Q_OBJECT already is), you should add it to your class. There already was discussion on this topic here , so it could help you.
You should rather use a virtual slot (the Qt doc explicitely say they can be virtual) :
Put these declarations in your base class
class ErrorClass : public QObject{
Q_OBJECT
//...
void makeConnectHappen();
public slots:
virtual void exampleSlot();
}
Then, implement makeConnectHappen() for the base class exactly the way you did, and you'll only have to reimplement the slot in the derived class. Then, when the button will emit the pressed() signal, it will trigger the correct slots depending on the class of the objects you instantiated with this button.