Qt C++ "new" operation may cause unexpected errors? - c++

There are two UIs in my project, namely, Login and MainWindow.
Now I use signal-slot method to transfer some data of Login to some MainWindow class member variables,and here is some key code:
Login::Login(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
MainWindow *w = new MainWindow;
connect(this,SIGNAL(sendData(QList<QString>)),w,SLOT(receiveData(QList<QString>)));
}
//get data from Login
void MainWindow::receiveData(QList<QString> userList){
userName = userList.at(0);
password = userList.at(1);
QSqlQuery query;
bool b = query.exec(QString("SELECT * FROM user WHERE user_id = '%1' AND password = '%2'").arg(userName).arg(password));
if(b){
query.first();
userType = query.value(1).toString();
qDebug()<<"user_type:"<<userType; //always has value in userType
qDebug()<<"user_id:"<<userName; //always has value in userName
}
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public:
QString userName; //member variables declared here.
QString password;
QString userType;
I tried to connect signal and slot in main function instead of Login constructor:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
...
MainWindow w;
Login l;
connect(&l,SIGNAL(sendData(QList<QString>)),&w,SLOT(receiveData(QList<QString>)));
if(l.exec() == QDialog::Accepted){
w.show();
}
return a.exec();
}
but with the following bug information:
D:\QtProject\TMS\main.cpp:416: error: invalid conversion from 'Login*' to 'SOCKET {aka unsigned int}' [-fpermissive]
connect(&l,SIGNAL(sendData(QList<QString>)),&w,SLOT(receiveData(QList<QString>)));
D:\QtProject\TMS\main.cpp:416: error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'
Now, What really confuses me is that why the value of userName or userType is empty(which has been populated with data in function receiveData()) when I use them in other MainWindow functions.
I have tried searching on net for a long time but without any result working.
If you can give me any idea, I will appreciate it a lot.
Thanks in advance.

What you tried in your main() function is the right way to go. What you need to change:
connect() in main() must be QObject::connect() – it’s a static member function of the QObject class. If you call it from inside the implementation of a class that derives from QObject you don’t need to qualify the call because the compiler picks the correct function by default. Not so in main(). From your compiler errors you can deduce that the compiler picked a completely unrelated connect() function.
The constructor of Login instantiates an additional MainWindow object and connects to its slot. That’s not what you want. You want to use the existing main window object – w. Delete the new and connect lines from Login::Login(). They are redundant.
In main() move return a.exec() into the if. Otherwise when the login dialog is not accepted your program does not show the main window, but it never terminates either. QApplication::exec() starts the main GUI event loop. In a very tiny nutshell: That is what keeps your main window alive until the user decides to close the program. If you start the loop without showing the main window then there is no way to end the program except for killing the process. You want your main() to look like this:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
Login loginDialog;
// ... connect and any other setup stuff
if (loginDialog.exec() == QDialog::Accepted) {
mainWin.show();
return app.exec();
}
return 1;
}
P.S. Avoid one-letter variable names. Without useful names you programs become unreadable extremely quickly.

The error message indicates the source of the problem:
error: cannot convert 'const char*' to 'const sockaddr*' for argument '2' to 'int connect(SOCKET, const sockaddr*, int)'
You are calling a completely different connect() function and not QObject::connect() (notice the use of QObject in front of the connect() - it's very important since it's a static method). The sockaddr indicates that you are trying to use the
int connect(int socket, const struct sockaddr *address, size_t address_len);
from #include <sys/socket.h>, which is clearly incorrect. Perhaps you have added a header that replaces the QObject::connect() when you do an autocomplete. I would suggest that you carefully check what your editor gives you as a suggestion and also check for the socket.h header somewhere.
I was able to reproduce an incorrect autocomplete by just adding the #include <sys/socket.h> to a small Qt application and attempting to do an autocomplete inside Qt Creator inside the same source file:
Last but not least you really need to take care of the rest of the code. In addition I would also suggest using the new signal-slot syntax when creating a connection. It allows proper typechecking (the old SIGNAL() and SLOT() do not offer that since you just pass a string as argument).

Related

How to fix QObject::connect: No such slot.. when connecting a sender to a slot both in the same class [duplicate]

This question already has answers here:
QObject connection function
(3 answers)
Closed 3 years ago.
I am writing a programm, that creates a QLineEdit that only accepts digits and should, when it rejects an input that is not a digit, turn the background to some abitrary color. If the input is accpeted it will turn the background white again. Now I need to connect the inputRejected and textEdited events of the QLineEdit to randomcolor() and white() respectively, but the connect is making me trouble and i do not know how to fix it.
This is the first time I'm working with the connect and i slugged through many forums alreay trying out the different Syntax i found there.
#include <QtWidgets>
class OnlyNumbers : QLineEdit {
public:
static int spawn(int argc, char *argv[]){
QApplication app(argc, argv);
OnlyNumbers P;
return app.exec();
}
OnlyNumbers() : QLineEdit() {
this->setValidator(new QIntValidator());
QObject::connect(this, SIGNAL(inputRejected()), this, SLOT(randomcolor()));
QObject::connect(this, SIGNAL(&QLineEdit::textEdited(const QString)), this, SLOT(&OnlyNumbers::white()));
QRegExp rx("[0-9]*"); QValidator *validator = new QRegExpValidator(rx, this);
this->setValidator(validator);
this->show();
}
public slots:
void randomcolor(){
this->setStyleSheet("QLineEdit { background: rgb(std::rand()%256, rand()%256, rand()%256); selection-background-color: rgb(rand()%256, rand()%256, rand()%256); }");
}
void white(){
this->setStyleSheet("QLineEdit { background: rgb(255, 255, 255); selection-background-color: rgb(233, 99, 0); }");
}
};
int main(int argc, char *argv[])
{
return OnlyNumbers::spawn(argc, argv);
}
QObject::connect: No such slot QLineEdit::randomcolor()
QObject::connect: No such signal QLineEdit::&QLineEdit::textEdited(const QString)
These are the errors i get, and i don't know what to do with them, because for em the two are existant. Sadly I cannot describe my problem better, because i don't know more.
SOLVED: The Problem was, that i didn't seperate calls definition and declaration in onlynumbers.h and onlynumbers.cpp. Also i cannot put std::rand()%256 in the string i need to split the string and concatonate it with all the numbers converted to a qstring. :D Thanks for the help. You gave me the motivation to keep googeling.
You forgot Q_OBJECT for your class. For example:
class OnlyNumbers : QLineEdit {
Q_OBJECT
...
See the documentation on QObject:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties.
Without the macro the meta compiler simply will not generate the information needed for the slots/signals declared in your class.
Also, after Q_OBJECT has been added you should rerun qmake on your project since qmake actually generates the calls to moc in the makefile. This is explained by the documentation of the Meta-Object Compiler (moc):
Whenever qmake is run, it parses the project's header files and generates make rules to invoke moc for those files that contain a Q_OBJECT macro.
Also as mentioned in the comments - the SIGNAL/SLOT macros are the old string based implementation, and there are many benefits to switch to the new compile time checked connect - see New Signal Slot Syntax and Differences between String-Based and Functor-Based Connections.

Use UI elements from static function

I am building a qt application in which i am have to access ui elements. but i am getting error as
invalid use of member 'foo::ui' in static member function
The code is big so cant add here.
Declaration of ui
private:
Ui::foo *ui;
Initialization in Constructor
foo::foo(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::foo)
{
ui->setupUi(this);
}
Accessing in static function where it is giving error.
ui->fp->setText("Some Text");
Static function declaration.
static I eventCallback(PVOID i_pv_context,
T_xyz i_i_command,
PVOID i_pv_param);
main code
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
BarrierInterfaceModule w;
w.show();
return a.exec();
}
I have looked on Internet but did not get solution. please let me know if there is a way around.let me know if you need any more info Thanks in advance
I'm aware of two possible solutions:
Use a singleton class for foo. This method only works if you need only one instantiation of foo, which is probably the case because it is a QMainWindow. Now, you can set the text as follows: getInstance()->ui->fp->setText("Some Text");
Often callback function are able to pass a pointer to user supplied data, but this depends on the library you are using.

Is it possible to connect a slot or regular function from one class to a slot or regular function from another class? (QT)

To be specific to my problem I've been trying to connect a a slot from one class to a regular function of another class. I'm trying to do this so I can close the ui of one the main window from a dialog window. I tried everything I could possibly think of but it seems like every time I think of something to try the Qt compiler shuts me down by throwing some error or not working for no apparent reason such as when I did this
function(Ui::MainWindow *ui)
{
copy = ui; // copy is a pointer declared as Ui::MainWindow *copy in the dialog class
}
I tried this so I could close the main window from the copy pointer in the dialog class and although it compiled for that, it wouldn't compile when I tried to use it in another function of that class even though it was a class variable. After that I then realized that I should be able to connect the two functions from the main function. I wrote this
QObject::connect(&i, SIGNAL(on_passInput_returnPressed()), &w, SLOT(initalizer()));
The above compiles but when debugging I discovered it never gets executed and not sure why despite the fact that the SIGNAL on_passInput_returnPressed() is actually declared as slot in the class header. If that is the reason why it doesn't get executed how do I connect the slot from the dialog class to a regular function from the MainWindow class? There must be a way because I spent a day practically thinking about this non-stop and can't think of any other way given the nature of object scopes (in OOP) on top of the fact that the pointer thing I thought of didn't work.
Also I just now recreated the error from the pointer thing described above here it is.
error: invalid use of incomplete type 'class Ui::MainWindow'
copy->close();
^
Again this error is referring to trying to access the close function via the copy pointer from another function in the same class as the pointer assignment that worked in the other function. The copy pointer is declared as follows in the class header. Also in case you're wondering, yes, the pointer assignment written above does get executed. I checked via debugging.
private:
Ui::InitalPrompt *ui;
Ui::MainWindow *copy;
If you need more info just let me know what you need and I'll edit this post with it. I've obsessively tried so much I can think so much so that I've given up without further help due to how unforgiving Qt has been with me.
Also if there's a way of doing what I'm trying to do with the new Qt5 syntax of the connect function can you please give me the exact thing to type because despite looking into that new syntax myself I can't get it to compile for the life of me. (and yes I'm using Qt5) That's why the code above is written as old-fashion syntax.
Added the following as suggested to do so in a reply which is the class of the copy pointer.
#include "initalprompt.h"
#include "ui_initalprompt.h"
#include "mainwindow.h"
#include <QLineEdit>
#include <QCloseEvent>
#include <QMessageBox>
InitalPrompt::InitalPrompt(QWidget *parent) :
QDialog(parent),
ui(new Ui::InitalPrompt)
{
ui->setupUi(this);
}
InitalPrompt::~InitalPrompt()
{
delete ui;
}
void InitalPrompt::on_passInput_returnPressed()
{
pass = ui->passInput->text();
}
void InitalPrompt::reject()
{
QMessageBox::StandardButton resBtn = QMessageBox::Yes;
bool changes = false;
if (changes) {
resBtn = QMessageBox::question( this, "APP_NAME",
tr("Are you sure?\n"),
QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
}
if (resBtn == QMessageBox::Yes) {
QDialog::reject();
}
// the only issue is with the statment below don't know why
copy->close();
}
void InitalPrompt::catcher(Ui::MainWindow *ui)
{
copy = ui;
}
"Invalid use of incomplete type" means the compiler does not (yet) have a definition for the class when it reaches that line. In the header file that contains your copy pointer, include a forward declaration above the class declaration (the file would look something liek this):
#ifndef BLAH_BLAH_H
#define BLAH_BLAH_H
/*All of your normal #includes here*/
namespace Ui {
class InitialPrompt;
class MainWindow; //Note the forward declaration here
}
#include "mainwindow.h"
class BlahBlah
{
/*Class stuff here*/
private:
Ui::InitalPrompt *ui;
Ui::MainWindow *copy;
};
#endif //BLAH_BLAH_H
If you post the entirety of your class file that has the *copy, we can look further into it.
No, it is not possible. You can either:
call w->initalizer() directly from on_passInput_returnPressed() or
define a signal signal_on_passInput_returnPressed() in your ui class and emit that signal from on_passInput_returnPressed(). Then
QObject::connect(&i, SIGNAL(signal_on_passInput_returnPressed()), &w, SLOT(initalizer()));
should work.
For example:
class Whatever :
public QObject {
Q_OBJECT
void on_passInput_returnPressed();
signals:
void signal_on_passInput_returnPressed();
};
void Whatever::on_passInput_returnPressed() {
emit signal_on_passInput_returnPressed();
}

How to find out from the slot which signal has called this slot?

I mean if I have many different signals which are connected to the same slot. I saw this question but can't understand the link in the answer. Can you give me simple example?
I think you can use this method:
[protected] int QObject::​senderSignalIndex() const
From Qt documentation:
Returns the meta-method index of the signal that called the currently executing slot, which is a member of the class returned by sender(). If called outside of a slot activated by a signal, -1 is returned.
For signals with default parameters, this function will always return the index with all parameters, regardless of which was used with connect(). For example, the signal destroyed(QObject *obj = 0) will have two different indexes (with and without the parameter), but this function will always return the index with a parameter. This does not apply when overloading signals with different parameters.
Warning: This function violates the object-oriented principle of modularity. However, getting access to the signal index might be useful when many signals are connected to a single slot.
Warning: The return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
This function was introduced in Qt 4.8.
Here is a small example that I created for you that demonstrates how it works:
#include <QTimer>
#include <QMetaObject>
#include <QMetaMethod>
#include <QCoreApplication>
#include <QDebug>
#include <QObject>
class Foo : public QObject
{
Q_OBJECT
public slots:
void mySlot() {
QMetaMethod metaMethod = sender()->metaObject()->method(senderSignalIndex());
qDebug() << metaMethod.name();
qDebug() << metaMethod.methodSignature();
qApp->quit();
}
};
#include "main.moc"
int main(int argc, char **argv)
{
QCoreApplication coreApplication(argc, argv);
QTimer timer;
Foo foo;
QObject::connect(&timer, &QTimer::timeout, &foo, &Foo::mySlot);
timer.setSingleShot(true);
timer.start(1000);
return coreApplication.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
"timeout"
"timeout()"

No matching function for QObject::connect

I'm writing a program that send an UDP frame every 10 mS. Here's how my program is supposed to work :
I've got a client class :
//Constructor
clientSupervision::clientSupervision()
{
}
void clientSupervision::sendDataUDP(){
//Create a frame and send it
...
}
void clientSupervision::sendDataUDPTimer(int timer){
QTimer *tempsEnvoieTrameSupervision = new QTimer();//Create a timer
tempsEnvoieTrameSupervision->setInterval(timer);//Set the interval
//Mise en place des connections
QObject::connect (tempsEnvoieTrameSupervision,SIGNAL (timeout()),this, SLOT (envoiTrameSupervision())); //Connect the timer to the function
tempsEnvoieTrameSupervision->start();// Start the timer
}
//Call sendDataUDP
void clientSupervision::envoiTrameSupervision(){
std::cout << "Envoi de la trame de supervision";
sendDataUDP();
}
My header file of clienSupervision.h :
#ifndef CLIENTSUPERVISION_H
#define CLIENTSUPERVISION_H
#include <winsock2.h> // pour les fonctions socket
#include <cstdio> // Pour les Sprintf
#include "StructureSupervision.h"
#include "utilitaireudp.h"
#include <QTimer>
#include <QObject>
#include <iostream>
class clientSupervision
{
Q_OBJECT
public:
clientSupervision();
void sendDataUDP();
void sendDataUDPTimer(int timer);
public slots:
void envoiTrameSupervision();
};
#endif // CLIENTSUPERVISION_H
Then I use this in my main :
int main(int argc, char *argv[])
{
clientSupervision c;
c.sendDataUDPTimer(10);
QCoreApplication a(argc, argv);
return a.exec();
}
I've got the error :
no matching function for call to 'QObject::connect(QTimer*&, const char*, clientSupervision* const, const char*)
I don't understand why the connect function can't find a matching function.
What should I change?
There can be several reasons for the issue in general:
You do not inherit QObject.
You do not have the Q_OBJECT macro in your class.
You do not define the method as slot in your header file where the class is declared.
Your issue is the first which can be seen here:
class clientSupervision
You should change your code to:
class clientSupervision : public QObject
// ^^^^^^^^^^^^^^^^
Of course, the constructor implementation and signature would need to change, too, as follows:
explicit clientSupervision(QObject *parent = Q_NULL_PTR) : QObject(parent) { ... }
In addition, you seem to leak your QTimer instance as it does not get the parent as a parameter to the constructor.
Furthermore, the QObject:: scope is needless in your code as your class ought to inherit QObject directly or indirectly either way.
Even more, I would highly encourage you to utilize the new signal-slot syntax.
Another possible cause of this error is trying to connect to a slot which is overloaded. For example, this well cause the same error
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
&QWidget::update,
Qt::QueuedConnection);
But not if you explicitely cast:
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
static_cast<void (QWidget::*)()>(&QWidget::update),
Qt::QueuedConnection);
Here's another one that snuck up on me: The class of the slot object had been forward declared in the header, but not defined in the implementation by including its header.
If none of the answers above worked, check if you have assigned correct object to the signals and the slots. You will get this error when the signals and slots are valid and refer to one object but the object assigned to that signal and slot is different.