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_OBJECTpublic:
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?
-
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 slotSince 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
-
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.
-
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 :)