I have loop inside my main window code, that is simply changing the colour of some text-boxes on screen.
It is simply for(int i=0; i<200; i++), but I'd like to make every colour change visible to the user, so inside the loop I've tried to add sth like a 10ms pause, so every execution is visible on screen.
I used this:
QTimer t;
t.start(10);
QEventLoop loop;
connect(&t, SIGNAL(timeout()), &loop, SLOT(quit()));
loop.exec();
The problem is, that I'd like to have this 10ms pace constantly, so the whole operation will take about ~2 seconds. Unfortunately, it slows down gradually, so hard, that the last ~20 executions takes even about 1 second each
It looks rather decently when i<20~50, adding more makes it significantly slowing...
I thought about my not-really-brand-new PC, but it is really simple operation to be done, so I don't really think it is because of my slow pc.
I'm assume my approach is wrong
PS. During the execution, ram usage for my app is about ~21MB, and cpu about 20-30%
It is not good way to achieve something. QTimer is enough to this task. For example:
QTimer *t = new QTimer;//without loops and sleeping
connect(t, SIGNAL(timeout()), this, SLOT(someSlot()));
t->start(10);
Create someSlot and in this slot change color and do other tasks. To stop timer after 2 seconds, you can use counter instead of using system time.
void MainWindow::someSlot()
{
//do something
}
Also consider that 10 ms is very very fast, human eyes not able to catch so fast changing. Try to use longer value.
Related
I want to create a function, let's say (qDebug() << "result" ;). I want to display the result 2 secs later, the delay must be in this function implemented. In other words :
void MainWindow::my_function()
{
// Here I need something to make a delay of 2 secs
qDebug() << "result";
}
Is there a method or something that allows to wait 2 secs and then executes the next line ?
I m looking for the easiest method on QT.
Do NOT (mis)use sleep functions
Sleep functions are a specialized tool which is incredibly easy to misuse, and Qt gives you a lot of better options. So do not use sleep functions unless you know what you are doing (if only to avoid starting a bad habit).
So, what are your options?
If you only want the 2 second delay (e.g. after the user presses a button) you could use a QTimer::singleShot() which will call the function after the timer expires e.g.
QTimer::singleShot(2000, this, &MainWindow::printResultFunction)
Or you might use a local QEventLoop which you you will exec and then quit (again) using a timer e.g.
QEventLoop loop;
QTimer::singleShot(2000, &loop, &QEventLoop::quit);
loop.exec();
Or you might start a separate thread, which executes your function and in this function use (gasp) QThread::msleep() As I said before sleep functions are a specialized tool - here you know what you are doing. You are not stalling your GUI thread and qt events. You are pausing the execution of a thread designed to do one thing: doing stuff, waiting 2 seconds, doing some more stuff and terminating.
my suggestion is to read first why sleep are a bad idea, specially when GUIS are involved..
anyways, you can since qt5
Functions of QThread
void msleep(unsigned long msecs);
void sleep(unsigned long secs);
void usleep(unsigned long usecs);
using this in your code, you can do
void MainWindow::my_function(){
// Here I need something to make a delay of 2 secs
sleep(2);
qDebug() << "result";
}
but as I said before, read 1st, because this will work, but will freeze the main window too, which is a not so nice idea when considering User Experience etc
I'm writing a little game in c++ atm.
My Game While loop is always active, in this loop,
I have a condition if the player is shooting.
Now I face the following problem,
After every shot fired, there is a delay, this delay changes over time and while the delay the player should move.
shoot
move
wait 700 ms
shoot again
atm I'm using Sleep(700) the problem is I can't move while the 700 ms, I need something like a timer, so the move command is only executed for 700 ms instead of waiting 700 ms
This depends on how your hypothetical 'sleep' is implemented. There's a few things you should know, as it can be solved in a few ways.
You don't want to put your thread to sleep because then everything halts, which is not what you want.
Plus you may get more time than sleep allows. For example, if you sleep for 700ms you may get more than that, which means if you depend on accurate times you will get burned possibly by this.
1) The first way would be to record the raw time inside of the player. This is not the best approach but it'd work for a simple toy program and record the result of std::chrono::high_resolution_clock::now() (check #include <chrono> or see here) inside the class at the time you fire. To check if you can fire again, just compare the value you stored to ...::now() and see if 700ms has elapsed. You will have to read the documentation to work with it in milliseconds.
2) A better way would be to give your game a pulse via something called 'game ticks', which is the pulse to which your world moves forward. Then you can store the gametick that you fired on and do something similar to the above paragraph (except now you are just checking if currentGametick > lastFiredGametick + gametickUntilFiring).
For the gametick idea, you would make sure you do gametick++ every X milliseconds, and then run your world. A common value is somewhere between 10ms and 50ms.
Your game loop would then look like
while (!exit) {
readInput();
if (ticker.shouldTick()) {
ticker.tick();
world.tick(ticker.gametick);
}
render();
}
The above has the following advantages:
You only update the world every gametick
You keep rendering between gameticks, so you can have smooth animations since you will be rendering at a very high framerate
If you want to halt, just spin in a while loop until the amount of time has elapsed
Now this has avoided a significant amount of discussion, of which you should definitely read this if you are thinking of going the gametick route.
With whatever route you take, you probably need to read this.
I'm building a simple game that shows a countdown to the user, starting at 1:00 and counting down to zero. As 0:00 is reached, I want to display a message like "time's up!".
I currently have a QTimer and a QTime object (QTime starting at 00:01:00)
QTimer *timer=new QTimer();
QTime time{0,1,0};
In the constructor I'm setting the timer to timeout every 1 second, and it's connected to an event that updates the countdown on screen, which is initially displaying the timer at 1:00:
connect(timer, SIGNAL(timeout()), this, SLOT(updateCountDown()));
timer->start(1000);
ui->countdown->setText(time.toString("m:ss"));
This is the slot being called every 1 second:
void MainWindow::updateCountDown(){
time=time.addSecs(-1);
ui->countDown->setText(time.toString("m:ss"));
}
Now I need to be able to call a new method whenever the QTime reaches 0:00. I'm not very keen on adding an if on the updateCountdown method to check if the QTime is at 0:00 every second. I also thought maybe I could add a second QTimer that times out at 1 minute, but I'm not sure if both QTimer objects will start at the exact same time so the 1 minute timeout will happen exactly when the QTime object is at 0:00.
So is there a way to add a second timeout to the same QTimer object (to timeout once every second to update the countdown on screen and then a second timeout after 1 minute to end the game? I suspect the answer will be "no", but in that case, what would be the best approach? (if none of my options are valid, is there a better way to do it?).
The answer to your first question is no -- QTimer supports a single timeout (or a single specified time-interval, if it's not running in single-shot mode).
The answer to your second question is -- the best approach is the simplest one that can possibly work. Use a single QTimer, and in your updateCountdown() method, include an if statement to do something different when the countdown finally reaches zero. (Btw you don't really need to use a QTime object to represent the countdown; you could just as easily use an int that starts at 60 and is decremented until it reaches 0)
Why is this better/simpler? You could use two QTimer objects instead, but then you have to worry about keeping them in sync -- perhaps that's not a big deal for now, but what happens when you want to add a "Pause" button to your game, or when you want to add a time-bonus that gives the player 10 extra seconds of play time? All of a sudden, your 60-second timer will no longer be doing the right thing, and it will be a pain to stop and restart it correctly in all cases.
If-statements are cheap, and easy to understand/control/debug; so you might as well use one.
So I know in Qt, you can just put everything you want after a signal to happen into a slot, but when editting code later on; that can require a lot of restructuring, and may complicate things.
Is there a more simple way to hold your program until a signal is emitted in Qt, like say for example:
downloadImage();
Qt::waitForSignal(downloadImageFinished());
editImage();
Also; why doesn't something like this work:
// bool isFinished();
downloadImage(); // When done, isFinished() returns true;
while (!isFinished()) {}
editImage();
? Thanks.
Basically, you should do this:
QEventLoop loop;
connect(this, &SomeObject::someSignal, &loop, &QEventLoop::quit);
// here you can send your own message to signal the start of wait,
// start a thread, for example.
loop.exec(); //exec will delay execution until the signal has arrived
Wait inside a cycle will put your execution thread into a doom of spinlock - this shouldn't happen in any program. Avoid spinlocks at all cost - you don't want to deal with the consequences. Even if everything works right, remember that you will take whole processor core just for yourself, significantly delaying overall PC performance while in this state.
Here is how I use QTimer:
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->setInterval(1000);
timer->start();
Program monitors update() function and prints the current time in it. Normally it works as expected, it prints time at every second, but when program starts to process other jobs, there would be some breaks like 5 to 8 secs.
Qt Documentation mentions about accuracy issues like 1 ms, obviously I have another problem. Any ideas ?
QTimer (and all event-base message deliveries) is not interrupt driven. That means you are not guaranteed you will receive the event right when it's sent. The accuracy describes how the event is triggered, not how it's delivered.
If you are not doing threaded process on long job, call QCoreApplication::processEvents() periodically during the long process to ensure your slot gets called.
Your other jobs run for several seconds, and there's no event processing during these. You'd need to thread the jobs in order to get the responsiveness you want.