I'm attempting to build a program which takes any text file and turns it into a typing test. It has a timer that will display to the screen.
However, I can't figure out how to display the timer while actually running my game instructions. The timer works and displays the elapsed time but displaying the timer is the only thing it will do.
Can anyone give me some pointers of things that might be helpful for solving this problem?
QTimer has a signal timeout() which will be emitted after your interval time is elapsed. A QTimer unless specified as a singleshot runs again and again.
Let's assume you wish to do something every second, you can start a timer with interval 1000 (in msec). You can then connect its timeout signal to a slot. There you can specify how to go about doing stuff.
It's fine to run multiple timers at the same time. Also, for your initial implementation (for displaying the timer); you might want to take a look at QElapsedTimer.
Edit:
I found this example. It might provide you something to look at.
QTimer emits timeout() signal in every time interval specified by you unless it's a 'single-shot' timer.
If you want to display the elapsed time, connect the timeout() signal of your timer object to your slot which will display the time elapsed. Your slot will contain your logic to display whatever you want.
Related
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 am using a push button which records incoming microphone sound signal. Usually, the signal arrives a little late after pressing the record button and my recorded output contains zero until 10 ms(after which i receive an actual output). I am using the following QTimer function to set the delay but there is the ouput is the same,
QTimer->singleShot(0.010, this, SLOT(onStartRecordPushButton))
Are there any other methods to crop the signal for the first 10 ms or start recording only when a non zero signal arrive? Thanks
QTimer::singleShot takes milliseconds as an argument, not seconds.
Your call should probably look like this:
QTimer->singleShot(10, this, SLOT(onStartRecordPushButton))
I want to use a QMessageBox to announce a short waiting interval to the user.
QMessageBox* box(new QMessageBox(QMessageBox::Information,"Parser","Processing " + mFileName));
box->setStandardButtons(QMessageBox::NoButton);
box->setWindowModality(Qt::WindowModal);
box->show();
QApplication::processEvents();
parser.analyseFile(mFileName);
box->hide();
box->deleteLater();
QApplication::processEvents();
The function only takes few seconds.
The box gets displayed but neither the icon nor the text is shown in time before the function finishes. Why does QApplication::processEvents(); not prevent the program from continuation before the box is completely shown.
Is it possible to achieve the desired behaviour without resorting to threads.
Doing the processing in a separate thread would be preferable, since that would leave the GUI thread free to do things like handle mouse events, window resizes, etc, while the task is being completed; that way the GUI won't "freeze up" temporarily.
If you don't want to spawn a thread, however, you can call processEvents() periodically from within your analyseFile() function and that will give you roughly the same behavior. Try to call it at least every 50mS to avoid sluggish GUI response.
A second possibility might be to add a slot somewhere:
void MyClass :: ParseFile()
{
parser.analyseFile(mFileName);
box->hide();
box->deleteLater();
}
... and then invoke that asynchronously like this:
QTimer::singleShot(0, this, SLOT(ParseFile()));
... that might give the windowing system enough time to finish displaying the QMessageBox before ParseFile() executes, or it might not (in which case you could try to increase the delay argument from 0 to, say, 100 milliseconds instead). That's a little hacky, but it could work.
I'm New to QT. I understand that you can force a display refresh, but I've pulled all my hair out trying to figure out how. Here is what I'm specifically trying to do.
I press a button (onClick signal event), which runs code that changes an image (QLabel) on the display, waits for input, and then proceeds by changing a new image (different QLabel). I've tried everything and the display doesn't refresh until the onclick signal event code is complete. Right now, I'm not waiting for user input, I'm using usleep(~500 ms) for testing purposes.
From what I read, QT is event driven meaning that I'm basically creating a bunch of events, that get put in a que, and executed when the (onClick signal event) returns to the (main loop)/(event handler). I don't want to wait until the function is complete, it's going to make programming extremely painful if I have to accomplish this routine entirely based on events.
How can I force the QLabel pixmap to refresh. I've tried everything. Below is all the code I have tried in my onClick signal event handler. (upButton is the name of the QLabel which is a pixmap)
update();
repaint();
ui->upButton->setUpdatesEnabled(TRUE);
update();
repaint();
QPaintEvent paintevent(ui->upButton->childrenRegion());
QPaintEvent * test = &paintevent;
paintEvent(test);
this->changeEvent(test);
ui->upButton->update();
ui->upButton->repaint();
ui->upButton->repaint(ui->upButton->childrenRegion());
repaint();
QApplication::sendPostedEvents();
this->parentWidget()->update();
usleep(100000);
As you can see, I'm just shooting in the dark at this point. I've tried to look at sample code and do all my homework, but I'm lost. Appreciate any help, advice, and or sample code.
I was using sleep to emulate a brief amount of time the computer was waiting for something to happen.
As I stated in my question, I didn't want to use events because it's a whole lot of unnecessary work to accomplish something extremely simply.
Also, the 'event' that needs to take place for the program to continue, is a USB event. Since I'm using an HID class device, there is no way to set an event to happen without a wait loop. USB HID classes don't permit setting interrupts, the OS claims the device.
I managed to get the above to work. I walked through the debugger and noticed the display would refresh before the sleep function. Running the program independently, I got random results with the display refreshing 1% of the time. I got rid of the sleep function, and added some other code in it's place to emulate a delay, and it was fine.
Just for everyone's knowledge, this is possible, it's not forbidden, and it's easy to do with the following:
qApp->processEvents();
qApp is a global external variable in the QApplication header.
Because this USB event is making my flow tricky, I stumbled upon the QWaitCondition Class. I was going to start a process waiting for the USB event. I would wait until the process releases the wait condition for my routine to continue.
But if anyone thinks this is a bad idea, please, speak out. I really do appreciate your feedback PiedPiper and Hostile Fork.
Thank you.
I noticed sometimes when you have multiple layered widgets, or widgets inside of widgets it helps to call their repaint() events.
For example
this->repaint();
this->parentWidget()->repaint();
this->parentWidget()->parentWidget()->repaint();
This is far easier then pushing out any processing to another Thread, or creating additional event handlers.
You shouldn't be waiting for input in your event handler. You need to rethink the logic of your program to use events the way they were intended. All the update() and repaint() calls in your code are unnecessary if you return to the event loop.
If i understood correctly, you have a slot and in this slot, you update the image shown in a QLabel. But you want this change to be displayed before the slot finishes.
If that is the case, issue an update() event, and call qApp->processEvents(). This method processes events that are waiting in the event queue and then returns, therefore this may be what you are after.
PS: an update() may not be necessary at all, i am not sure.