QTimer is not making a time delay



  • Hi,

    I have two QPushButton and a QSlider. I Want to press the startButton and the position of the slider should increment, wait 1 sec and increment again and so on. When I hit the stopButton I want the loop of the slider incrementation to stop.

    Right now I'm trying this, but it's just jumping right to the slider's last position or the program is crashing. Of course I'm not writing down code, that is irrelevant for this problem in my opinion

    In FVolumeplayer the player is displayed as a dockwidget in the mainwindow. If a button is clicked I emit signals and handle the events in the mainwindow.
    FVolumePlayer.h
    @class FVolumePlayerWidget: public QDockWidget
    {
    Q_OBJECT

    public:

    enum State {Paused=0, Playing=1, Stopped=2};
    State playerState;
    State state() {return playerState;}
    //...
    public slots:
    void on_playButton_clicked_slot();
    void on_stopButton_clicked_slot();

    signals:
    void play();
    void stop();
    };@

    FVolumePlayer.cpp
    @FVolumePlayerWidget::FVolumePlayerWidget(QMainWindow parent)
    : QDockWidget(tr("Timeline"),(QWidget
    )parent), playerState(Stopped)
    {
    //...
    playButton = new QPushButton();
    playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
    connect(playButton, SIGNAL(clicked()), this, SLOT(on_playButton_clicked_slot()));
    stopButton = new QPushButton();
    stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop));
    connect(stopButton, SIGNAL(clicked()), this, SLOT(on_stopButton_clicked_slot()));

         horizontalSlider = new QSlider(Qt::Horizontal, this);
        //...
    

    }

    void FVolumePlayerWidget::on_playButton_clicked_slot()
    {
    emit play();
    }

    void FVolumePlayerWidget::on_stopButton_clicked_slot()
    {
    emit stop();
    }@

    In the mainwindow I connect the signals from the player to slots and check for the current state to make the player act like desired.
    FMainWIndow.cpp
    @FMainWindow::FMainWindow(ProcessorNetwork *network, QWidget *parent, Qt::WindowFlags flags)
    : network_(network), QMainWindow(parent, flags), volumeCount(0)

    {
    vlmPlayWidget_ = new FVolumePlayerWidget(this);
    addDockWidget(Qt::BottomDockWidgetArea , vlmPlayWidget_);

        connect(vlmPlayWidget_, SIGNAL(play()), this, SLOT(play_slot()));
    

    connect(vlmPlayWidget_, SIGNAL(stop()), this, SLOT(stop_slot()));
    }

    void FMainWindow::play_slot()
    {
    if (vlmPlayWidget_->state() == FVolumePlayerWidget::Playing)
    {
    QMessageBox::critical(this, "Error", "Volume Player is already running");
    return;
    }

    if(vlmPlayWidget_->state() == FVolumePlayerWidget::Stopped)
    {
    vlmPlayWidget_->playerState = FVolumePlayerWidget::Playing;
    }
    QEventLoop evt;

    while(vlmPlayWidget_->playerState != FVolumePlayerWidget::Stopped)
    {
    evt.processEvents();
    if(vlmPlayWidget_->playerState == FVolumePlayerWidget::Playing)
    {
    volumeCount = vlmPlayWidget_->horizontalSlider->value()+1;
    vlmPlayWidget_->horizontalSlider->setValue(volumeCount);
    QTimer::singleShot(1000, this, SLOT(vlmPlayWidget_->horizontalSlider->update()));
    }
    }
    vlmPlayWidget_->playerState = FVolumePlayerWidget::Stopped;
    }

    void FMainWindow::stop_slot(){
    vlmPlayWidget_->playerState = FVolumePlayerWidget::Stopped;
    //volumeCount = 0;
    vlmPlayWidget_->horizontalSlider->setValue(volumeCount);

    }@

    As I said, the QTimer is not making a time delay of 1 second between each iteration and the slider is moving to his last position immediatly. And I read I nead an eventloop somwhere, but I don't know if I put it in the right lines. So how do I get this working the right way? Or do you need more information to help me?



  • try

    QTimer::singleShot(1000, vlmPlayWidget_->horizontalSlider, SLOT(update()));


  • Lifetime Qt Champion

    Hi,

    bq. @QEventLoop evt;

    while(vlmPlayWidget_->playerState != FVolumePlayerWidget::Stopped)
    {
    evt.processEvents();
    if(vlmPlayWidget_->playerState == FVolumePlayerWidget::Playing)
    {
    volumeCount = vlmPlayWidget_->horizontalSlider->value()+1;
    vlmPlayWidget_->horizontalSlider->setValue(volumeCount);
    QTimer::singleShot(1000, this, SLOT(vlmPlayWidget_->horizontalSlider->update()));
    }@

    This is wrong in many ways:

    • evt is another event loop that you don't start so calling processEvents on that object won't have any effect. Also it won't have the effect you are thinking about.
    • Your call to QTimer::singleShot is also wrong, it should be (delay, object_that_has_the_slot, SLOT(slot_of_your_object())

    I would recommend that you refactor a bit your code. You are trying to do several simple things in a very convoluted manner.

    Changing a slider value each second (raw idea):
    Have a QTimer as class member
    Set it to run each second
    Connect the timer timeout signal to a slot where you increment the slider value.
    Connect your start button clicked signal to the timer start slot
    Connect your stop button clicked signal to the timer stop slot

    Since you have all your buttons/slider in FVolumePlayer, do all the work in that widget, MainWindow does not need at all to know the internals of your widget.

    Hope it helps



  • Okay, I tried to implement your Idea like this in the FVolumePlayer.cpp:

    @volumeTimer = new QTimer(this);
    connect(volumeTimer, SIGNAL(timeout()), this, SLOT(play()));
    volumeTimer->setInterval(1000);

    playButton = new QPushButton();
    playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
    connect(playButton, SIGNAL(clicked()), volumeTimer, SLOT(start()));
    stopButton = new QPushButton();
    stopButton->setIcon(style()->standardIcon(QStyle::SP_MediaStop));
    connect(stopButton, SIGNAL(clicked()), volumeTimer, SLOT(stop()));@

    and

    @void FVolumePlayerWidget::play()
    {
    horizontalSlider->setValue(horizontalSlider->value()+1);
    }@

    But It just does nothing when I click the playButton. Am I missing something? play() is declared as public slot in FVolumePlayer.h



  • The code looks fine. Maybe check if all the connect calls return true. Also do you have a running eventloop ? Like do you call QApplication::exec() or QCoreApplication::exec() somewhere?



  • bq. Also do you have a running eventloop ? Like do you call QApplication::exec() or QCoreApplication::exec() somewhere?

    Yes, I do in the main.cpp

    bq. The code looks fine. Maybe check if all the connect calls return true.

    How do I check this?



  • connect returns a boolean just do this
    @
    bool connectTest = connect(volumeTimer, SIGNAL(timeout()), this, SLOT(play()));
    @
    also have you checked if you place a break point in the play() method if you ever enter that function?



  • Okay thanks it's already working, the code is fine. Turns out, the moment I pushed the button,my computer was running very slow and closed the program maybe a second too soon. I compiled again and now it's working.

    Thanks alot to all of you, you really helped me out. My brain was blowing out steam already.


  • Lifetime Qt Champion

    You're welcome !

    Since your problem's gone, you can update the thread's title to solved so other forum users may know that a solution has been found :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.