PDA

View Full Version : static QTimer



PauloF91
6th June 2013, 15:30
I want to get a single timer to run for several objects.
If I put this in the header file of my class:
static QTimer* timer = new QTimer(this);

It says: « 'this' cannot appear in a constant-expression ». I understand i cannot use 'this', since I want a class member, not an object member (I guess that makes sense), but I don't know how to solve it. How do I put it then?

Thanks in advance.

PF91

Santosh Reddy
6th June 2013, 16:59
Here is a static class member example


//a.h
Class A
{
private:
static QTimer timer1;
static QTimer *timer2;
}

//a.cpp
#include "a.h"
QTimer A::timer1;
QTimer * A::timer2 = new QTimer(0); //EDIT: Added *

PauloF91
6th June 2013, 18:05
Lets say I have class B that inherits from class A:


//a.h
Class A
{
public:
static QTimer timer1;
static QTimer *timer2;
}

//b.h
Class B : public A
{
}

//b.cpp
#include "b.h"
B::B(){
QTimer A::timer1;
QTimer A::timer2 = new QTimer(0);
}


And I'm getting this error:
invalid use of qualified-name 'A::timer1'
invalid use of qualified-name 'A::timer2'

Where is this wrong?

PS: I don't think I'm getting this straight. If I'm gonna have a single (static) timer, I guess I should only start it once. In this code, that will be done each time I instantiate an object from class B, I guess that's not correct.
All I wanna do is a QObject::connect function from my timer1's timeout() SLOT to a SIGNAL, and that signal is different from object to object (since I have others classes that inherit from class A, besides class B) that's why I'm running it in B's (or other subclass) constructor. I guess that's doable.

Santosh Reddy
6th June 2013, 21:45
Oh yes you got it wrong.

If I understand your problem, you have a base class say A, and there are different derived classes from it each wanting to connect to a common signal from base object but do derived class specific slot.

Will this example work?


//a.h
Class A
{
public:
static QTimer *timer;
}

//a.cpp
#include "a.h"
QTimer * A::timer = new QTimer(0);

//b.h
Class B : public A
{
}

//b.cpp
#include "b.h"
B::B() : A() {
QObject::connect(timer, SIGNAL(timeout()), object, SLOT(object_slot()));
}


Anyway this is just a basic C++ problem, nothing to do with Qt, you better read more about C++ static class members.

PauloF91
6th June 2013, 23:28
If I understand your problem, you have a base class say A, and there are different derived classes from it each wanting to connect to a common signal from base object but do derived class specific slot.
Yes that's it.
Ye.. this is my very first project in C++ or anything related to OOP, I should read some stuff about this, but I gotta get this done asap.

Just a couple things I still don't get.
What do you mean by "object" in:

QObject::connect(timer, SIGNAL(timeout()), object, SLOT(object_slot()));
Should I put '0' or 'this'? Cause neither or them will work. I got this (obvious) error:

QObject::connect: Cannot connect QTimer::timeout() to (null)::MySlot()

Sorry if this is too obvious, I wouldn't ask if I didn't really had to.
Thanks in advance.

wysota
7th June 2013, 07:17
I would recommend against using a static timer.

Santosh Reddy
7th June 2013, 10:22
I am sure even if showed you how to use QTimer or SIGNAL/SLOTS in general that will still not solve you problem. Instead can you tell use what actually you have to do, and how you are doing it?

PauloF91
7th June 2013, 13:53
Instead can you tell use what actually you have to do, and how you are doing it?
Im plotting some data in a few graphics I've made myself.
Each graph represents an object. And I have 2 kinds of graphs (therefore, 2 classes):
- line graphs (Class GraphLine);
- histograms (Class GraphHistogram).

And they both inherit from a base class Graph.
So I thought I could use a Timer, so each time it timed out, I could update all graphs with new data.
I had it working, but I was creating one timer per graph. That was not a problem until I realized I wanted to stop and re-start all timers at once each time I wanted (while the program was running).

That's when I thought of a static Timer.


//graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include <QTimer>

class Graph{
public:
Graph(/*stuff*/);
static QTimer *timer;

protected:
/*stuff*/
};

#endif // GRAPH_H

//graph.cpp
#include "graph.h"

QTimer *Graph::timer = new QTimer(0);

Graph::Graph(/*stuff*/){
/*stuff*/
}

//graphline.h (same goes for graphhistogram.h)
#ifndef GRAPHLINE_H
#define GRAPHLINE_H
#include "graph.h"
class GraphLine : public Graph{
public:
GraphLine(/*stuff*/);
void updateGraph(int rand = 0);

private:
int graphArray[100];

public slots:
void MySlot();
};
#endif // GRAPHLINE_H


//graphline.cpp
#include "graphline.h"

GraphLine::GraphLine(/*stuff*/) : Graph(/*stuff*/){
updateGraph(0);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(MySlot()));
timer->start(40);
}

void GraphLine::updateGraphic(int rand){
/*graphic draw process*/
}

void GraphLine::MySlot(){
updateGraph(rand() % 100); // now i'm just giving rand values instead of true data
}

Santosh Reddy
7th June 2013, 14:26
See if this example helps


#include <QtGui>
#include <QtWidgets>
#include <QApplication>

class Graph : public QWidget
{
Q_OBJECT
public:
explicit Graph(QWidget * parent = 0)
: QWidget(parent)
, mGridLayout(new QGridLayout(this))
, mLabel(new QLabel("Graph"))
, mCount(0)
{

if(mTimer.interval() != mInterval)
mTimer.setInterval(mInterval);

QPushButton * startButton = new QPushButton("Start Update", this);
QPushButton * stopButton = new QPushButton("Stop Update", this);

connect(startButton, SIGNAL(clicked()), this, SLOT(startUpdateTimer()));
connect(stopButton, SIGNAL(clicked()), this, SLOT(stopUpdateTimer()));
connect(&mTimer, SIGNAL(timeout()), this, SLOT(updateGraph()));

mGridLayout->addWidget(mLabel, 0, 0, 1, 2);
mGridLayout->addWidget(startButton, 1, 0, 1, 1);
mGridLayout->addWidget(stopButton, 1, 1, 1, 1);
}

public slots:
void startUpdateTimer(int interval = mInterval)
{
if(mTimer.interval() != interval)
mTimer.setInterval(interval);
mCount = 0;
mTimer.start();
}

void stopUpdateTimer(void)
{
mTimer.stop();
}

virtual void updateGraph(void) = 0;

protected:
QGridLayout * mGridLayout;
QLabel * mLabel;
int mCount;

private:
static QTimer mTimer;
static const int mInterval = 1000;
};

QTimer Graph::mTimer;

class GraphLine : public Graph
{
Q_OBJECT
public:
explicit GraphLine(QWidget * parent = 0)
: Graph(parent)
{
setWindowTitle("GraphLine");
}

public slots:
virtual void updateGraph(void)
{
QString str = QString("GraphLine::updateGraph(): %1").arg(mCount++);
qDebug() << str;
mLabel->setText(str);
}
};

class GraphHistogram : public Graph
{
Q_OBJECT
public:
explicit GraphHistogram(QWidget * parent = 0)
: Graph(parent)
{
setWindowTitle("GraphHistogram");
}

public slots:
virtual void updateGraph(void)
{
QString str = QString("GraphHistogram::updateGraph(): %1").arg(mCount++);
qDebug() << str;
mLabel->setText(str);
}
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

GraphLine g1;
g1.show();

GraphHistogram g2;
g2.show();

return app.exec();
}

#include "main.moc"

PauloF91
8th June 2013, 01:00
Looking at your example did help me! I got it working... a single timer to run all my graphs.
I had to redo my base class to inherits from QWidget, and now my QObject::connect function is working just fine.

Thanks!