I am trying to implement pause button for a game I am developing in Qt + OpenGL.
I want to implement it using QTimer.
Basically I am updating screen per 100ms. So in order to pause game, I will stop the timer on button press. and when button is again pressed i will start the timer again
Here is my pauseOrPlay SLOT:
void Window::pauseOrPlay()
{
GLWidget::modifyTimer = TRUE;
GLWidget::isPaused = !GLWidget::isPaused;
GLWidget timerUpdater;
timerUpdater.timerFunc();
}
and Here is my timerFunc()
GLvoid GLWidget::timerFunc()
{
static QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
if( GLWidget::isPaused)
timer->start(100);
else
timer->stop();
}
But I am not getting the functionality. I get paused screen on this particular code and upon trying few tweaks here and there, sometimes I get screen updating very fastly which pointed me to this but I was unable to find cure to my problem somehow
Any help or Pointers?
PS: In this question there is nothing about OpenGL, but I think those are the people who might have dealt with similar think, adding OpenGL tag
That connection is in a bad place. You have it set up to connect each time you pause or resume the game. But if you connect multiple times, your slot will be called multiple tiles for each signal emission.
Make sure you only create the timer and connect to it once. I suggest moving the timer construction and signal connection into your GLWidget's constructor. Store a pointer to the timer as a member variable of your class so you can start and stop it in the class's member functions.
Related
I am currently starting on QTCreator. I have been asked to use QTimers in a particular context which is this:
We have an open window,
One or more QTimers are triggered and make things appear on the screen every x msec.
When we press "Escape" the window should close and everything should be reset to 0.
But here is the problem, the timers are defined in a static way:
QTimer::singleShot(500, this, SLOT(foo());
When I call this->close() (which closes my window), the timers do not stop and continue. I tried several solutions: browse all the QTimers contained in my object, obviously there are none since they are defined in static. Instead of declaring them in static I've tried to create each time a new QTimer object like that:
QTimer *timer= new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(2000);
timer->setParent(this);
timer->start();
And then call timer->stop() later, but I think it's very brutal when you have multiple Timers in the same code.
Is there a way to stop the timers when this->close is called, knowing that the timers are defined as a static one ?
Assuming you are using,
QWindow *qw = new QWindow();
QTimer *timer= new QTimer();
To solve the issue you need to connect destroyed() signal of QWindow to timer's slot stop()
So as soon as window is destroyed all registered timers will be stopped without explicit stop call. make sure you connect all timer instances. Code snippet as following,
QObject::connect(&qw, SIGNAL(destroyed()), timer, SLOT(stop()))
QObject::connect(&qw, SIGNAL(destroyed()), timer2, SLOT(stop()))
QObject::connect(&qw, SIGNAL(destroyed()), timer3, SLOT(stop()))
PS:
QTimer *timer= new QTimer(this); // here you are setting parent as 'this' already
timer->setSingleShot(true);
timer->setInterval(2000);
timer->setParent(this); // remove this, no need to set parent again.
timer->start();
I am new to and learning the Qt GUI framework.
I have an ultrasonic sensor wired up to the Raspberry Pi, to measure water level. If I were coding in C, I would have used a while(1) loop to constantly read the sensor input. But when I put while(1) inside MainWindow.cpp, the window cannot be displayed. However, using qDebug() I can still print out the sensor value, which means my while(1) still running but the main window won't appear. I found out in this answer that because of while(1),
MainWindow ctor never returns, so w.show() is never called and a.exec() (main message loop) is never executed.
To solve this, I use QTimer instead of a loop: connect the timeout() SIGNAL to a SLOT which is a function to read the sensor value one-time:
waterLevelTimer = new QTimer(this);
connect(waterLevelTimer, SIGNAL(timeout()), this, SLOT(getWaterLevel()));
waterLevelTimer->start(100); // "loop" once every 100 millisecond
With this method, I can read the sensor value with the fastest interval is 1 millisecond and the GUI still displayed fine.
But should I use QTimer to mimic a while(1) loop? Is there a better way to have an infinite loop to read GPIOs while still being able to use GUI for other work?
The main thread where the GUI of Qt runs never should be blocked by long-lasting operations like an infinite while-loop, because otherwise you would block the event system and nothing will work anymore.
Instead you usually create a worker thread in parallel (see QThread) where you do your loop in the run function of the thread. Maybe also use such timer as you suggest, which works if the executed code is faster than the timer duration.
QThread *thread = QThread::create([]{
while(1)
checkSomething();
});
thread->start();
I'm trying to make a program in Qt. I will not send all, but the fragment with which I have a problem. The point is, I have to interrupt a function that has a Timer in it, but I don't know how to interrupt it while it's waiting before timer. 😕 Please reply!
void MainWindow::Test(){
TestWrite(); //TestWrite is a function where I write my answer
QTimer::singleShot(5000, this, &MainWindow::TestCheck); //TestCheck is a function where the answer is checked
}
void MainWindow::on_Test_clicked()
{
Test();
timer = new QTimer(this); //Creates a timer and calls the Test function every 7 seconds
timer->connect(timer, &QTimer::timeout, this, &MainWindow::Test);
timer->start(7000);
}
........
........
void MainWindow::on_Back_clicked()
{
timer->stop(); //I am trying to make the "Back" button interrupt the Test, TestWrite and TestCheck functions. Now, if you quickly click "Back" and "Test", the effect is as if you did not click the "Back" button
}
Timers in Qt that you start with the static QTimer functions (like you do in MainWindow::Test) cannot be stopped at all, because there's no timer object exposed to you that you could use to stop() (or otherwise manipulate) the timer. Such timers will expire in any case, and they will emit their signal in any case. You need to decide in your slot whether you're still interested in the signal.
When you create an explicit timer object (as you do in on_test_clicked(), you can only stop() it, or re-start() it with a minimum expiry time (0) to have it expire "immediately".
If you don't want to have a timer expire that you already started, simply stop() it.
The way you stated your question shows a possible mis-understanding of how timers work in Qt. Nothing is "waiting" for a timer, but rather an expired timer sends a signal to a slot. "Waiting" in Qt would freeze your user interface.
I'm using Qt for an application.
I would like to display a window then put a timer and display a second window.
But currently the timer is done then the 2 windows open at the same time
this->firstWindow->show();
QTime dieTime = QTime::currentTime().addSecs(10);
while (QTime::currentTime() < dieTime);
this->secondWindow->show();
I tried a lot of solutions, like putting the show() of the firstwindow directly into the constructor but nothing works.
You are using a blocking while loop to wait for the time to elapse, so the GUI thread cannot update the user interface. You could use QTimer for a non-blocking wait or refresh the GUI by adding qApp->processEvents(QEventLoop::AllEvents, 100); into the while loop.
I would prefer QTimer, because then you are not creating your own event loop. For example:
QTimer::singleShot(10000, this->secondWindow, SLOT(show()));
I have a quite lengthy foreach loop in a QDialog. It basically looks like this:
foreach (xxx, xxx) {
... doSomeStuff ...
QApplication::processEvents();
if (m_cancelMapLoading) {
break;
}
}
m_cancelMapLoading is set to true by clicking a "Cancel" button. The QApplication::processEvents(); makes this possible.
This works quite fine, but if the dialog is closed as long as that foreach loop still runs, it continues running. I tried to set m_cancelMapLoading to true in each function closing the dialog, but this does not help.
I also tried to test not only for m_cancelMapLoading being true, but also for isVisible(). This actually stops the dialog, but it re-opens it at once without the GUI elements in it.
Unfortunately, QtConcurrent::run etc. can't be used for the function, because the data structures that are manipulated by the foreach loop are not thread safe.
Is there a convenient way to solve this?
You can use a QTimer and Qt's parent-child structure to your advantage here. QTimer with a timeout value of zero has a special meaning in Qt
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface:
So you could do something like
void Dialog::beginDoingStuff()
{
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(processData());
m_timer->start(0);
}
void Dialog::processData()
{
// Perform one cycle of your process here
}
This will perform the processData() function in the same thread as the rest of the dialog, and when the dialog is destroyed by being closed, the timer will be deleted (because it's parent is the dialog), meaning the processing will stop.
A good and quite easy way to unload your GUI from heavy processing is assigning it to another thread or QtConcurrent.
You could then either poll a "should-I-terminate-yet?" variable or terminate the thread manually when it is no longer needed.
I highly recommend a parallel processing since offers better control rather than doing a "DoEvents"-like queue emptying.
We actually managed to solve the problem by connecting the dialog's finished signal to the click slot of the cancel button. This actually stops the loop in all circumstances.
We also introduced starting the function by a QTimer (for a nicer implementation not blocking the function where it's started), but this does not stop the loop (perhaps because we don't destroy the dialog when it's closed).
Thanks for all help :-)