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()));
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();
Hello I know how to create a progressBar with Gtkmm. I know also with a button how when I click on the button the progressBar increase of 10% for instance. But I don't know how to implement a progressBar which increase automatically I mean like this :
for(int i = 0; i<=10; i++){
double percentage(progressBar.get_fraction() + 0.1);
progressBar.set_fraction(percentage);
getchar();
}
But I don't see when the progressBar increases... I just see when the progressBAr is full...
Thank you for your help !
When you want to use a progress bar (or spinner, etc.) that should actually change its appearance, you need to ensure that the main thread gets some time to update the UI accordingly.
If you have a loop in main thread that sets new values and blocks the thread in getchar(), this thread cannot update the UI to reflect the new state of any widget.
To see your updates you should move the loop calling getchar in some other thread and only do the gtk_* function call in the main thread. This can be achieved by enqueing an update-function via g_idle_add().
Then the UI can be updated while your thread is blocked.
If you replace getchar by some other action that takes some time, this other activity will also prevent the thread from updating the UI unless you move it in some other thread.
You might also think about other mechanisms to return control back to the main thread between updating the widget's state.
In my application I want to display some image with this code
myImage = scene->addPixmap(image);
myImage->setOffset(x, y);
Then I want to sleep for some seconds:
std::this_thread::sleep_for(std::chrono::seconds(2));
and then display another image. But this code waits for 2 seconds at first and then displays both images at once. How can I make the program wait between displaying those two images?
Use QTimer::singleShot() and connect it to a slot that updates the picture:
class MyObject : public AQObjectInheritingClass
{
Q_OBJECT
...
public Q_SLOTS:
void changeImage()
{
//change image here
}
And in instead of sleep_for():
QTimer::singleShot(2000, &instanceOfMyObject, SLOT("changeImage()");
Two seconds later, changeImage() will be invoked.
You cannot sleep in event based application (GUI applications are event-based). Event based applications have main loop, that has to be running to process events, and update its state. Calling sleep_for stops that main loop, so your app doesn't process events so it doesn't react to input and doesn't repaint itself. That's why all drawing if deferred fot two seconds then flushed at once.
As an alternative, you should use timers, such as QTimer
there is Qt-specific non-blocking way to pause thread with QEventLoop:
QEventLoop loop;
QTimer::singleShot(1000,&loop,SLOT(quit()));
loop.exec();
While loop is being executed, all other events for this thread are processed.
I have a GUI Button that calls a shell script to start recording a video. In addition I want a slider to show progress of recording (maximum recording time is 30 seconds). I build the following function:
coid MainWindow::on_recordStart_clicked()
{
QElapsedTimer timer;
QProcess *Prozess = new QProcess();
Prozess->start("record.sh");
timer.start();
for(;;)
{
ui->timelineLabel->setText(QString::number(timer.elapsed())); //label
ui->timeLine->setValue(timer.elapsed()); //slider
if (timer.hasExpired(30000)) break;
}
It only updates the Slider and Label after the break. Anyone knows why?
Your main (UI) thread is busy iterating through your for loop and won't be able to handle the events to update your label.
There is one quick and dirty solution (not tested), add the following line after setValue:
QCoreApplication::processEvents();
The nicer solution would to move the process handling to a separate thread and notify the main thread about the progress via a signal/slot.
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.