Just a simple prog to illustrate the issue in a larger one. What I am trying to do is to create a function for signal/slot connection without using any classes. I am new to OOP and don't want to have to do with classes at the moment. So, I am creating a function before the main function and hope this will work... but it doesn't. The prog can be compiled and executed, but I get a notification: Object::connect: No such slot QTextEdit::onClicked(). I anticipate the issue can very easily be solved as it is rather a mistake of expression than of understanding, so thanks in advance for your help! :)
#include <QtGui>
#include <QtCore>
void onClicked (QTextEdit text, QString a)
{
text.setText(a);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget mw;
mw.setWindowTitle("Main Window");
mw.resize(400, 400);
mw.show();
QLabel label ("Enter something:", &mw);
label.setAlignment(Qt::AlignHCenter);
label.show();
QLineEdit line (&mw);
line.show();
QString a = line.text();
QTextEdit text (&mw);
text.show();
QPushButton btn ("Convert", &mw);
QObject::connect(
&btn,
SIGNAL(clicked()),
&text,
SLOT(onClicked()));
btn.show();
QVBoxLayout layout_mw;
layout_mw.addWidget(&label);
layout_mw.addWidget(&line);
layout_mw.addWidget(&btn);
layout_mw.addWidget(&text);
mw.setLayout(&layout_mw);
return app.exec();
}
well,it is true that slots are only available in QObjects BUT you can for sure connect signals to lambdas too :)
so, in this case you can uses the helpful lambda and omit the custom function
void onClicked (QTextEdit text, QString a) :
like
QObject::connect(&btn, &QPushButton::clicked,
[](QTextEdit te, QString s){qDebug() << "am in...";});
You can read in the Qt documentation that:
All classes that inherit from QObject or one of its subclasses (e.g.,
QWidget) can contain signals and slots.
So you can not define slots in main.cpp. You have two options. Either define a class derived from QObject and add your slot there or use Qt 5.* and connect your signal to a lambda using the new syntax for connections.
Related
When I have solved this I am finally done with my prog :D As always, a model of the problem is below. I get the invalid use of 'this' in a non-member function error. It seems to me I have done everything correctly: I have moved the class outside the main function and I have also not forgotten the Q_OBJECT macro... Could anybody please help me here and please mind that I am new to OOP. Thank you!
#include <QtGui>
#include <QtCore>
class MyObject : public QObject
{
Q_OBJECT
public:
QTextEdit text;
QString a;
public slots:
void onClicked() {
text.setText(a);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget mw;
mw.setWindowTitle("Main Window");
mw.resize(400, 400);
mw.show();
QLabel label ("Enter something:", &mw);
label.setAlignment(Qt::AlignHCenter);
label.show();
QLineEdit line (&mw);
line.show();
QString a = line.text();
QTextEdit text (&mw);
text.show();
QPushButton btn ("Convert", &mw);
QObject::connect(
&btn,
SIGNAL(clicked()),
this, /* the compiler keeps complaining... */
SLOT(onClicked()));
btn.show();
QVBoxLayout layout_mw;
layout_mw.addWidget(&label);
layout_mw.addWidget(&line);
layout_mw.addWidget(&btn);
layout_mw.addWidget(&text);
mw.setLayout(&layout_mw);
return app.exec();
}
You can't use this outside a non-static member function.
It seems you want to connect the clicked() signal to the onClicked() function on an instance of MyObject. That means you need to first of all create an instance of the MyObject class. Then use a pointer to that object as the receiver of the signal:
MyObject my_object;
QObject::connect(
&btn,
SIGNAL(clicked()),
&my_object,
SLOT(onClicked()));
Be careful though, because the member variables in MyObject have nothing related with the local variables with the same name in the main function.
From my example code above, my_object.text is a totally different variable from text. The same with my_object.a and a, of course.
As shown in a comment to your question, there are better ways to do what you want, without the need to create the MyObject class.
I'm a very beginnner at C++ /Qt programming. I've made this simple dialog box that check the QLineEdit, if the text entered is "bob" should enable the OK button.
I can't get it to compile successfully, it gives me:
dialog.cpp|31|undefined reference to `Dialogmio::send()'
What am I doing wrong?
This is dialog.h:
//dialog.h
#ifndef DIALOG_H_INCLUDED
#define DIALOG_H_INCLUDED
#include <QDialog>
class QPushButton;
class QLineEdit;
class Dialogmio : public QWidget
{
public:
Dialogmio(QWidget *parent =0);
signals:
void send ();
public slots:
void recip(QString &text);
private:
QLineEdit *linedit;
QPushButton *buttonOK;
};
#endif
This is dialog.cpp:
//dialog.cpp
#include <QtGui>
#include "dialog.h"
Dialogmio::Dialogmio(QWidget *parent)
: QWidget(parent)
{
linedit = new QLineEdit();
buttonOK = new QPushButton("OK");
buttonOK->setEnabled(FALSE);
connect( linedit, SIGNAL( textChanged(const QString &) ), this, SLOT( recip(const QString &) ));
connect (this,SIGNAL( send()), this, SLOT( buttonOK->setEnabled(true)) );
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(linedit);
layout->addWidget(buttonOK);
setLayout(layout);
}
void Dialogmio::recip(QString &text)
{
QString a = linedit->text();
if (a == "bob"){
emit send(); //here it gives me the error
}
}
This is main.cpp:
#include <QApplication>
#include "dialog.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Dialogmio *dialog = new Dialogmio;
dialog->show();
return app.exec();
}
I've inserted the Q_OBJECT macro as suggested, now I get one more errors on line 7:
dialog.cpp|7|undefined reference to `vtable for Dialogmio'|
You start by including the Qt file for QDialog, but then go on to inherit from QWidget. While inheriting from QWidget is not a problem, was your intention to actually inherit from QDialog(?), in which case you should define your class this way: -
class Dialogmio : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget* parent);
private slots:
void aSlotFunction();
}
The signals and slots mechanism are C++ extensions that are unique to Qt and in order for a class to use it, the class must include the Q_OBJECT macro, which adds all the necessary functionality. During the build stages, Qt parses the header and creates the code required for the extensions, including run-time type information, the dynamic property system and of-course the signals and slots.
As you state you're using codeblocks as the IDE, if it doesn't automatically run qmake before building, you'll need to do that whenever you add any signals or slots to a class in order for the moc (meta-object-compiler) to see them.
Another thing is that the call to connect signals and slots is wrong: -
connect (this,SIGNAL( send()), this, SLOT( buttonOK->setEnabled(true)) );
The parameter in the SLOT macro takes a slot function, so you need to create a slot and connect it to the send signal: -
connect(this, SIGNAL(send()), this, SLOT(aSlotFunction());
Inside the aSlotFunction, you can then call the set enabled for the button: -
void Dialogmio::aSlotFunction()
{
buttonOK->setEnabled(true);
}
If you're using Qt 5, there's an easier syntax of handling the connection: -
connect(this, &Dialogmio::send, this, &Dialogmio::aSlotFunction);
As this syntax accepts pointers to the functions that will be called, they don't actually have to be declared as slots to work. In addition, you do not provide the arguments, so if they change, you won't have to update the connect calls too.
What I'm trying to do is launch a program within another program using QProcess and then save the output from the launched program into a QTextEdit of the launcher program. Every time I launch this program I want it to add more text to the QTextEdit. Now I get the program to launch but then after the text is supposed to be written it crashes. Here is the code:
#include <QWidget>
#include <QPushButton>
#include <QTextEdit>
#include <QProcess>
#include <QVBoxLayout>
#include <QApplication>
class Widget : public QWidget
{
Q_OBJECT
QTextEdit* text;
public:
Widget() : text(new QTextEdit) {
QPushButton* addBtn = new QPushButton("Add Module");
text->setReadOnly(true);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(addBtn,0);
layout->addWidget(text);
connect(addBtn,SIGNAL(clicked()),SLOT(launchModule()));
}
Q_SLOT void launchModule() {
QString program = "C:/A2Q2-build-desktop/debug/A2Q1.exe";
QProcess *myProcess = new QProcess(this);
connect(myProcess, SIGNAL(finished(int)), SLOT(finished()));
connect(myProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(finished()));
myProcess->start(program);
}
Q_SLOT void finished() {
QProcess *process = qobject_cast<QProcess*>(sender());
QString out = process->readAllStandardOutput(); // will be empty if the process failed to start
text->append(out);
delete process;
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget w;
w.show();
app.exec();
}
#include "main.moc"
It's crashing because you're deleting the sender object while inside a slot. Instead of delete process, you should
process->deleteLater();
For logging purposes you should be using QPlainTextEdit instead of a QTextEdit. The former is faster. You're prematurely pessimizing by using the latter. Alas, even QPlainTextEdit becomes abysmally slow if you're sending about 100 lines/s (at least on Qt 4.8). If you want a really fast log view, you'll need to use QListWidget, with a caveat, or roll your own.
I have a complete example of how to send to and receive from a process in another answer.
The process is crashing because you're deleting the parent from within the finished slot.
Also, it's probably easier to do something like this:
QObject::connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(getOutput()));
instead of using the finished() slot. But that's more personal preference than anything.
I'm trying to write a simple Qt program which takes text inside a QLineEdit and appends it into a QTextEdit object when the return key is pressed.
Here is the code for my program:
#include <QApplication>
#include <QtGui>
#define WIDTH 640
#define HEIGHT 480
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTextEdit textArea;
textArea.setReadOnly(true);
QLineEdit lineEdit;
QPushButton quit("Quit");
QObject::connect(&quit, SIGNAL(clicked()), qApp, SLOT(quit()));
QHBoxLayout hLayout;
hLayout.addWidget(&lineEdit);
hLayout.addWidget(&quit);
QVBoxLayout vLayout;
vLayout.addWidget(&textArea);
vLayout.addLayout(&hLayout);
QWidget window;
window.setBaseSize(WIDTH, HEIGHT);
window.setLayout(&vLayout);
window.show();
//This is the line I can not get to work
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
return app.exec();
}
Essentially, the problem is connecting the QLineEdit returnPressed() SIGNAL to the QTextEdit append() SLOT. I am hoping someone can point out what is wrong with my code.
Thank you very much in advance for your time.
When you run your program, you should notice on the console the following Qt error output..
Object::connect: No such slot QTextEdit::append(lineEdit.text()) in ..
You would need to qualify the append reference in your call to connect with the QTextEdit variable name textArea.
But that's not going to help much because you can only specify signal and slot method names and parameter types when calling connect so you can't specify lineEdit.text() in there.
Since the append() slot expects a QString, ideally you would want to connect a signal that includes a QString but there is no such signal for QLineEdits.
You pretty much have to write a slot yourself that you can connect to returnPressed() and call textArea.append(lineEdit.text()) from there. You will need to subclass a QObject of some kind to write a slot which would usually mean subclassing QWidget and putting all of your UI building code in its constructor.
You might also notice that your program crashes when you close it. Since Qt likes to manage the destruction of most QObjects itself, it is usually best to allocate all QObject instances on the heap with new. This isn't technically necessary all the time but it is much easier :)
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
returnPressed() doesn't take any arguments, but append(QString) does take one argument; a QString. Thus, if this would work, you would theoretically call append(""), meaning you wouldn't append anything. Using lineEdit.text() wouldn't work either at this place.
I would recommend you to create a class for the widget:
class Widget : public QWidget
{
public:
Widget(QWidget parent = 0);
//Other public functions
private:
//Private functions and variables
public slots:
void boom();
};
Then you can just use
Widget w(0);
w.show();
in your main function.
void boom() would be called by returnPressed(), and it would take lineEdit.text() and append it to the QTextEdit.
I hope this helps.
here is the code it might be helpful.....
#include "hwidget.h"
Hwidget::Hwidget(QWidget *parent) :
QWidget(parent)
{
}
void Hwidget::mainform_init(void)
{
lineeditp = new QLineEdit;
quitp = new QPushButton("&Exit");
hboxlayoutp = new QHBoxLayout;
hboxlayoutp->addWidget(lineeditp);
hboxlayoutp->addWidget(quitp,0,0);
vboxlayoutp = new QVBoxLayout;
texteditp = new QTextEdit;
texteditp->setReadOnly(true);
vboxlayoutp->addWidget(texteditp,0,0);
vboxlayoutp->addLayout(hboxlayoutp);
QWidget *mywin = new QWidget;
mywin->setLayout(vboxlayoutp);
mywin->setWindowTitle("My Sig and Slot");
mywin->show();
lineeditp->setFocus();
}
void Hwidget::mcopy(void)
{
qDebug() <<"i am your copy slot";
texteditp->setText(lineeditp->text());
lineeditp->clear();
}
#include <QApplication>
#include "hwidget.h"
int main (int argc, char *argv[])
{
QApplication app(argc,argv);
Hwidget *hwin = new Hwidget;
hwin->mainform_init();
hwin->connect(hwin->quitp,SIGNAL(pressed()),
qApp,SLOT(quit()));
hwin->connect(hwin->lineeditp,SIGNAL(returnPressed()),
hwin,SLOT(mcopy()));
return app.exec();
return 0;
}
#ifndef HWIDGET_H
#define HWIDGET_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QObject>
#include <QString>
#include <QDebug>
class Hwidget : public QWidget
{
Q_OBJECT
public:
explicit Hwidget(QWidget *parent = 0);
void mainform_init(void);
signals:
public slots:
void mcopy(void);
private:
QHBoxLayout *hboxlayoutp;
QVBoxLayout *vboxlayoutp;
public:
QPushButton *quitp;
QLineEdit *lineeditp;
QTextEdit *texteditp;
};
#endif // HWIDGET_H
I've read several articles about push button events in Qt but none seem to solve my problem. I have a simple GUI built with Qt Designer which only contains one button. The run-time error I get is the following:
Object::connect: No such slot QApplication::FullSizeR() in CameraWindow.h:25
Object::connect: (sender name: 'FullSize')
Object::connect: (receiver name: 'CameraViewer')
FullSizeR() is the function I want called when My button is pushed.
Here's' how main is defined:
int main(int argc, char *argv[]) {
// initialize resources, if needed
// Q_INIT_RESOURCE(resfile);
QApplication app(argc, argv);
CameraWindow cw;
cw.show();
//app.setActiveWindow(&cw);
//cw.getData(); // this paints the window
return app.exec();
}
And this is how CameraWindow is defined:
class CameraWindow : public QDialog{
Q_OBJECT
public:
bool serverConnected;
void getData();
CameraWindow()
{
widget.setupUi(this); //this calls Qt Designer code
//the function bellow produces a run-time error
//access the button via widget.FullSize
connect(widget.FullSize,SIGNAL(clicked()), qApp, SLOT(FullSizeR()));
}
QLabel *imgl;
virtual ~CameraWindow();
protected slots:
void FullSizeR();
private:
Ui::CameraWindow widget;
};
I've properly included QObject and my function definition under 'slots'
This is the definition of FullSizeR:
void CameraWindow::FullSizeR()
{
QMessageBox::information(this,"Button clicked!\n", "Warning");
}
The above doesn't seem to be hard to solve. I know its something simple if I only knew Qt a bit better :-/
Thanks All
connect(widget.FullSize,SIGNAL(clicked()), qApp, SLOT(FullSizeR()));
The error message says it all: qApp doesn't have the slot. You need this:
connect(widget.FullSize, SIGNAL(clicked()), this, SLOT(FullSizeR()));