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.
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.
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?
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.
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?
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
.
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();
}