Consider the following scenario:
I have integrated QT in my c++ app. I wish to enter Data from a GUI rather than terminal. For this purpose, i created a function for QT. My dialog window consists of three text lines and a button, upon the click of which i want to call a particular method of some other class. I am having trouble with SINGAL and SLOTS.
Consider the following files:
main.cpp has
a.h -> a.cpp
a.cpp has
a.h
myslots.h
and the QT app method inside a.cpp as:
int A::inputData(){
...
A a
myslots ms;
QObject::connect(button, SIGNAL(clicked()), &ms, SLOT(clickButton(&a)));
....
}
myslots.h has:
a.h and inherited from A as:
class myslots : public QObject, public A {
Q_OBJECT
public slots:
void clickButton(A &a);
signals:
void buttonClicked();
};
myslots.cpp has:
myslots.h and the following method
void myslots::clickButton(A &a) {
cout <<"I am called successfully"<<endl;
a.perform_action(-2.3, 4.5, 4.4);
emit this->buttonClicked();
}
I get the following error:
QObject::connect: No such slot myslots::clickButton(&a)
Actually i want to pass three double values from three textlines say: 1.3, 2.4, 4.5 to a function by clicking the button, where the function to be called is in another class that is inherited by myslots.h and accepts three parameters.
Currently am just testing whether i am able to call the function properly or not but am not.
Thanks
This will not work. In SIGNAL or SLOT must be a type, not an object or its reference. I mean this
QObject::connect(button, SIGNAL(clicked()), &ms, SLOT(clickButton(&a)));
must be
QObject::connect(button, SIGNAL(clicked()), &ms, SLOT(clickButton(A)));
But then you must catch another error - where is A in your SIGNAL? Why do you use A in the signal at all?
Some issues:
1 - When tou derive from QObject, always put the Q_OBJECT macro in the private section of your class, do something like
class MyClass: public QObject {
Q_OBJECT
public:
...
this Q_OBJECT macro is important for classes that have signals and slots.
2 - In the connect statement you have to tell Qt the type of the parameters, not the names you use, that is, if you slot function is
void myslots::clickButton(A &a);
The you connect to it with
connect(emiterObject, SIGNAL(someSignal(A)), targetObject, SLOT(clickButton(A)));
Since Qt 5.x you are able to use a lambda expression as slot.
So your connect statement should look like:
QObject::connect(button, &QPushButton::clicked, [a, ms](){ms.clickButton(&a);});
But, using a and ms as local variables is not realy a good thing, as stated by Karsten Koop.
The error is in your :
QObject::connect(button, SIGNAL(clicked()), &ms, SLOT(clickButton(&a)));
it has to be:
QObject::connect(button, SIGNAL(clicked(A)), &ms, SLOT(clickButton(A)));
the type that you send in the SIGNAL must be in SLOT that receives that type.
Related
I have two classes that are interacting with each other, let's call them for the sake of simplicity ClassA and ClassB. In ClassA, I would like to emit a signal when a specific QGroupBox is shown that triggers a slot in ClassB to set the given channel's checkbox.
I have a code that consists of several thousand lines, so I included only the most relevant parts.
ClassA header
private:
QGroupbox* m_Channel1GroupBox;
void setup();
signals:
void setCheckBox(int, bool);
ClassA source
void ClassA::setup()
{
m_Channel1GroupBox = new QGroupBox("Channel 1", this);
connect(m_Channel1GroupBox, &QGroupBox::show, [this]()
{
emit setCheckBox(1, true);
});
}
ClassB header
private:
QCheckBox* m_Channel1CheckBox;
public slots:
void setCheckBox(int, bool);
ClassB source
void ClassB::setCheckBox(int channel, bool check)
{
if (channel == 1)
{
m_Channel1CheckBox->setChecked(check);
}
}
Main.cpp
connect(m_ClassA, &ClassA::setCheckBox, m_ClassB, &ClassB::setCheckBox);
The lambda expression compiles, but unfortunately it doesn't do what it is expected to do, which is whenever m_Channel1GroupBox->show() is called, then tick the checkbox of Channel1. Actually this block of code never executes, which would emit setCheckBox.
Please note that the setCheckBox function works perfectly when called in another function of ClassA and it checks or unchecks the desired channel in ClassB. This is possible using another connect in the Main.cpp file where the object instances are created.
You will need to subclass QGroupBox to achieve the functionality you require.
Override QWidget::showEvent(QShowEvent*) in your QGroupBox subclass and do the work there.
Please see the documentation for QWidget.
run the code and you will see that the
QGroupBox has no signal to emit called show...
show is actually a slot
QObject::connect: signal not found in QGroupBox
But...
if you are calling show per hand, then emit the signal right after that...
I need to connect a QPushButton (startListeningPushButton) from my StartWindow to a slot in my MainController. I still have a few questions:
Should I make a pointer of Ui::startWidget ui, because by default Qt created it as a normal variable?
Is getStartWindow() the right way to get the StartWindow from ViewController?
What would be the right way to get startListeningPushButton from StartWindow (is my getter right)?
This is my code:
MainController.cpp:
MainController::MainController()
{
connect(m_viewController.getStartWindow()->getStartListeningPushButton, &QPushButton::clicked, this, &MainController::bla)
}
ViewController.cpp:
StartWindow* ViewController::getStartWindow()
{
return &startWindow;
}
StartWindow.cpp:
QPushButton* StartWindow::getStartListeningPushButton()
{
return ui->fStartListeningPushButton;
}
StartWindow.h:
#ifndef STARTWINDOW_H
#define STARTWINDOW_H
#include "ui_startwindow.h"
class StartWindow : public QWidget
{
Q_OBJECT
public:
StartWindow(QWidget *parent = 0);
~StartWindow();
QPushButton* getStartListeningPushButton();
private:
Ui::startWidget *ui;
};
#endif // STARTWINDOW_H
If you are using Qt Designer and Qt IDE generated such code that it's object not a pointer I don't think that you should make it pointer.
Yeah, returning a pointer to QWidget (StartWindow in your case) is pretty OK.
Your getter is OK.
Seems like you have mistype in your connect, it should look like this:
QObject::connect(m_viewController.getStartWindow()->getStartListeningPushButton(), SIGNAL(clicked()),
this, SLOT(bla()));
It's unclear if you have and then what is your problem.
The only thing I doubt would work is the first parameter of your call to connect:
m_viewController.getStartWindow()->getStartListeningPushButton should actually be m_viewController.getStartWindow()->getStartListeningPushButton() (to have the function be called so that you get the pointer to expected QPushButton and pass it to the connect function).
In the connect function:
First and third parameter must be of type QObject*. So this can either be this pointer (if current class is derived from QObject), or any class attribute of type QObject* (ui->fStartListeningPushButton) or a function call returning QObject* (m_viewController.getStartWindow()->getStartListeningPushButton()). But m_viewController.getStartWindow()->getStartListeningPushButton (with no ()) does not make sense here).
Second parameter must be a signal (declared in header file class using signals: keyword. You don't need implement any code here, you just declare the signal and Qt MOC mechanism implements it silently). Valid syntax for this parameter is &QPushButton::clicked or SIGNAL(clicked()) (Qt4 syntax, still valid in Qt5).
Fourth parameter must be a slot (declared in header file class using slots: keyword, and implemented by you). Valid syntax for this parameter is &MainController::bla or SLOT(bla()) (Qt4 syntax, still valid in Qt5).
There's actually a fifth optional parameter to use when you'll start dealing with threads.
I have a problem creating a QPushButton and linking its signal to my slots. First, I created a class with the slot:
class A : public QWidget{
public slots:
void handleButton();
};
There is my handleButton function in the .cpp
void A::handleButton(int row, int col){
m_button->setText("Example");
// resize button
m_button->resize(100,100);
}
Then I want to connect the button.
QObject::connect(m_button, SIGNAL(clicked()), qApp, SLOT(handleButton()));
But I got an error when I start the application:
"No such slot"
Make sure that qApp is an object of class A (i.e. where your slot is defined).
That said, the signatures are wrong: a signal links to a slot only if the signature match
http://qt-project.org/doc/qt-4.8/signalsandslots.html
The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.
And your slot hasn't the right signature:
http://qt-project.org/doc/qt-4.8/qabstractbutton.html#clicked
void QAbstractButton::clicked ( bool checked = false ) [signal]
You have a few errors in this code, if you define "void handlebutton()" then you must implement void handlebutton() NOT void handlebutton(inx x, int y) this code should not even compile.
More: in QT you CAN ONLY connect SIGNALS and SLOTS with the same parameters so you can connect SIGNAL(clicked()) with SLOT(handlebutton()) but not SIGNAL(clicked() with SLOT(handleButton(int, int)).
Another problem is that connect is executed at runtime so You must compile and run before Qt can show you the error.
So a possible solution is:
define and implement the slot void handlebutton() and connect that to the signal clicked(), then define another method handleButton (int x, int y) that you will call from inside handleButton().
I really hope that makes sense to you.
Your class definition should look like :
class A : public QWidget
{
Q_OBJECT
public slots:
void handleButton(int, int);
};
And you should connect it like:
QObject::connect(m_button, SIGNAL(clicked()),qApp, SLOT(handleButton(int a, int b)));
where a and b are variables for row and column.
This should work. Try understanding basic C++. :)
I know there are many many questions that are just the same, but none of them helps me:
class Form1 : public QMainWindow {
Q_OBJECT
public:
Form1();
virtual ~Form1();
public slots:
void langChange(const char* lang_label);
private:
Ui::Form1 widget;
void setLangStrings();
};
From1 constructor:
Form1::Form1() {
widget.setupUi(this);
connect(widget.btnL0, SIGNAL(clicked(bool)), this, SLOT(langChange("en")));
connect(widget.btnL1, SIGNAL(clicked(bool)), this, SLOT(langChange("fr")));
setLangStrings();
}
And I also have this langChange function implemented:
void Form1::langChange(const char* lang_label)
{
GL_LANG = lang_label;
setLangStrings();
}
I get this stupid error when the connect function is called:
No such slot Form1::langChange("sl") in Form1.cpp:15
I'm using NetBeans with QDesigner for the UI. I must say this QT4 is very difficult to learn.
You simply can't connect SIGNAL with bool as argument to SLOT with const char* as argument. To do this kind of stuff you have to use QSignalMapper. You have an example how to use it inside documentation. In your case, it's very simple, so you should handle it easly.
The SLOT function must have the same signature than the SIGNAL function
Edit: From the official Qt documentation (http://qt-project.org/doc/qt-4.8/signalsandslots.html):
The signature of a signal must match the signature of the receiving
slot. (In fact a slot may have a shorter signature than the signal it
receives because it can ignore extra arguments.)
I'm relatively new to Qt; I'm writing a small program and I don't want to get into making my own classes for each widget and such. So far I haven't had many difficulties, but I'm slightly confused about signals and slots. I want to make a signal that triggers when a user types into a text box (QLineEdit) and presses enter. I would prefer the slot to be a function that accepts the text inputted by the user.
So far I've come up with this:
textBox.connect(&textBox,SIGNAL(textBox.returnPressed()),/*What to put here?*/,processText(/*Here?*/))
I apologize if this piece of code is terribly wrong; as I said I'm relatively new to Qt.
Help would be very much appreciated.
Signals and slots must be methods of a QObject (/QObject subclass). You can't use free functions as slots. "Minimal OOP" here probably would mean QObject singleton(s) containing the slots.
Also a signal with signature (A, B, C) can only be connected to slots with signatures (), (A), (A, B), (A, B, C), i.e. one can discard/ignore trailing arguments. A slot cannot have more/other arguments than the signal, nor can you bind slot arguments to a certain value when connecting (Where QSignalMapper covers the most common use case I think).
Sadly, I don't think there is a way to achieve this without inheritance - if you want the text to go with the signal or some custom handling to be done in the slot that is called.
If not, you can just use the "returnPressed" signal emitted from the QLineEdit and some pre-existing slot I couldn't possibly know.
Here's my solution using inheritance.
To make your own slot, you need to make an inherited class. Inherit it from Qobject, directly or indirectly.
//myClass.h
#ifndef myclass_h_
#define myclass_h_
#include <QObject>
class myClass: public QObject
{
// important
Q_OBJECT;
....
public slots:
void takeText(QString p_value);
};
#endif
And to get a signal like that from a QLineEdit, you need something custom as well
//myLineEdit.h
#ifndef mylineedit_h_
#define mylineedit_h_
#include <QLineEdit>
class myLineEdit: public QLineEdit
{
// important
Q_OBJECT;
....
public slots:
void handleReturnPressed();
signals:
void newText(QString p_value);
};
#endif
And then do these
myLineEdit::myLineEdit()
{
connect(this, returnPressed(),
this, handleReturnPressed());
}
void myLineEdit::handleReturnPressed()
{
emit(newText(text());
}
After this, create a myClass object, and connect the signal to it.
myClass * thing = new myClass();
myLineEdit* lineEdit = new myLineEdit();
connect(lineEdit, SIGNAL(newText(QString),
things, SLOT(takeText(QString));