I am trying to run QTimer and have it warn me when timeouting. To do so, I use slot and signal to link the two.
The guy.h:
#ifndef GUY_H
#define GUY_H
#include <QGraphicsItem>
#include <QTimer>
#include <QObject>
class Guy : public QGraphicsItem
{
public:
Guy(int x, int y);
void timerStart();
public slots:
void onTimeOutTimer();
[...]
QTimer *timer;
}
#endif // GUY_H
The guy.cpp:
#include "guy.h"
#include <QTimer>
#include <QObject>
#include <stdio.h>
#include <iostream>
Guy::Guy(int x, int y)
{
timer = new QTimer();
}
void Guy::timerStart()
{
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOutTimer()));
this->timer->setInterval(1000);
this->timer->start();
std::cout << "starting timer" << std::endl;
}
void Guy::onTimeOutTimer()
{
std::cout << "check" << std::endl;
}
But as an ouput, I get this error:
No matching function for call to 'QObject::connect(QTimer*&, const char*, Guy* const, const char*)'
As I undertsand it is that QTimer is no QObject required as first input of the function connect(), but the documentation specifies QTimer inherits from QObject.
I have no clue here.
You will need to inherit from QObject, too, to get this working as signals and slots are availabl for QObjects. QGraphicsItem does not inherit QObject, not even indirectly.
Not only that, you will also need to add the Q_OBJECT macro as follows:
class Guy : public QObject, public QGraphicsItem
{
Q_OBJECT
...
}
or even better because QGraphicsObject inherits QObject and QGraphicsItem.
...
#include <QGraphicsObject>
...
class Guy : public QGraphicsQObject
{
Q_OBJECT
...
}
Also, if you make this change, I suggest to change the QObject::connect to connect as you do not need to indicate the QObject:: scope then.
On a side note, including stdio.h does not seem to make sense here.
Furthermore, allocating the QTimer instance on the heap looks like wasteful to me. It is not only leaking the memory, but also adds additional complexity. Even if you allocate it on the heap, you should pass this as the parent and use the initializer list or C++11 style initialization. Also, if you allocate it on the heap, you could use forward declaration in the header.
If the slot is not used outside the class, you should also make that private.
It is probably also a bad idea to make the timer member public. Hopefully you do not do that.
You can inherit from QGraphicsObject which provides a base class for all graphics items that require signals, slots and inherits QGraphicsItem and QObject. Also add Q_OBJECT macro in your class declaration.
If you use new Qt5 style connects as in
QObject::connect(timer, &QTimer::timeout, this, &Guy::onTimeOutTimer)
The onTimeOutTimer function does not need to be marked as slot, and Guy could stay a non-QObject. Much slimmer and less macros involved.
Related
I am a bit new to Qt C++ and I think there is a small thing I'm missing but can't figure what is it.
I am trying to make a simple Qt C++ application just to get familiar with it, but I face some problem, First, I have the votor class, which is the main application class, and another class which is called recorder, which will be used inside the main votor class. For simplicity, I omitted un-related parts,
Here are the files:
votor.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_votor.h"
#ifndef TSTRECORD_H
#define TSTRECORD_H
#endif
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
#include "recorder.h"
class VOTor : public QMainWindow
{
Q_OBJECT
public:
VOTor(QWidget *parent = Q_NULLPTR);
recorder xs;
private:
Ui::VOTorClass ui;
};
votor.cpp
#include "votor.h"
VOTor::VOTor(QWidget *parent) : QMainWindow(parent), xs(parent)
{
ui.setupUi(this);
//xs = recorder();
}
recorder.h
#pragma once
#include <QDebug>
#include <QObject>
#include <QtCore/qbuffer.h>
#include <QtCore/qiodevice.h>
#include<QtMultimedia/qaudioformat.h>
#include<QtMultimedia/qaudiodeviceinfo.h>
#include<QtMultimedia/qaudioinput.h>
class recorder : public QObject
{
Q_OBJECT
public:
// recorder();
recorder(QObject *parent);
~recorder();
//Some functions related to recording omitted for more focus
private:
//omitted members for simplicity, just some integers, chars and qt objects not related to problem
recorder.cpp
#include "recorder.h"
recorder::recorder(QObject *parent) : QObject(parent)
{
//just initializing the omitted members normally
}
//recorder::recorder() {}
recorder::~recorder()
{
}
as you see, recorder object is a member inside votor class. Now, I need to call recorder constructor to initialize its parent. Now, I knew I can't just make (inside votor.h)
recorder xs(parent);
so,
1- is there a way I can call recorder constructor other than initialization list ?
I want another way as I was more convenient to use recorder xs(..) than initialization list, I feel (just feel) that using initialization list is heavy (not performance-wise but on readability ). I know also I can use dynamic allocation, but I don't want to use it without a good reason for.
2- I have decided to use initialization list to call recorder constructor and pass (Qobject* parent) to recorder. The code is built successfully, but when running, it gives access violation error which I can't figure why...
it gives:
"Access violation reading location 0x7C32F08D."
I think I am missing small thing.. I hope to know what is wrong.
Edit:
as #p-a-o-l-o suggested, the access violation was from the omitted code, So, I am posting it here as I don't know what is the problem in my code:
full version of recoder.h
class recorder : public QObject
{
Q_OBJECT
public:
recorder();
//recorder(QObject *parent);
~recorder();
void record();
void stop();
public slots:
void stateChanged(QAudio::State);
private:
unsigned char state;
QBuffer* voiceBuffer;
QAudioFormat* format;
QAudioDeviceInfo* info;
QAudioInput* audioIn;
unsigned char writeWav(QByteArray*);
};
and the part causes access violation according to debug mode, which is constructor of recorder class
recorder::recorder() : QObject(Q_NULLPTR)
{
state = 0;
voiceBuffer->open(QIODevice::WriteOnly);
format->setSampleRate(8000);
format->setChannelCount(1);
format->setSampleRate(16);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setCodec("audio/pcm");
format->setSampleType(QAudioFormat::SignedInt);
*info = QAudioDeviceInfo::defaultInputDevice();
audioIn = &QAudioInput(*info, *format);
//audioIn->stateChanged.connect(stateChanged);
//connect(audioIn, &QAudioInput::stateChanged, stateChanged);
connect(audioIn, SIGNAL(stateChanged (QAudio::State) ), this, SLOT(stateChanged(QAudio::State)));
}
About question #1: as rightfully suggested in comments, a proper constructor for a QObject-derived class would have a nullptr default argument:
recorder(QObject *parent = Q_NULLPTR);
If you really need that parent object to initialize the other members in construction, you have no alternatives and must call that constructor, somehow.
Otherwise, have a no-arguments constructor and initialize the other members there:
recorder::recorder() : QObject(Q_NULLPTR)
{
//just initializing the omitted members normally
}
Such a constructor will be invoked automatically, no need of initialization list here.
If you still need a parent for the recorder object, give it one in the VOTor constructor:
VOTor::VOTor(QWidget *parent) : QMainWindow(parent)
{
ui.setupUi(this);
xs.setParent(parent);
}
About question #2: as far as I can see from the code you posted, the access violation have nothing to do with Qt parenting and must be related to the (omitted) code inside the recorder constructor.
Just to clear it out: parenting a member object is always safe, since it will go out of scope before ~QObject() gets called, so it will be removed from the children list before ~QObject() could possibly call delete on it.
Taking the OP code as an example, the sequence of destructors is the following:
~VOTor()
~recorder() ---> xs is removed from the children list
.
.
.
~QObject() ---> will call delete on all children, but ws is not in the list anymore
Qt documentation is quite clear about the order of construction/destruction of parents and children: in short, if the child is created on the stack everything will be fine until the child is created after the parent.
But, again, if the child happens to be a member of the parent class, it will be fine as well for the reasons mentioned above (even if its construction actually happens before its parent's).
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.
I am trying to subclass QEditLine so that I can define a new SIGNAL that sends an object identifier. At the moment, I connect a parent signal to a slot in the new class and from that slot I emits a proper new signal with the additional object identifier.
I cannot understand one thing. The problem is I don't know how to define a new signal function itself. I don't know what I should put there. I mean I know its arguments but I don't know what it shpould do as a function. I am doing this for the first time and it may looks very silly ;p but I really stuck there >.<.
Can anybody please provide some clues. It is probably a very easy problem.
Thanks
// myqeditline.h
#ifndef MYQEDITLINE_H
#define MYQEDITLINE_H
#include <QWidget>
#include <QLineEdit>
#include <QString>
class MyQEditLine : public QLineEdit
{
Q_OBJECT
public:
explicit MyQEditLine(const QString& n, QWidget *parent = 0);
protected:
QString name;
signals:
void textChanged(QString textCHanged, QString sender);
protected slots:
public slots:
void myTextChanged(QString textChanged);
};
#endif // MYQEDITLINE_H
// myqeditline.cpp
#include "myqeditline.h"
MyQEditLine::MyQEditLine(const QString &n, QWidget *parent)
: QLineEdit(parent),name(n) {
connect(this,SIGNAL(textChanged(QString)),this,SLOT(myTextChanged(QString)));
}
void MyQEditLine::myTextChanged(QString textChanged) {
emit textChanged(QString textChanged, QString name);
}
I just realised that the answer to my question is on this Qt Project website, in section regarding "Signals", in 4th paragraph. It says: "Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void)."
I'm trying to call my function as a function slot in Qt,But i don't know how to go about it.
it seems the following approach is wrong :
Update:
According to an answer i updated my source code,but still something is apparently wrong with it.Trying to compile this snippet of code causes these errors:
C2515:' no appropriate default constructor is available.'
And
C2665: QObject::connect':none of the 3 overloads could convert all the
arguments.'
respectively in Visual studio 2010.
#include <QtGui/QApplication>
#include <QPushButton>
#include <QObject>
#include <QMessageBox>
class myclass;
int main(int argc,char *argv[])
{
QApplication a(argc,argv);
QPushButton btnshowmessage("show");
myclass *my=new myclass();
QObject::connect(&btnshowmessage,SIGNAL(clicked()),my,SLOT(warningmessage()));
btnshowmessage.show();
return a.exec();
}
//////////////////////////////////////////////////////////////////////////
class myclass: public QObject
{
Q_OBJECT
public:myclass(){}
public slots:
void warningmessage()
{
QMessageBox::warning(0,"Warning","Test Message!",QMessageBox::Ok);
}
};
You use signals and slots to connect one Object's signal to another Object's slot. Every signal or slot should be inside a class which must be also derived from QObject class and contain the Q_OBJECT macro.
So to make your code work, put the slot into some class of yours:
class MySlotClass:public QObject
{
Q_OBJECT
public slots:
void MyFunction()
{
QMessageBox::warning(0,"WarningTest","This is a waring text message",QMessageBox::Ok);
}
}
and connect like this:
MySlotClass m = new MySlotClass();
Qobject::connect(&btnShowaMessageBox,SIGNAL(clicked()), &m ,SLOT(MyFunction()));
Currently Qt does not allow connection of signals to functions that are not declared as slots on some QObject derivative. I believe Qt5 may offer this possibility, but connect will have different syntax to allow this.
basically your slot function must be in a QObject derived class and declared in a
public slots:
section.
Read the documentation on signals/slots.
I want to add a signal to a class that inherits from QGraphicsScene.
signals:
void update(std::vector< std::vector<int> > board);
When I do this, Qt Creator warns me that I forgot the Q_OBJECT macro. But somewhere I read that since QGraphicsScene doesn't inherit from QObject, I shouldn't put it in my class definition. But signals need this macro.
How do I add a signal to a class that doesn't inherit from QObject?
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
Reposting as answer, as requested:
Is update() your signal? did you try to implement the signal yourself? If yes, don't do that, signals are defined by moc.
QGraphicsScene does inherit from QObject. You can consult the documentation.
http://doc.qt.io/qt-5/qgraphicsscene.html
Vtables have something to do with virtual functions. When you have an error like Undefined reference to vtable then it cannot find an implementation for a virtual function (I think). Have you implemented all of your functions? Maybe you used the virtual keyword when you weren't supposed to? Or vice versa?
Also, you say that you want to add a signal, but your code chunk shows a slot? Could you show a little more of your class?
If you have not implemented any class with Q_Object before to the project and you add the Q_OBJECT line yourself, you get the vtable error. If you add another c++ class to the project that inherits from QObject, then you get rid of this problem. You can remove this class you created if you dont need it. I am not sure why this happens, but this is easy way to get rid of the problem. Maybe the creator adds some line to the . pro file when you add a class that inherits from qobject.
Have you implemented your destructor? If not, try changing ~BoardGUI(); to ~BoardGUI(){};
Have you added boardgui.h to the MOC preprocessor's file list? Any class that uses QObject and Signals/Slots needs to be passed through the Meta-Object Compiler so it can generate the actual code behind the signals.
I am unsure if Qt Creator handles this automatically.
You simply have to inherit from QObject yourself.
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QObject, public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
If you are using Qt Creator, you shouldn't have to worry about moc, everything should be handled by Qt Creator.