[SOLVED] Adding own slots to QTimer using an own class that inherits from QTimer OR Creating a timer function with simple stop, pause and continue mec
-
Hi,
I want to use QTimer in my recent Qt-Project. After having some troubles with SIGNAL-SLOT connections that were mainly based on the lack of slots in the QTimer class (i.e. I needed slots for my QTimer objects that didn't exist yet), I decided to write an own class which is derived from QTimer. Upon debugging, I received the error message:
"'QTimer::QTimer(const QTimer&)' is private
Q_DISABLE_COPY(QTimer)"
Seemingly, what Q_DISABLE_COPY does is that it prevents me from deriving classes from QTimer using copy constructors.
But I really need these slots. Has anyone got a solution to my problem? Or maybe a different way of doing it, so I don't have to derive a class from QTimer. I'm gratefull for any help.My code is (at least part of it):
MyTimer.h:
@
#ifndef MYTIMER_H
#define MYTIMER_H#include <QtWidgets>
class MyTimer : public QTimer
{
public:
MyTimer(QObject * parent = 0);
~MyTimer();private slots:
void pauseTimer();
void continueTimer();private:
int timeDiff;
int timeWanted;int get_timeDiff(); int get_timeWanted();
};
#endif // MYTIMER_H
@MyTimer.cpp:
@
#include "MyTimer.h"
#include <QMetaType>
#include <QMetaObject>//==========Konstructor and Destructor============
MyTimer::MyTimer(QObject *parent): QTimer(parent){
timeDiff=0;
timeWanted=0;
qRegisterMetaType<MyTimer>("MyTimer");
}
MyTimer::~MyTimer(){
}//==============SLOTS=============================
void MyTimer::pauseTimer(){
timeWanted=this->interval();
timeDiff=this->remainingTime();
QMetaObject::invokeMethod(this,"stop");
}void MyTimer::continueTimer(){
this->setInterval(timeWanted-timeDiff);
QMetaObject::invokeMethod(this,"start");
}//=====================FUNCTIONS==================
int MyTimer::get_timeDiff(){
return timeDiff;
}int MyTimer::get_timeWanted(){
return timeWanted;
}
@And the function I need it for:
@
void MainWindow::zeitfuncnew(int zeitVar){
QEventLoop zeitloop;zeitTimer->setInterval(zeitVar); zeitTimer->setSingleShot(true); connect(stopAct,SIGNAL(triggered()),&zeitloop,SLOT(quit())); connect(pauseAct,SIGNAL(triggered()),zeitTimer,SLOT(pauseTimer())); connect(weiterAct,SIGNAL(triggered()),zeitTimer,SLOT(continueTimer())); connect(zeitTimer,SIGNAL(timeout()),&zeitloop,SLOT(quit())); zeitTimer->start(); zeitloop.exec();
}
@zeitTimer, stopAct, pauseAct an weiterAct are all declared and defined somewhere else, but that's not relevant (in my opinion. If you need it however, I will be happy to provide the missing code.).
What I basically want to do :
Basically, I want to create a timing function with a simple stop, pause and abort mechanism.
That function (zeitfuncnew) waits for a certain time (zeitVar), unless the user hits stop or pause. If the user hits stop, the function should stop waiting and abort. If the user hits pause, the functions should pause until the user hits continue, without aborting. Then, if the user hits continue, the timer should resume waiting from where he left.
e.g.: If I set zeitVar = 15000 and ...
... hit stop after 7 seconds the function should stop waiting and abort.
... hit pause after 7 seconds, then wait another 45 seconds, before I hit continue, the function should continue counting from 7 seconds (7 000 ms) and should therefore finish waiting after another 8 seconds before aborting.As I allready said, I'm gratefull for all the help I can get. However, I'm in a bit of a hurry, so I would be even more gratefull, if someone could answer me soon, please.
Kind regards,
Arduvast
-
Hi and welcome to devnet,
Short version
@qRegisterMetaType<MyTimer>("MyTimer");@
Is the line giving your that complaint. You can't register a QObject as QMetaType since they can't be copied. Also, are you sure you need that ?
On a side note, are you sure that you need to inherit QTimer for your purpose ? It seems that you are more using a QTimer that extending it. I would probably be even simpler to have a "StopWatch" class that uses a QTimer and implement the slots you need rather that inherit from QTimer.
Hope it helps
-
Hi SGaist,
thank you for your reply and thanks a lot for the help. I followed your advice and created an own class that uses QTimer instead of inheriting it, and it seems to work. I'll run some more tests on the class, and if it really works, I'll post the code here.
======EDIT======
I did the testing this afternoon, and it really seems to be working, so here's the code for anyone, who's got a similar problem.
1.) mywatch.h:
@
#ifndef MYWATCH_H
#define MYWATCH_H#include <QWidget>
#include <QEventLoop>
#include <QTimer>class myWatch : public QWidget
{
Q_OBJECT
public:
explicit myWatch(QWidget *parent = 0);
~myWatch();
void zeitfuncWatch(int);
int get_zeitDiff();
int get_zeitWunsch();
bool beenden();
void setBeenden(bool);public slots:
void pauseWatch();
void weiterWatch();
void quitWatch();private:
int zeitDiff;
int zeitWunsch;
bool beEnden;
QTimer *watchTimer;
QEventLoop *watchLoop;
};
#endif // MYWATCH_H
@
2.) myWatch.cpp:
@
#include "mywatch.h"
//=================Konstruktor und Destruktor================
myWatch::myWatch(QWidget *parent) :
QWidget(parent)
{
zeitDiff=0;
zeitWunsch=0;
beEnden=false;
watchTimer = new QTimer;
watchLoop = new QEventLoop;watchTimer->setSingleShot(true); connect(watchTimer,SIGNAL(timeout()),watchLoop,SLOT(quit()));
}
myWatch::~myWatch(){}
//======================SLOTS=================================
void myWatch::pauseWatch(){
if(watchTimer->isActive()==true){
//zeitWunsch=watchTimer->interval();
zeitDiff=watchTimer->remainingTime();
watchTimer->stop();
}
}void myWatch::weiterWatch(){
if(watchTimer->isActive()==false){
watchTimer->start(zeitDiff);
}
}void myWatch::quitWatch(){
if(watchTimer->isActive()==true){
watchTimer->stop();
}
beEnden=true;
watchLoop->quit();
}//====================FUNKTIONEN====================
int myWatch::get_zeitDiff(){
return zeitDiff;
}int myWatch::get_zeitWunsch(){
return zeitWunsch;
}bool myWatch::beenden(){
return beEnden;
}void myWatch::setBeenden(bool theEnd){
beEnden=theEnd;
}void myWatch::zeitfuncWatch(int zeitVar){
//watchTimer->setInterval(zeitVar);
zeitWunsch = zeitVar;
watchTimer->start(zeitVar);
watchLoop->exec();
}
@
So basically, if you use this class and its member functions, you use them like this (only an example of use, no actually complete and working code. Use e.g. in MainWindow.cpp):
@
#include "mywatch.h"myWatch *timeWatch = new myWatch(this);
int plusVar = 15;QPushButton *continue_button = new QPushButton("Continue", ... );
/*actually, ... is "this", as QPushButton is usually used in either the MainWindow or some subsidiary window.
**Since none of both exist in this code EXAMPLE, I took the liberty to use ... instead.
**THIS WILL NOT WORK IN REAL CODE.
**In real Qt Code you'll have to have some kind of window or something you can place the PushButtons
**into (and you will have to use "this" instead of "...")
*/
QPushButton *pause_button = new QPushButton("Pause", ... );
QPushButton *quit_button = new QPushButton("Stop", ... );void anyfunc(); //this could be any function
void anyfunc(){
connect(pause_button, SIGNAL(realeased()),timeWatch,SLOT(pauseWatch()));
connect(continue_button, SIGNAL(realeased()),timeWatch,SLOT(weiterWatch()));
connect(quit_button, SIGNAL(realeased()),timeWatch,SLOT(quitWatch()));//do somethin here timeWatch->zeitfuncWatch(15000); //this will wait for 15 seconds //do something else here //you can use it in loops as well, if you like for (int i = 0; i < 9; i++){ //do something timeWatch->zeitfuncWatch((600000+plusVar)/3); if(timeWatch->beenden()==true){ /*check, whether zeitfunc() was exited regularly (after the set time), or was exited using the quit_button. **You can use bool beenden() to check, whether quit_button was used, and setBeenden(bool) to reset **bool beEnden to false.*/ timeWatch->setBeenden(false); //do something out of the regular } //do something else }
}
@
To anyone who wants to use this class :
One thing you have to keep an eye on*:* The timer in mywatch.cpp runs in an EventLoop. This EventLoop is started, when zeitfuncWatch() is called. However, weiterWatch() starts the timer without starting an EventLoop. And quitWatch will stop an EventLoop, not checking if one is running at all. I don't know, what the consequences of starting a timer without an EventLoop are (or stopping an EventLoop that isn't running, yet).
What I did to evade this problem was using QActions instead of the PushButtons, together with a toolbar. Then I disabled the respective QActions that were connected to pauseWatch, weiterWatch and quitWatch and reactivated them, whenever the QAction was called that set of a function containing zeitfunc(). Due to the speed of computers nowadays, the respective function would be executed in the blink of an eye, until it hit zeitfunc; so it would have been pretty hard to toggle pause, stop or continue in the short moment between their reactivation and the moment zeitfunc and the EventLoop started. At the end of the respective function (or after having executed zeitfunc()), I disabled the QActions again.
That way, weiterWatch(), pauseWatch() and quitWatch() effectively aren't activated as long as zeitfunc() isn't running.
You will have to find your own way of doing it.
One last thing: Sorry for all the German in the code. Here's a translation of the words used:
weiter = continue
Pause = pause
Zeit = time
Wunsch = wish
beenden = (to) end (sth.)