Seite 1 von 1

[gelöst] QTimer Countdown

Verfasst: 8. Februar 2011 20:20
von Mani99
Hallo,

ich möchte einen countdown starten, habe aber probleme mit der realisierung, und zwar erstelle ich ein QTime objekt und möchte darstellen, das immer eine sekunde bei timeout() abgezogen wird

Aber es ist so, das bei timeout() die aktuelle uhrzeit in dem lcd feld dargestellt wird minus einer sekunde, obwohl ich QTime mit 10 sekunden initialisiere.

Kann mir jemand sagen was ich falsch mache?

Code: Alles auswählen

class MyApp : public QMainWindow
{
    Q_OBJECT

    public:
        explicit MyApp(QWidget *parent = 0);
        ~MyApp();

    private:
        Ui::MyApp *ui;
        QTimer *my_timer;
        QTime *c_time;

    public slots:
        void timerAction();

private slots:
    void on_btnStartStop_toggled(bool checked);
};

Code: Alles auswählen

MyApp::MyApp(QWidget *parent) : QMainWindow(parent), ui(new Ui::MyApp)
{
    ui->setupUi(this);

    my_timer = new QTimer(this);
    c_time = new QTime();
    c_time->setHMS(0,0,10,0);
    my_timer->setInterval(1000);

    connect(my_timer, SIGNAL(timeout()), this, SLOT(timerAction()));

    ui->lcdNumber->display(c_time->toString("hh:mm:ss"));
}

void MyApp::timerAction()
{
    my_timer->addSecs(-1)
    QTime new_time = my_timer->addSecs(c_time->elapsed()*-1);
    ui->lcdNumber->display(new_time.toString("hh:mm:ss"));

    /*
    if(new_time == QTime(0,0,0,0))
    {
        qDebug("Timer abgelaufen!");
        my_timer->stop();
    }*/
}

void MyApp::on_btnStartStop_toggled(bool checked)
{
    if(checked)
    {
        my_timer->start();
        c_time->start();
        ui->btnStartStop->setIcon(QIcon(QString::fromUtf8(":/btn/img/player_play.png")));
    }
    else
    {
        blindTimer->stop();
        ui->btnStartStop->setIcon(QIcon(QString::fromUtf8(":/btn/img/player_pause.png")));
    }
}

MyApp::~MyApp()
{
    delete ui;
}

Verfasst: 8. Februar 2011 20:56
von dontinelli
Hast du mal in der Doku nachgeschaut, was folgende Zeile bewirkt:

Code: Alles auswählen

c_time->start();
Lässt du diese weg, sollte es wohl klappen.

Verfasst: 8. Februar 2011 20:59
von Mani99
Hi,

danke für die antwort, hat soweit fuktioniert, aber jetzt wird genau von den 10 sekunden 1 abgezogen und dann aktualisiert sich QLCDNumber nicht mehr!

Verfasst: 8. Februar 2011 21:42
von Christian81
1. kann der Code nicht kompilieren - QTimer hat keine Funktion addSecs()
2. QTime::elapsed() bringt keine Sekunden zurück - Doku

Verfasst: 9. Februar 2011 13:05
von Mani99
Danke für die antworten und hinweise.

Ich hab mir das jetz noch einmal angesehen, und weiß jetzt das QTime::elapsed() millisekunden zurückliefert. Aber so ganz weiß ich noch immer nicht wie eine stopp uhr erstellen kann.

Was mir bei meinen tests noch aufgefallen ist, die zeit läuft nicht konstant mit dem timer. Einmal laufen wirklich die sekunden, dann ein sprung um zwei sekunden, etc.

Ich weiß das das damit zusammenhängt, das sich die GUI neu zeichnen muss, und ich das mit ein paar processEvent() verbessern kann.

Wäre es event. sinnvoll das mit einem thread zu lösen?

Könnte mir jemand bitte einen tipp geben was noch falsch läuft?

Danke!

Im anhang befindet sich das testprogramm.

timertest.h

Code: Alles auswählen

#include <QMainWindow>
#include <QTime>
#include <QTimer>

namespace Ui {
    class TimerTest;
}

class TimerTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit TimerTest(QWidget *parent = 0);
    ~TimerTest();

    QTime *startTime;
    QTime *runningTime;

    QTimer *myTimer;

private:
    Ui::TimerTest *ui;

    void init();

public slots:
    void myTimer_TimeOut();

private slots:
    void on_btnStartStop_toggled(bool checked);
};
timertest.cpp

Code: Alles auswählen

#include "timertest.h"
#include "ui_timertest.h"

TimerTest::TimerTest(QWidget *parent) : QMainWindow(parent), ui(new Ui::TimerTest)
{
    ui->setupUi(this);

    init();
}

void TimerTest::init()
{
    startTime = new QTime(0,0,30,0);
    runningTime = new QTime();

    myTimer = new QTimer(this);
    myTimer->setInterval(1000);

    connect(myTimer, SIGNAL(timeout()), this, SLOT(myTimer_TimeOut()));

    ui->lcdNumber->display(startTime->toString("hh:mm:ss"));
}

void TimerTest::myTimer_TimeOut()
{
    QTime time_out = startTime->addMSecs(runningTime->elapsed()*-1);
    ui->lcdNumber->display(time_out.toString("hh:mm:ss"));

    if(time_out == QTime(0,0,0,0))
        myTimer->stop();
}

void TimerTest::on_btnStartStop_toggled(bool checked)
{
    if(checked)
    {
        startTime->start();
        myTimer->start();
    }
    else
    {
        myTimer->stop();
    }
}

TimerTest::~TimerTest()
{
    delete ui;
}


Verfasst: 9. Februar 2011 15:30
von dontinelli
Also ich denke, du machst das reichlich kompliziert. Weshalb brauchst du startTime und runningTime? Ich würde das in etwa so machen (quick and dirty, d.h. ungetestet):

header:

Code: Alles auswählen

#include <QMainWindow>
#include <QTime>
#include <QTimer>

namespace Ui {
    class TimerTest;
}

class TimerTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit TimerTest(QWidget *parent = 0);
    ~TimerTest();

    QTime *startTime;

    QTimer *myTimer;

private:
    Ui::TimerTest *ui;

    void init();

public slots:
    void myTimer_TimeOut();

private slots:
    void on_btnStartStop_toggled(bool checked);
}; 
cpp

Code: Alles auswählen

#include "timertest.h"
#include "ui_timertest.h"

TimerTest::TimerTest(QWidget *parent) : QMainWindow(parent), ui(new Ui::TimerTest)
{
    ui->setupUi(this);

    init();
}

void TimerTest::init()
{
    startTime = new QTime(0,0,30,0);

    myTimer = new QTimer(this);
    myTimer->setInterval(1000);

    connect(myTimer, SIGNAL(timeout()), this, SLOT(myTimer_TimeOut()));

    ui->lcdNumber->display(startTime->toString("hh:mm:ss"));
}

void TimerTest::myTimer_TimeOut()
{
    startTime->addMSecs(-1000);
    ui->lcdNumber->display(startTime.toString("hh:mm:ss"));

    if(startTime == QTime(0,0,0,0))
        myTimer->stop();
}

void TimerTest::on_btnStartStop_toggled(bool checked)
{
    if(checked)
    {
        myTimer->start();
    }
    else
    {
        myTimer->stop();
    }
}

TimerTest::~TimerTest()
{
    delete ui;
}
Musst dir halt immer bewusst sein, dass je nach Systemlast der QTimer nicht sehr genau ist. Wenn's etwas genauer sein sollte, würde ich den Interval herunter setzen und die Differenz berechnen (z.b. hiermit).

LG
Dontinelli

Verfasst: 9. Februar 2011 15:48
von Mani99
Hi,

danke für die antwort, nur folgendes kann nicht funktionieren:

Code: Alles auswählen

void TimerTest::myTimer_TimeOut()
{
    startTime->addMSecs(-1000);
    ui->lcdNumber->display(startTime.toString("hh:mm:ss"));

    if(startTime == QTime(0,0,0,0))
        myTimer->stop();
} 

Code: Alles auswählen

startTime->addMSecs(-1000);
zieht 1000 msecs ab und gibt ein const QTime zurück. Und bei jedem timeout() werden wieder von den anfänglichen 30 sekunden 1 sekunde abgezogen --> d.h. läuft ewig!

Code: Alles auswählen

if(startTime == QTime(0,0,0,0))
Das wird glaub ich so auch nicht hin hauen, weil startTime ein pointer ist!

Verfasst: 9. Februar 2011 15:57
von Christian81
Abgesehen davon dass man einfach einen integer mit 10 initialisieren und bei jedem timeout() um 1 verringern könnte was das ganze wesentlich vereinfacht...

Verfasst: 9. Februar 2011 16:11
von Mani99
Hi,

danke, die einfache variante funktioniert ganz gut! :D