Qt pętla czasowa

0

Witam, ponownie proszę Was o pomoc, gdyż mam trudności z pewnym problem, mój worek pomysłów jest pusty. Aplikacja jest prosta. Po uruchomieniu widać QLabel oraz QLCDNumber który odlicza 7 sekund. Po upływie tego czasu zmienia się text w QLabel oraz jego kolor na 3 sekundy i ponownie odlicza się 7 sekund- taka pętla.
Nie wiem jak to zrobić. myślałem o użyciu _sleep(1000) w pętli 7 razy za każdym razem wyświetl aktualną sekundę i na tej zasadzie zrobić resztę.
Gdyby użyć do tego Qt-owskiej funkcji timer->start(1000)? Problem w tym, że jakby kod kodem a timer chodzi własnym życiem. Nie wiem jak napisać kod żeby timer odliczył te 7 sekund A POTEM DOPIERO wykonała się reszta kodu. Gdyby ktoś miał jakieś wskazówki byłbym wdzięczny. Z góry dzięki za pomoc.

2

QTimer wysyła sygnał timeout() gdy skończy się jego czas (robi to wielokrotnie jeśli nie jest typu singleshot). Żeby wykonać kod musisz użyć QObject::connect do połączenia wysłania sygnału z innym sygnałem bądź slotem.

QTimer t;
t.start(7000);

QObject::connect(&t, &QTimer::timeout, []{ cout << "Minelo 7 sekund" << endl; });
// oczywiście w tym wątku musi być aktywny QEventLoop

connect oczywiście nie musi być do lambdy, może też być do standardowego slotu.

0

pewnie to głupie pytanie ale muszę je zadać. Dlaczego nie mogę napisać czegoś takiego
int a=0;
moj_timer->start(1000);

//oczywiście gdzieś tam umieszczam QObject::connect(moj_timer, SIGNAL(timeout()), this, SLOT(moj_wyswietl()));
//gdzie moj_wyswietl to public slot o zawartości moj_timer->stop();

while(a==0)
{
if(moj_timer->isActive()==0){a=1;}
}

dlaczego u mnie powoduje to zawieszenie, logicznie co w tym jest nie tak?

0

Qt używa eventloopa do jednowątkowej obsługi zdarzeń. Jeśli zablokujesz się w funkcji to jednocześnie zablokujesz wykonywanie obsługi innych zdarzeń (w tym sprawdzenia, czy timer nie dostał timeouta).

Teoretycznie możesz to ominąć (ale to jest ogólnie niefajne rozwiązanie, mające sens chyba tylko w przypadku bardzo krótkiego kodu) i użyć QCoreApplication::processEvents wewnątrz pętli oczekującej.

Przy okazji: jeśli tylko jest taka możliwość używaj nowego syntaxu łączenia sygnałów i slotów (tak jak pokazałem w moim przykładzie) zamiast tego z makrami - jest bezpieczniej i lepiej.

0

teraz rozumiem, dzięki, jeśli mogę to chciałbym zapytać o jeszcze jedną rzecz, czyli jeśli mamy np.
{
timer.start(1000)
std::cout<<"line_1";
std::cout<<"line_2";
std::cout<<"line_3";

...

1000 innych rzeczy, nigdzie nie stopuję timera

}

// to program będzie odliczał tę sekundę do samego końca robiąc to naprzemiennie razem z wykonywaniem innych linijek kodu? Tzn. odliczy kilka ms potem wyświetli line_1 znowu coś tam urwie z tego niepełnego 1000 znowu coś wyświetli itd. Czy odliczy sekundę wyświetli line_1, znowu odliczy sekundę potem wyrzuci line_2 etc. Czy tak czy nie, czy jak?

0

Nie patrzyłem w kod, ale spodziewałbym się, że implementacja zapamiętuje timestamp wywołania start i potem (w eventloopie! nie w Twojej funkcji) patrzy czy now - moment_startu >= czas_timera.

1

Można iść jeszcze bardziej na łatwiznę i wykorzystać animation framework. Tyle wystarczy by uzyskać pożądany efekt:

void MainWindow::on_startButton_clicked()
{
    auto sequence = new QSequentialAnimationGroup(this);
    auto countDown = new QPropertyAnimation(ui->lcdNumber, "value", sequence);
    countDown->setDuration(7000);
    countDown->setStartValue(7.0);
    countDown->setEndValue(0.0);
    sequence->addAnimation(countDown);
    connect(countDown, &QAbstractAnimation::finished, [this]() {
        ui->label->setText("XXX");
        QPalette palette;
        palette.setBrush(QPalette::All, QPalette::Foreground, Qt::red);
        ui->label->setPalette(palette);
    });
    auto pause = sequence->addPause(3000);
    connect(pause, &QAbstractAnimation::finished, [this]() {
        ui->label->setText("YYY");
        ui->label->setPalette(QPalette());
    });

    sequence->setLoopCount(10);
    sequence->start();
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1