The code before Sleep() function doesn't work - c++

I have a simple Qt application - a window with text area (QTextEdit) in in. I print some text into that area, push the button and get the response depending on what has been typed in. Here is the slot responsible for what must be done for a certain input. Block else is doing just fine. But there is a problem with the if. I want it to close the app if the 'close it, please' it typed in. Before closing it shoud change the text in the text area. So there is a need for delay before closing. I tried to implement it with a cycle - doesn't work, it thinks hard and then closes anyway without showin the message.
If I use Sleep() it does the same - waits and closes without changing the text area. Why does it happen? The setText() command is before the Sleep() function, why isn't it implemented before sleep?
void Layout::text_slot()
{
QString s=m_texter->toPlainText();
if (s=="close it, please")
{
m_texter->setText("OK, my Lord!");
//for (int i=0;i<10000;i++)
//for (int j=0;j<10000;j++)
Sleep(1000*10);
QApplication::quit();
}
else
{
m_texter->setText("What 're you saying?");
}
}

Use QTimer::singleShot to wait
e.g.
void Layout::text_slot()
{
QString s=m_texter->toPlainText();
if (s=="close it, please")
{
m_texter->setText("OK, my Lord!");
// TODO: disable any user interaction here
// e.g. disable text input field
QTimer::singleShot(1000*10, qApp, SLOT(quit()));
}
else
{
m_texter->setText("What 're you saying?");
}
}

Related

QT: Run a function as long as button is toggled

I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}

Updating Qt Images does not work until exec is called

I need to create a simple GUI which displays images, the images in this example can change and the GUI will need to update it's contents.
I wrote the following update function in my widget class:
void myClass::updatePic() {
QPixmap pix("./pic.png");
int width = ui->picLabel->width();
int height = ui->picLabel->height();
ui->picLabel->setPixmap(pix.scaled(width,height,Qt::KeepAspectRatio));}
I try to use it in the following manner:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
myClass w;
w.show();
sleep(3);
w.updatePic();
sleep(3);
w.updatePic();
sleep(3);
return a.exec();}
But the window just opens and does not display the images until we get to the a.exec() line, and then it opens the last image. What am I doing wrong?
EDIT:
Clarification, the trigger for changing the images comes from an external program (specifically, the gui will be a node in ros, and will be triggered by another node). Is there a way to push a button not from the gui via an external program? the timer will work but I dislike this "busy wait" style solutions.
Thanks for the suggestions so far
exec runs the QT event loop, which includes rendering widgets.
So move your updatePic call into your widget and activate it by for example a button or in the show event
At first learn more about event loop. In particular, you must know that all events like paintEvent or resizeEvent are usually called on corresponding events handle. The events handle is usually called by the event loop, i.e. inside of exec function.
Let's unite answers of #MohaBou and #RvdK. You need to handle timer shots after the exec call. Use QObject::timerEvent for this.
myClass::myClass()
{
<...>
// This two variables are members of myClass.
_timerId = startTimer(3000);
_updatesCount = 0;
}
myClass::~myClass()
{
<...>
// For any case. As far as I remember, otherwise the late event
// may be handled after the destructor. Maybe it is false, do
// not remember...
if (_timerId >= 0) {
killTimer(_timerId);
_timerId = - 1;
}
}
myClass::timerEvent(QTimerEvent *event)
{
if (event->timerId() == _timerId) {
if (_updatesCount < 2) {
updatePic();
++_updatesCount;
} else {
killTimer(_timerId);
_timerId = - 1;
}
}
}
The startTimer method here adds especial timer event to the event query every 3 seconds. As all events, it may be handled only when the event loop will take control and all earlier events are handled. Because of it you can have a duration if many "heavy" events are handled.
EDIT: sorry, I didn't understand #MohaBou at first read. His answer with explicit QTimer is also good enough (but I still don't understand a part about modality).
The function exec also renders the child widgets. exec() blocks the application flow while show() doesn't. So, exec is mainly used for modal dialogs.
I recommend to update it in your custom witget by using a refresh timer. Use a QTimer to update the image every 3 secs:
QTimer* timer = new QTimer(this);
timer->setInterval(3000);
connect(timer, SINGAL(timeout()), this, SLOT(updatPicture()));
Update your picture in your custom slot:
MainWindow::updatePicture() {
updatePic()
}
If you want, you could use a lambda function:
connect(timer, &QTimer::timeout, this, [&w]() {
updatePic()
});

Serial connection does not work correctly with QPushbuttons

void CSerialController::sl_executeCommand(const QString s_command,QString&s_result){
QMutexLocker locker(mpo_mutex);
KT_Error t_error = ERROR_NONE;
QByteArray o_serialOutput;
QString s_serialAnswer = "";
char c_serialLetter = ' ';
// Port is already open
mpo_serial->clearBuffer(); // Flush and ReadAll
t_error = mpo_serial->sendStr(s_command); //
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
while ((t_error == ERROR_NONE) && (c_serialLetter != '\n')) // Reads Serial till newline is found
{
t_error = mpo_serial->getChar(c_serialLetter); // -> checks BytesAvailable -> if no bytes available -> waitForReadyRead(1) <- This is in a Loop while given time is over(Timeouttime)
o_serialOutput.append(c_serialLetter);
}
}
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
s_serialAnswer = o_serialOutput;
s_serialAnswer.remove("\r\n");
}
s_result = s_serialAnswer; }
Im working with C++ and Qt 5.5 and i cant get the serial connection to work correctly. Im using signals to connect a QPushButton with a slot in the CSerialController class which calls this function in the same class. I tried this function with a endless while-loop and it works correctly all the time. Its just not working when i use the buttons. First time i use a button it works correctly but the second time i press a button which calls this slot, the serialport only sometimes returns a value. (Writing works just not reading) I even tried changing the Thread of this class but that didnt help aswell. If you want i can post the sendStr and getChar functions aswell but like i said they work without a problem(allready used in a lot of projects)
UPDATE: I tried using the Windows API for the serial connection = problem is gone. Seems like a problem with QSerialPort usage on an old CPU (I7-870)

How to prevent a long process to hangs wxwidgets window

I have a wxwindows application and in the onclick event of a button, I have a very long process, for example I have something such as this:
for(int i=1;i<100;i++)
{
sleep(1000);
gaugeProgress->SetValue(i);
*textOutput<<i;
}
Running this code, stops UI to be responsive. I add
Refresh();
Update();
just after
*textOutput<<i;
but it did not work.
is there any way that I can pump the events?
I am working on Windows using VS 20102
In those cases I use wxYield() like this:
for(int i = 1; i < 100; i++)
{
// sleep() freezes the program making it unresponsible.
// sleep(1000);
gaugeProgress->SetValue(i);
*textOutput << i;
// wxYield stops this function execution
// to process all the rest of stocked events
// including the paint event and resumes immediately.
wxYield();
}
This stops the current process and lets the application to process the message stack like the paint event.
But I think that the proper way to do this should be using threads.
You can add a wxTimer member in your wxwindows, start it in the window constructor, as such:
m_timer.Start(1000);
then capture the timer event with a function, for example:
void mywindow::OnTimer(wxTimerEvent& event)
{
Refresh();
Update();
}
Make sure you connect the event to the wxTimer member.

FLTK Closing window

I am using FLTK. I have a window with a variety of buttons the user can click to perform some action. In my int main() i have a switch statement to handle all of these. When the user clicks exit the switch statement is setup like so:
case Exit_program:
cout << "save files and exit\n";
do_save_exit(sw);
This goes to the do_save_exit function that creates a exit confirmation window with two buttons yes (exit) and no (don't exit). I got the yes button to work, exits the program, but the no button mean i should just hide the confirmation window. This is the follow functions:
void yes(Address addr, Address)
{
exit(0);
}
void no(Address addr, Address)
{
}
void do_save_exit(Window& w)
{
Window quit(Point(w.x()+100, w.y()+100), 250, 55, "Exit confirmation");
Text conf(Point(15,15),"Do you really want to save and exit?");
Button yes(Point(60, 20),35,30,"Yes",yes);
Button no(Point(140, 20),35,30,"No",no);
quit.attach(conf);
quit.attach(yes);
quit.attach(no);
wait_for_main_window_click();
}
The problem is, when i click the no button it goes to void no, but I can't go anywhere from there. I just want to do quit.hide() but the no function doesn't have sight of the quit window (out of scope). How should I proceed? Thank you
P.S: I have thought about using a pointer to the quit window and then using the pointer to quit the window in the no function but am not sure how to do that exactly.
The Fl_Window callback is called when an attempt is made to close the window. The default callback hides the window (and if all windows are hidden, your application ends). If you set your own window callback, you can override this behaviour, so as not to hide the window:
// This window callback allows the user to save & exit, don't save, or cancel.
static void window_cb (Fl_Widget *widget, void *)
{
Fl_Window *window = (Fl_Window *)widget;
// fl_choice presents a modal dialog window with up to three choices.
int result = fl_choice("Do you want to save before quitting?",
"Don't Save", // 0
"Save", // 1
"Cancel" // 2
);
if (result == 0) { // Close without saving
window->hide();
} else if (result == 1) { // Save and close
save();
window->hide();
} else if (result == 2) { // Cancel / don't close
// don't do anything
}
}
Set your window's callback wherever you set up your Fl_Window, e.g. in your main function:
window->callback( win_cb );
You probably need to look at using a modal (i.e., dialog) window. Look at <FL/fl_ask.h>
if (fl_ask("Do you really want to save and exit?"))
save_and_exit();
The header also has functions for the popup's font, title, etc.
When you build you don't get an error or warning? The problem is probably that you have both global functions names yes and no and also local variables called just the same. Rename either the functions of the variables.
No need to use hide().
You can simply use exit(0); in a callback.