QT update Linedit at runtime - c++

I am trying to update the text on my linedit every time I get a frame, but my program crash. I tried doing the same with a loop, but the window shows only after the loop has finished. setH() is my slot, in Debug mode it run perfectly, the problem is when trying to update the text in LineEdit while the programm is running(the mainwindow is on the screen) . Thank you
void MainWindow::updatehand(){
if (controller.isConnected()){
int hc =frame.hands().count();
QString hndc= QString::number(hc);
emit hChanged(hndc);
}
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
updatehand();
}

It is the reason for the crash:
connect(this, SIGNAL(hChanged(const QString)), this, SLOT(setH(const QString)));
Such connection is acutally a direct function call. The function setH() is called in place of emit hChanged(hndc);. Then the function updatehand() is called from setH().
It is an infinite loop with the stack overflow crash.
If you want to call updatehand() 60 times per seconds it is possible to called using QTimer, for example with QTimer statics memember:
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
QTimer::singleShot(1000 / 60, this, SLOT(updatehand()));
}
Here updatehand() is also a slot.
In that case the even loop continues to dispatch UI messages after return from setH().
Approximately after 16 ms the timer will call updatehand().
The above solution technically breaks the infinite cross-refernce loop. However, it can be done better. There is a risk that setH() will be triggered many times from the external caller. In that case many timers will be activated.
It looks that you need just one QTimer instance to call periodiacally updatehand() independently of setH(). So, updatehand() can be pooled with given period to updated data. It can call setH() directly, the setH() function only sets the QLineEdit text:
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
}

Related

QPropertyAnimation not running immediately when QAbstractAnimation::start() is called

I am trying to make a simple multi-page widget with QStackedWidgets in Qt Creator with Qt 4.8.6. The goal is to have a QLabel and QProgressBar fade away after the progress bar reaches full value. I thought the best way to achieve this was using QGraphicsOpacityEffect and QPropertyAnimation in tandem as seen below.
void MainWindow::AnimateStartScreen()
{
//QSound::play("./Audio/THX-DeepNote-48Khz.wav");
sleep(5);
logoEffect = new QGraphicsOpacityEffect();
logoAnimation = new QPropertyAnimation(logoEffect, "opacity");
ui->startLogo->setGraphicsEffect(logoEffect);
logoAnimation->setDuration(2000);
logoAnimation->setStartValue(1);
logoAnimation->setEndValue(0);
logoAnimation->start();
progressBarEffect = new QGraphicsOpacityEffect();
progressBarAnimation = new QPropertyAnimation(progressBarEffect, "opacity");
ui->startProgressBar->setGraphicsEffect(progressBarEffect);
progressBarAnimation->setDuration(2000);
progressBarAnimation->setStartValue(1);
progressBarAnimation->setEndValue(0);
progressBarAnimation->start();
sleep(3);
}
Which is then called by the main method:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.HideTitleBar();
w.CenterWidget();
//QMainWindow::showFullScreen();
w.show();
w.IncrementProgressbar();
w.AnimateStartScreen();
w.ChangePageTo(1);
return a.exec();
}
Here lies the problem. I want this animation to finish before I change the page like so:
void MainWindow::ChangePageTo(int page)
{
ui->stackedWidget->setCurrentIndex(page);
}
Is there a way I can delay page change until my animation is complete? When I comment out the page change, the animation doesn't seem to even start until QApplication::exec() is called in my main method, evident by a 8 second waiting period (the combination of both sleep calls), rather than a 5 second delay before QAbstractAnimation::start() is called.
I believe what is happening is that the sleep(3) line is stopping the thread in which the GUI is running on, hence delaying the start of the animation for three seconds. When the sleep call has completed, I wonder if the animation tries to continue, but because of the page change,there is just no visible effect from the quick transition.
How can I make a 3 second delay without stopping the thread that the animation is running off of? Or are there any other suggestions that will produce the same effect?
I believe what is happening is that the sleep(3) line is stopping the thread in which the GUI is running on
Almost certainly. For the animation to run you need to keep the message queue running which, in the code you've posted, won't occur until the subsequent call to a.exec().
If you really need to block execution of MainWindow::AnimateStartScreen until the animation has completed then perhaps a better idea would be to replace the call to sleep(3) with...
while (progressBarAnimation->state() != QAbstractAnimation::Stopped)
QCoreApplication::processEvents();
(Although you might have to play about with the flags pass to QCoreApplication::processEvents to get the precise behaviour you require.)
Use next pattern for non-blocking waiting (instead of sleep):
QEventLoop loop;
connect( progressBarAnimation, &QAbstractAnimaion::finished, &loop, &QEventLoop::quit );
loop.exec();

QLabel not updating from slot call

My QLabel is not updating from slot. I run sender class in separate thread using QObject::moveToThread:
QThread* serviceThread = new QThread;
service = new ExportService();
connect(service,SIGNAL(stateChanged(Service::ServiceState)),
this,SLOT(statusChanged(Service::ServiceState)));
service->moveToThread(serviceThread);
serviceThread->start();
Service object send states by emiting signal with ServiceState enum value, this signal is captured by QDialog slot:
void Dialog::statusChanged(Service::ServiceState s)
{
switch (s) {
case Service::IDLE:
qDebug() << "Idle";
ui->label->setText("Service send response succesfully.");
break;
case Service::REQUESTING:
qDebug() << "Requesting";
ui->label->setText("Requesting response from service...");
break;
case Service::ERROR:
qDebug() << "Error";
ui->label->setText("Error. Cannot get response from service.");
break;
default:
break;
}
}
After operation on the object which emits a signal twice, the first time with value of Service::REQUESTING and second time with value of Service::IDLE my QLabel change text only to "Service send response succesfully.". In the console I can see that qDebug() << "Requesting"; works so the state changed successfully.
After comment out ui->label->setText("Service send response succesfully."); label has changed to requesting state but after the whole operation was done ie i see "Requesting" in console then "Idle" and after that QLabel has changed.
What should I do if I want to see QLabel changing in realtime?
First, try adding update() after setText(), chances are setText() doesn't automatically schedule a repaint() for the QLabel, if it works then problem solved.
However, for update() function:
http://doc.qt.io/qt-4.8/qwidget.html#update
void QWidget::update()
This function does not cause an immediate repaint; instead it
schedules a paint event for processing when Qt returns to the main
event loop. This permits Qt to optimize for more speed and less
flicker than a call to repaint() does.
> Calling update() several times normally results in just one
paintEvent() call.
which basically says, if you call them too frequently and some of them will be optimized away.
If this is not the desired behaviour, try adding a forced repaint() after setText(), or using a timer to schedule periodical forced repaints.
http://doc.qt.io/qt-4.8/qwidget.html#repaint
UPDATE
As is mentioned in the comment, forcing repaint() isn't good solution.
This answer is intended to provide an analysis of the cause of the code's behaviour and the "forced repaint()" suggestion is more of a way to verify this analysis than a solution to the problem.
However, without further information on the purpose of the program, it's very difficult to provide further suggestions.
The status change from requesting to idle happens quickly. The text "Requesting response from service..." is not on the label long enough for the eye to see it.
The fact that "Requesting ..." is in the debug output is proof of this, but if you want more proof there are other things you could do:
use a counter that counts each time the statusChanged() function is called and display this either in the same label as the status text (in addition to the status text) or a different label.
add a high accuracy timer output to the debug outputs - see how close together the status changes are.
use a couple of check boxes, one for idle status and one for requesting status. Change their state when the appropriate status is received. That is whne the first Idle is received set the check box to checked. When the next idle is received toggle it to unchecked.
I would just accept that the debug outputs are telling the truth and move on.

Qt - GUI freezing

I wrote in C++ a solver for the 8-puzzle game, and now I'm trying to use Qt to give it a GUI.
Basically I have an underlying object of type "Board" which represents the board of the puzzle, and I have organized the GUI as a grid of QPushButton. Then I have a method updateUI which associates to every button the correct text, based on the Board. Something like
for(int i=0; i<Board::MATRIX_DIM * Board::MATRIX_DIM; i++)
{
m_buttons[i]->setText(m_values[i]);
}
In another method (solveGUI) I have
void MainWindow::solveGUI()
{
m_game->solve();
int solutionDepth = m_game->getSolutionDepth();
Move *solutionMoves = m_game->getSolutionMoves();
for(int i=0; i<solutionDepth; i++)
{
Move m = solutionMoves[i];
m_board.performMove(m); /* perform the move on the Board object */
updateUI(); /* should update the GUI so that it represents the Board */
Sleep(1000);
}
}
where the first line (m_game->solve) takes some time. Then I obtain a list of the moves performed, in solutionMoves, and what I would like to do is showing this moves on the board, with some delay between a move and the next one. This method is called by my main, which looks like this:
QApplication app(argc, argv);
MainWindow w;
w.show();
w.solveGUI();
return app.exec();
The result is that the GUI hangs and, after some time, it displays only the solution, completely skipping the moves.
What am I missing? Thank you!
P.S. I don't think I need a different Thread for the solver because I want the solver to run before the solution is displayed. Is it right?
It's app.exec() that actually runs the main loop which handles all events, including displaying GUI. If you want to call solve() before that, it's OK, but if you want to actually display and update GUI before exec(), it's wrong. I'm not sure if it's totally impossible, but it's definitely not the right way to do it.
There are two ways around it. The more canonical way is to redesign a program using a QTimer. Then everything will be smooth and responsive. But that can be tedious sometimes. In your case it should be quite easy, though. Just save the results somewhere, and call a slot using a QTimer object every 1000 seconds - it will have the same effect as your Sleep(), but will keep everything responsive.
The other solution is to call your solveGUI() method after exec() starts its job. It can be done, for example, using QTimer::singleShot():
QTimer::singleShot(0, &w, SLOT(showGUI()));
return app.exec();
Then, before each Sleep(), you should call QApplication::processEvents(), which basically allows you to temporary yield control, processing all pending events, including GUI updates. This approach is somewhat easier, but it's inferior since the GUI still freezes at each Sleep(). For example, if the user wants to exit the application, or if the window is needed to be repainted, it will cause uncomfortable GUI lags.
You're stalling the main thread (which also does the event processing) and rendering it uncapable of responding to keyboard/mouse/window messages.
You should use an asynchronous timer operation instead of the sleep function: use a QTimer to delay showing the next solution and avoid messages being left unanswered for too long.
There is a nice article of methods to keep the GUI responsive during processing loops. if it's not a complicated case I think, just insert QCoreApplication::processEvents(); inside the long processing loops.
try the following:
void MainWindow::Wait(int interval ) {
QTime timer = new QTime;
timer.restart();
while(timer.elapsed() < interval) {
QApplication::processEvents();
}
}
...
for(...) {
//wait 1 second (1000 milliseconds) between each loop run at first
Wait(1000);
...
}
...
not tested yet - but should work (maybe there is some cpu load)!

Qt/C++: Checkable button and infinite loop

I'm coding a Qt Gui and I'm trying to implement a new feature, I now the precise result I want to arrive at but not how to code it.
I'm trying to add a checkable button that when checked would run a function that would only stop when the button is unchecked, but every second a PaintArea I have on the window would be updated (letting me see how the multiple executions of my function are changing my data). It seem that I'll need to use some QThread objects, but just the part dealing with the button is already counter intuitive to me, I've been trying to play with the autoRepeatDelay and autoRepeatInterval without getting my hand on what they do and how they could be useful to me.
I guess that what I'm trying to code is not really original, would have an idea of the steps to implement it, or an example of a code?
Edit:
According to the first answers (thank you for them by the way) my question may not be clear. Putting on the side the thread thing, I'd like to implement an infinite loop that only starts when a pressbutton goes to pressed position (it's a checkable button) and stops only when leaving it. The first version I tried to do (with a while(button->isChecked() loop) would completely freeze as the application would be running the loop, the gui would freeze and the button couldn't be turned off (hence the idea of running it in a separate thread). Voila! I hope it's a clearer formulation. Thank you in advance.
Here's a simple skeleton of something that might work. Without knowing your exact requirements, it may or may not be right for your problem. Hopefully it will give you a few hints that do actually help.
void Ui::buttonPressedSlot(bool checked){
if (checked){
Processor *processor = new Processor;
connect(this, SIGNAL(abortCalculations()), processor, SLOT(abort()), Qt::QueuedConnection);
connect(processor, SIGNAL(updateNeeded()), this, SLOT(updateGui()), Qt::QueuedConnection);
QThreadPool::globalInstance()->start(processor);
} else {
emit abortCalculations(); // this is a signal in your UI class
}
}
You can then use the following for your calculations.
class Processor : public QObject, public QRunnable{ // QObject must always be first in multiple inheritance
Q_OBJECT
public:
~Processor();
void run();
public slots:
void abort();
void doCalculations();
signals:
void updateNeeded(); // connect this to the GUI to tell it to refresh
private:
QScopedPointer<QEventLoop> loop;
};
Processor::~Processor(){
abort();
}
void Processor::run() {
loop.reset(new QEventLoop);
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(doCalculations()));
timer.setInterval(1000);
timer.start();
loop->exec();
}
void Processor::abort(){
if (!loop.isNull()){
loop->quit();
}
}
void Processor::doCalculations(){
// do whatever needs to be done
emit updateNeeded();
}
I don't know if I really understand what you want to do, but I will try to answer.
First, you want a Button that send a start & stop info to control a thread. You can use a checkbox to begin. This check box send a signal when its state changes. Connect this signal to a slot that perform start thread and stop according to the boolean sent.
Second, in you thread you need to launch the events loop. After, set a timer that call you repaint after every timeout.
Hope it helped.
PS: take care of execution context with you thread and Qt's objects.

Update Qt GUI in Loop ( show Bitmap image as movie )

i receive screenshot as bitmap from socket and when i show only one of them it work
but when i put in loop ( show all receive image to make movie) i get hang
void ShowImageBuffer(char* buf,int sizeofimagebuffer )
{
QByteArray byte=QByteArray::fromRawData(buf, sizeofimagebuffer );
QPixmap image;
if(image.loadFromData(byte,"BMP"))
{
ui->label->setPixmap(image);
ui->label->update();
}
}
while(1)
{
ShowImageBuffer(buf, sizeofimagebuffer)
}
i must use separate thread?( but i think we will not use any thread to change GUI?)
what is best to make it real time?
The problem I suppose is that you're not returning to the event loop this way. The update() method you're using doesn't repaint the QWidget immediately. It schedules a request to update the area, which is unified with other pending requests if any is available. This request is processed when the execution returns to the event loop. It is clearly stated in the documentation.
You might want to use a QTimer and invoke the ShowImageBuffer method at a specific frame rate. When the ShowImageBuffer is finished, execution returns to the event loop thus giving the time to process the update() request. Also consider the improvement suggested by AJG85.
Otherwise you can have a look at the repaint() method which immediately invokes the paintEvent() method, but still I suppose you should set a specific frame rate to get a good result. I would go with the QTimer way.