how to stop the Qtimer upon a condition - c++

when i executing this Qtimer it says "invalid use of 'this' in non-member function"
QTimer *timerStart( )
{
QTimer* timer = new QTimer( );
Ball *b = new Ball();
QObject::connect(timer,SIGNAL(timeout()),b,SLOT(move()));
//timer->start( timeMillisecond );
timer->start(15);
return timer;
}
my ball.h file
class Ball: public QObject, public QGraphicsRectItem{
Q_OBJECT
public:
// constructors
Ball(QGraphicsItem* parent=NULL);
// public methods
double getCenterX();
public slots:
// public slots
void move();
private:
// private attributes
double xVelocity;
double yVelocity;
int counter = 0;
QTimer timerStart( );
// private methods
void stop();
void resetState();
void reverseVelocityIfOutOfBounds();
void handlePaddleCollision();
void handleBlockCollision();
};
#endif // BALL_H
the move() function is in the same class. what i want to do is stop the returned timer upon a if condition is satisfied.
when i issue this code in Ball::Ball constructor in Cpp it works fine. the ball is moving.
QTimer* timer = new QTimer();
timer->setInterval(4000);
connect(timer,SIGNAL(timeout()),this,SLOT(move()));
timer->start(15);
but when i add Qtimer *timerStart beyond the Ball::Ball constructor, iT doesnt work

Declare the QTimer as a member in you class
h file:
class Ball: public QObject, public QGraphicsRectItem{
{
Q_OBJECT
public:
// constructor
Ball(QGraphicsItem* parent=Q_NULLPTR);
// control your timer
void start();
void stop();
...
private:
QTimer * m_poTimer;
}
Initiate the timer object in your constractor
cpp file:
Ball::Ball(QGraphicsItem* parent) :
QGraphicsItem(parent)
{
m_poTimer = new QTimer(this); // add this as a parent to control the timer resource
m_poTimer->setInterval(4000);
connect(m_poTimer,SIGNAL(timeout()),this,SLOT(move()));
}
void Ball::start()
{
// start timer
m_poTimer->start();
}
void Ball::stop()
{
// stop timer
m_poTimer->stop();
}

Related

Bypassing Qt signaling to avoid class-to-class signaling

I'm trying to figure out how I could work with Qt signals in a little bit different way.
I have a working example of such:
Game::Game(QObject *parent)
: QObject{parent}
, m_timer{nullptr}
{
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &Game::run);
m_timer->setinterval(300);
m_timer->start();
}
Above signaling works fine and calls the Game::run regularly as desired. Now I am trying to replicate this with this bypass (for the sake of learning and it could be useful for more complicated moments especially in unit testing)
Abstract class:
class ISignalHandler
{
public:
virtual void onTimeout() = 0;
protected:
virtual ~ISignalHandler() = default;
};
and another class MyTimer.cpp:
MyTimer::MyTimer(QTimer *parent)
: QTimer{parent}
{
m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, this, &MyTimer::onTimeout);
}
MyTimer::~MyTimer()
{
delete m_timer;
m_timer = nullptr;
}
void MyTimer::registerTimerSignal(ISignalHandler* callback)
{
m_callback = callback;
}
void MyTimer::onTimeout()
{
if (m_callback != nullptr)
{
m_callback->onTimeout();
}
}
and finally Game class:
//header:
class Game : public QObject, public ISignalHandler
{
Q_OBJECT
public:
explicit Game(QObject *parent = nullptr);
~Game();
//cpp:
Game::Game(QObject *parent)
: QObject{parent}
, m_timer{nullptr}
{
m_timer = new MyTimer();
m_timer->registerTimerSignal(this);
m_timer->setinterval(300);
m_timer->start();
}
void Game::onTimeout()
{
run();
}
I expected that the MyTimer class will repeat within itself, and the signal will be handled to Game class so ::run will be continuously called. Where is a mistake here?

QOpenGLWidget move context to another thread crash

I have this simple example and this program crashed when I tried to call context()->moveToThread(render_thread_);. Can anyone help?
class FrameRenderer: public QThread
{
Q_OBJECT
public:
FrameRenderer(QGLCanvas *parent):m_parent(parent), QThread(){}
void run() Q_DECL_OVERRIDE;
QGLCanvas *m_parent;
};
class QGLCanvas : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
QGLCanvas(QWidget* parent = NULL);
~QGLCanvas();
virtual void initializeGL();
virtual void paintGL();
virtual void resizeGL(int width, int height);
void DrawThreadEntry();
FrameRenderer* render_thread_;
};
void FrameRenderer::run()
{
m_parent->DrawThreadEntry();
}
QGLCanvas::QGLCanvas(QWidget* parent)
: QOpenGLWidget(parent)
{
render_thread_ = new FrameRenderer(this);
doneCurrent();
context()->moveToThread(render_thread_);
render_thread_->start();
}
void QGLCanvas::DrawThreadEntry()
{
while(true)
{
makeCurrent();
QOpenGLFunctions f;
f.initializeOpenGLFunctions();
f.glClearColor(1.0, 1.0, 1.0, 1.0);
f.glFinish();
doneCurrent();
emit update();
}
}
I don't know if it's the solution but i got a similar problem on iOS, the context was available but after a short period of time.
You can try to add a timmer and delay your call to OpenGL
.h
slots:
void update();
.cpp
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
If it's working maybe you should try look if you can do your move ToThread inside void QOpenGLWidget::initializeGL() which is responsible to set up the context

start qtimer from another class faces segmentation fault

I'm facing a problem using QTimer. The program closes with a segmentation fault in run time and when I exclude the "timer" from code, it runs properly. Here's the code:
Class A : public QObject, public QGraphicsPixmapItem{
Q_OBJECT
public:
A(QPixmap pic){
this->setPixmap(pic);
}
void start(){
timer = new QTimer();
timer->start(1000);
connect(timer, SIGNAL(timeout()), this, SLOT(moveObject()));
}
public slots:
void moveObject(){
moveTimer = new QTimer();
moveTimer->start(20);
connect(moveTimer, SIGNAL(timeout()), this, SLOT(changePosition()));
}
void changePosition(){
//a couple of things are done here
}
private:
QTimer *timer;
QTimer *moveTimer;
}
Class B : QGraphicsView{
Q_OBJECT
public:
B(QWidget *parent = 0) : QGraphicsView(parent){
a = new A(QPixmap("a.png"));
void go(){
a->start();
}
private:
A *a;
}
P.S. I delete moveTimer in changePosition as long as the object stops moving and recall moveObject so that it can move towards the next target.

Qt C++ QTimer does not call handler

I've got problem with QTimer in Qt C++, in my code timeoutHandler() is not called. Can anyone tell me why and how I can fix it?
Test.h
class Test : public QObject
{
Q_OBJECT
private:
static bool timeOuted;
public:
explicit Test(QObject *parent = 0);
virtual ~Test();
public slots:
static void handleTimeout();
};
Test.cpp
void Test::run()
{
QTimer::singleShot(3000, this, SLOT(handleTimeout()));
while(!timeOuted);
if(timeOuted)
{
timeOuted = false;
}
else
{
/* some work */
}
}
bool Test::timeOuted = false;
void Test::handleTimeout()
{
static int i = 0;
timeOuted = true;
qDebug() << "TimeOuted " << i++;
}
QTimer requires Qt event loop to work. When you enter the while(!timeOuted);, you block the current thread endlessly and the Qt's event loop has no chance to take any action (like calling your handler for the timer). Here's how you should do it:
Test.h:
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0);
virtual ~Test();
void run(); // <-- you missed this
private slots: // <-- no need to make this slot public
void handleTimeout(); // <-- why would you make it static?!
};
Test.cpp:
void Test::run()
{
QTimer::singleShot(3000, this, SLOT(handleTimeout()));
}
void Test::handleTimeout()
{
static int i = 0;
qDebug() << "TimeOuted " << i++;
/* some work */
}
To update answer from Googie you can use also lambda from C++11:
QTimer::singleShot(10000, [=]() {
// Handle timeout here
});

QTimer to execute method every second

I'm learning Qt and I was reading about Threads, Events and QObjects from Qt wiki, and followed the wiki recommendations on how to handle some work in a while condition but its not working for my specific case. Here's a simple example of what I'm currently trying to achieve.
class FooEvents : public FooWrapper {
public virtual serverTime(..) { std::cout << "Server time event\n"; }
public virtual connected(..) { std::cout << "Connected event\n"; }
}
class Foo : public QObject {
private:
FooAPI *client;
public:
Foo(FooEvents *ev, QObject *parent = 0) : client(new FooApi(ev)) { .. }
private slots:
void processMessages() {
if (state is IDLE)
reqFooAPiServerTime();
select(client->fd()+1, ...);
if (socket is ready for read)
client.onReceive();
}
public:
void connect(...) {
if (connection) {
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(processMessages()));
timer.start(1000); // I don't get the output from FooEvents
}
}
}
This is a very simple but I think it illustrates my case. Why is this not working and what other alternatives to I have to handle this case? Thanks.s
Edit: The processMessages is being called every second but I don't get any output from the events
Where is timer declared and defined?
If it's local to Foo::connect() it'll be destroyed before it ever has a chance to fire. Presumably it just needs to be a member object of the Foo class.
Also keep in mind that QObject provides it's own simple interface to a timer - just override the protected virtual timerEvent() function and call QObject's startTimer() to start getting those timer events. In this case instead of having a slot to receive the timer events, they will just end up at the overridden timerEvent() function:
protected:
void timerEvent(QTimerEvent *event) {
processMessages();
}
public:
void connect( /* ... */ ) {
// ...
startTimer(1000);
}
This won't work, because processMessages() is not a SLOT.
So Declare processMessages() as a private slot and then try.
You don't declare the timer neither the slot. In the header you must declare:
class ... {
QTimer timer;
...
private slots:
void processMessages();
...
};
Then remember to make the SIGNAL-SLOT connection and configure the timer:
connect(&timer, SIGNAL(timeout()), this, SLOT(processMessages()));
timer.setInterval(1000);
timer.start();
Also timer.start(1000); would be valid...
ANOTHER POSSIBILITY
Other possibility would be to use the timer associated with each Q_OBJECT and overload the timerEvent:
class ... {
Q_OBJECT
...
protected:
void timerEvent(QTimerEvent *event);
...
};
Then you must implement the timer event as this:
void MyClass::timerEvent(QTimerEvent *event) {
processMessages();
}
And you can configure the timer with a simple call to startTimer(1000);