Stop qt application in infinite loop when main window is closed - c++

My main application class is USB_Packet_Analyzer which processes some files, but also supports reading from a file to which somebody still writes. In that case, I have an infinity loop which checks whether something new was written in this file and if so, I continue in processing. In every iteration of loop I am calling QCoreApplication::processEvents();.
The problem is that when I close main window of app, it wont stop the application. If I check QApplication::topLevelWidgets().size() it is still 1, and QApplication::topLevelWidgets().at(0)->isVisible() is false. Why isn't it closing my window? Can I connect some signal to detect whether red cross on window was clicked or not? I know that when getting into this kind of loops i might use QThread, but I'd rather not get this involved. Is there any solution for my problem?

Take a look at the QFileSystemWatcher Class and its fileChanged signal.
#include <QFileSystemWatcher>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QFileSystemWatcher* fileWatcher;
Ui::MainWindow*ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
createUi();
fileWatcher = new QFileSystemWatcher(this);
connect(fileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChangedSlot(QString)));
QFileInfo file("file_to_watch.txt");
if (file.exists())
{
fileWatcher->addPath(file.absoluteFilePath());
}
}
void MainWindow::fileChangedSlot(const QString &path)
{
if (fileWatcher->files().contains(path))
{
qDebug() << "File changed" << path;
}
}

You can using of system interrupt signal to manage a Boolean to breaking your infinite loop or exiting the application.
e.g:
#include <iostream>
#include <csignal>
using namespace std;
void InterruptSignalHandler(int signal_number) {
cout<< "Signal Number is "<<signal_number<<endl;
exit(signal_number);
}
int main()
{
signal(SIGINT, InterruptSignalHandler);
string a;
while(true)
{
cout<<">";
cin >> a;
}
return 0;
}

Related

How do you run a function in the background of your program (Specifically an autosave function)? QT / C++

In my code I would like to integrate an auto-save function that runs every couple seconds or so. I would like this to run in the background because I have other stuff that I am going to be running at the same time. So how would I do this?
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <fstream>
#include <QFile>
#include <QDebug>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
// Setup code
ui->textEdit->setReadOnly(true);
ui->textEdit->append("Select one of the buttons on the left to pick a log");
}
MainWindow::~MainWindow() {
delete ui;
}
string lastSavedText[] = {
" ",
" "
};
QString qLastSavedTextHome, qLastSavedTextWork;
This is my first button
void MainWindow::on_homeButton_clicked() {
// Preparing text edit
ui->textEdit->setReadOnly(false);
ui->textEdit->clear();
ui->textEdit->setOverwriteMode(true);
// Loading previously saved text
QFile file { "home.apl" };
if ( !file.open(QIODevice::ReadOnly | QIODevice::Text) ) {
qDebug() << "Could not open file!";
return;
}
const auto& lastSavedText = file.readAll();
file.close();
ui->textEdit->setPlainText( lastSavedText );
}
This is my second one
void MainWindow::on_workButton_clicked() {
// Preparing text edit
ui->textEdit->setReadOnly(false);
ui->textEdit->clear();
ui->textEdit->setOverwriteMode(true);
// Loading previously saved text
QFile file2 { "work.apl" };
if ( !file2.open(QIODevice::ReadOnly | QIODevice::Text) ) {
qDebug() << "Could not open file!";
return;
}
const auto& lastSavedText = file2.readAll();
file2.close();
ui->textEdit->setPlainText( lastSavedText );
}
This is the save button I hope to eliminate with an autosave
void MainWindow::on_saveButton_clicked() {
// Converts textEdit to string
QString textEditText = ui->textEdit->toPlainText();
lastSavedText[0] = textEditText.toStdString();
// Saving files
ofstream home;
home.open("home.apl");
home << lastSavedText[0];
home.close();
ofstream work;
work.open("work.apl");
work << lastSavedText[1];
work.close();
}
There is 2 solutions.
Easy one
Use simply a timer that will execute the code of your save button. You can set the timer to execute any period of time.
QTimer
But this might cause the software to freeze if this operation takes too much time. In which case, you can put the function that saves inside a thread.
Threads
You can use threads to do that.
Thread, is basically a process that will detach from your main process and can be run at the same time, each thread doing its own work.
Note that to communicate between thread, the safest method is to use signals.
Qt Threads Documentation
Example
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
You can use a QTimer with QtConcurrent::run, and then you get the simplicity with the benefit of running the saving on a different thread you don't need to manage.
Practically, try
QTimer::singleShot(time, this, Qt::TimerType::CoarseTime, QtConcurrent::run(this,&MainWindow::on_saveButton_clicked));
Here's a first approximation using a background thread (for the sake of brevity, it inherits QThread - for your real application, consider decoupling the QThread base-class from this worker thread object. That will also make it possible to give a father-object for t).
class Thread: public QThread {
Q_OBJECT
public:
Thread(QTextEdit *textEdit):textEdit(textEdit) {
QTimer *t = new QTimer;
connect(t, SIGNAL(timeout()), SLOT(saveOnce()));
t->moveToThread(this);
t->start(2000);
}
protected:
QTextEdit *textEdit;
std::string lastSavedText[2];
private slots:
QString text() const { return textEdit->toPlainText(); }
void saveOnce() {
QString textEditText;
QMetaObject::invokeMethod(this,
"text", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QString,textEditText));
lastSavedText[0] = textEditText.toStdString();
// Saving files
ofstream home;
home.open("home.apl");
home << lastSavedText[0];
home.close();
ofstream work;
work.open("work.apl");
work << lastSavedText[1];
work.close();
}
};
Care must be taken, when taking this approach with BlockingQueuedConnection, that the thread does not call invokeMethod while the main thread is waiting for it to exit - then a deadlock happens because the main-thread cannot process the text() queued call anymore.

Modal Dialog hangs after accept, done, or close is called

I have a modal dialog called by:
qDebug() << "Creating LoginStatusDialog";
dlgConnectStatus = new LoginStatusDialog(login, key, auth);
qDebug() << "Done LoginStatusDialog, setting modal";
dlgConnectStatus->setModal(true);
qDebug() << "Done setting modal, executing";
int res = dlgConnectStatus->exec();
qDebug() << "dlgConnectStatus result = " << QString::number(res);
//see below for debug info and output
This calls a custom constructor which executes this below
LoginStatusDialog.cpp (extract):
LoginStatusDialog::LoginStatusDialog( QString _login, QString _key, QString *_auth_tok, QWidget *parent) :
QDialog(parent), ui(new Ui::LoginStatusDialog), login(_login), key(_key)
{
ui->setupUi(this);
Return_Object = new ReturnObject(ReturnCode::netcon_LoginSuccess, QString(""));
if (Return_Object->getCode() == ReturnCode::netcon_LoginSuccess) {
qDebug() << "pre close";
close();
//accept - hangs
//done(0); - hangs
qDebug() << "post close";
}
}
LoginStatusDialog header
#ifndef LOGINSTATUSDIALOG_H
#define LOGINSTATUSDIALOG_H
#include <QDialog>
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <thread>
#include "returnobject.h"
#include "datamanager.h"
namespace Ui {
class LoginStatusDialog;
}
class LoginStatusDialog : public QDialog
{
Q_OBJECT
public:
// explicit LoginStatusDialog(QWidget *parent = 0);
LoginStatusDialog( QString _login, QString _key, QString *_auth_tok, QWidget *parent = 0);
~LoginStatusDialog();
private:
Ui::LoginStatusDialog *ui;
QString login, key;
ReturnObject *Return_Object;
void initGui();
};
#endif // LOGINSTATUSDIALOG_H
Debug info
Debugging starts
Creating LoginStatusDialog
pre close
post close
Done LoginStatusDialog, setting modal
Done setting modal, executing
//remains open
By doing some research, several SO posts refer to using done(), close(), accept() to close the dialog
Using a CONNECT() uses the close() method to close the dialog, but attempting to manually close it has no success.
It was suggested to use a timer task, but that just does not seem like the actual way to close the dialog.
Any thoughts?
This seems more like a general design issue. If you truly want it done that way you could use a timer. But a simple redesign may be more helpful.
If you only want the dialog to be shown when an error occurs why not only show it only then?
Return_Object = new ReturnObject(ReturnCode::netcon_LoginSuccess, QString(""));
if (Return_Object->getCode() != ReturnCode::netcon_LoginSuccess)
{
dlgConnectStatus = new LoginStatusDialog(Return_Object);
dlgConnectStatus->setModal(true);
int res = dlgConnectStatus->exec();
//...
}
This way, the dialog who is responsible for only showing the information will only do this. Show the login error. It just seems like a design flaw for creating a dialog then immediately closing it (especially considering that the good case should be your default case).
If you have extra things the Dialog is doing you should consider how much of that code really needs to be in a class intended to be for showing information.
Calling close from constructor is wrong, cause your dialog is showing after constructor ends, so your check can't close dialog, that wasn't showed. You need to call close after(in) QDialog::showEvent. Or, just as I say in your first theme - you can use timer loop.

Qt Creator crashes when using multiple threads

I'm writing a Qt (5.3) program which has a joystick test UI in it, but I need a separate thread for an infinite while loop looking for joystick axis/button value changes through SDL. That part of the code is working fine as I can have the thread qDebug() messages and it seems to work. But from the main window, when I try to open the test joystick UI, the program crashes. I've had the test joystick UI running separation WITHOUT the JoystickThread thread and it seems to open up fine.
The error messages are inconsistent though - some times, I just get
The program has unexpectedly finished.
/home/narendran/QtWorkspace/build-LinkControl-Desktop-Debug/LinkControl crashed
This has shown up once:
QXcbWindow: Unhandled client message: "_GTK_LOAD_ICONTHEMES"
And a few other times:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
star: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
I found that this was common if XInitThreads(); is not run in the main function, but even with it on there, it crashes with the same error(s).
main.cpp
#include <qsplashscreen.h>
#include "linkcontrol.h"
#include "configure.h"
#include <unistd.h>
#include <QApplication>
#include <QPixmap>
#include <QStyle>
#include <QDesktopWidget>
#include "linkports.h"
#include "joystickthread.h"
#include <X11/Xlib.h>
int main(int argc, char *argv[])
{
XInitThreads();
QApplication a(argc, argv);
QPixmap pix(":splash.png");
QSplashScreen splash(pix);
splash.show();
a.processEvents();
JoystickThread jsThread;
jsThread.start();
LinkControl linkcontrol;
usleep(1000000);
splash.finish(&linkcontrol);
usleep(100000);
linkcontrol.show();
linkcontrol.setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter,linkcontrol.size(),a.desktop()->availableGeometry()));
return a.exec();
}
The actual thread is in joystickthread.cpp
#include "joystickthread.h"
#include "global.h"
#include "unistd.h"
/* JoystickThread::JoystickThread(int _interval)
{
this->interval_us = _interval;
} */
void JoystickThread::run()
{
while(1)
{
if(joystick->connected)
{
joystick->updateJSData();
// Check for changed values
for(int i=0; i<joystick->axis.count(); i++)
{
if(joystick->axis.value(i) != joystick->axis_last[i])
{
joystick->axisUpdateEmit(i);
// qDebug() << "AXIS: " << i << "\tVALUE: " << joystick->axis.value(i);
}
joystick->axis_last[i] = joystick->axis.value(i);
}
for(int i=0; i<joystick->button.count(); i++)
{
if(joystick->button.value(i) != joystick->button_last[i])
{
joystick->btnUpdateEmit(i);
// qDebug() << "BUTTON: " << i << "\tVALUE: " << joystick->button.value(i);
}
joystick->button_last[i] = joystick->button.value(i);
}
}
usleep(2500);
}
}
The function that causes the program to crash is in linkcontrol.cpp
void LinkControl::on_actionJoystick_Test_triggered()
{
qDebug() << "STARTING CHECK";
if(!js_test->initialized) {
qDebug() << "NOT INIT";
js_test = new TestJoystick();
js_test->initialized = true;
qDebug() << "FININSH INIT";
}
if(joystick->connected) {
qDebug() << "SHOWING UI";
js_test->show();
} else {
QMessageBox::critical(this, tr("No Joystick Connected!"), tr("Please connect a joystick first..."));
}
}
Where js_test is declared as a TestJoystick object in the linkcontrol.h file
public:
explicit LinkControl(QWidget *parent = 0);
QSlider *portSliders[16];
QLineEdit *setVals[16];
SerialTerminal *ser_term;
TestJoystick *js_test;
~LinkControl();
Thank you very much! Please let me know if you need anymore information.
QThreads are a little tricky to get used to initially, and have their share of gotchas.
You should construct and connect appropriate items at the top of your run function.
If you do it other places, you need to make sure that you don't use Qt::AutoConnection, but instead use Qt:QueuedConnection.
http://qt-project.org/doc/qt-5/qt.html#ConnectionType-enum
Certain elements are only accessible from the "GUI" thread or the main thread of the program. This is the thread that has QApplication::exec(); ran on. It has an event loop that propagates messages around.
Look at the Application output for runtime errors that Qt will tell you about.
When crossing thread boundaries, be sure to use signals and slots.
And if you are accessing a member of your thread class from outside that thread, be sure to use thread synchronization, practices, such as prefacing all access to these members with QMutexLocker locker(m_mutex);.
http://qt-project.org/doc/qt-5/threads.html
And as implied by the title "GUI thread", it is the only thread that is allowed to do certain things such as drawing QPixmaps and accessing certain parts of QWidgets.
Hope that helps.

how to restart an application in qt?

I do this works for restarting my game but program has error .I want to show a QDialog when user losses .In this QDilag i put two pushbutton for retry and exit.also i have a QDialog for beginning of game.Where is my mistake? (I read similar questions and do according these but yet i have problem)
extern int const EXIT_CODE_REBOOT;
mydialog_end::mydialog_end(QWidget *parent) :
QDialog(parent
{
retry=new QPushButton(this);
exit=new QPushButton(this);
retry->setText("RETRY");
exit->setText("EXIT");
connect(retry,SIGNAL(clicked()),this,SLOT(on_retry_clicked()));
connect(exit,SIGNAL(clicked()),this,SLOT(on_exit_clicked()));
}
void mydialog_end::on_retry_clicked()
{
qApp->exit(EXIT_CODE_REBOOT);
accept();
}
void mydialog_end::on_exit_clicked()
{
//what do i do for end of game?
reject();
}
//////////////in class myenemy///////
public slots:
void loss();
void Myenemy1::loss()
{
if(this->collidesWithItem(_mario))
{
//do something....
mydialog_end dialog;
dialog.exec();
}
}
//////////////in main////////////
extern int const RESTART_CODE;
int main(int argc, char *argv[])
{
Mydialogstart dlg;//a dialog for beginning game
int state= dlg.exec();
int return_from_event_loop_code=0;
do
{
QApplication a(argc, argv);
MainWindow w;
if( state==QDialog::Accepted)
{
w.show();
qDebug()<<"accepted";
}
else if(state==QDialog::Rejected)
{
qDebug()<<"rejected";
dlg.close();
return 0;
}
return_from_event_loop_code = a.exec();
} while(return_from_event_loop_code==RESTART_CODE);
return return_from_event_loop_code;
}
You can use QProcess::startDetached to run an instance of your application in a new process and detach from it. After that you should exit the application :
QProcess process;
process.startDetached("myApp",QStringList());
qApp->quit();
Here myApp is the name of the executable file of the application. On Windows it can be myApp.exe.
On this one, I would make a little inception... let's say your main application is called A then you should run A in a global B application. When A crashes, B throws the QDialog. If the use click on Retry then kill the old instance of A and start a new one.
There is a Qt Wiki entry that explains what you need to do in quite a lot of detail.
As it seems you have at least partially taken inspiration from there, but from what you post here, you seem to have never initialized the values for EXIT_CODE_REBOOT and RESTART_CODE in your code sample, or at least linked them to one another (which I would expect you'd want to do in some way)

I just don't understand threads in Qt

Okay, so, here's the deal.
I'm currently writing a small chat messaging simulation / project using SysV IPC, and I use Qt for my client app. What I want is a background thread that would wait on a message queue and send a signal to a GUI thread whenever a new message comes. I have attempted to write the code using QThread inheritance, but it doesn't seem to work, the messages are not shown, and I think I'm missing something here.
As for the code:
ipcEventListener.h:
class IPCEventListener : public QThread
{
Q_OBJECT
public:
IPCEventListener();
void run();
messageWrapper mw;
signals:
void sendChatMsg(MSG_CHAT_MESSAGE cm);
};
ipcEventListener.cpp
IPCEventListener::IPCEventListener()
{
}
void IPCEventListener::run()
{
mutex.lock();
int n = msgrcv(myQueueId, &mw, sizeof(mw)-sizeof(long), 0, IPC_NOWAIT);
mutex.unlock();
if (n>0)
{
snip...
else if (mw.resp.type == MESSAGE)
{
emit sendChatMsg(mw.chatMsg);
}
}
exec();
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
listener = new IPCEventListener(this);
connect(this->listener, SIGNAL(sendChatMsg(MSG_CHAT_MESSAGE)), this, SLOT(message_received(MSG_CHAT_MESSAGE)));
connect(this->ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
listener->start();
ui->comboBox->addItem("Client");
ui->comboBox->addItem("Room");
}
void MainWindow::message_received(MSG_CHAT_MESSAGE cm)
{
QString formattedMessage = "";
formattedMessage.append("[");
formattedMessage.append(cm.send_time);
formattedMessage.append("] ");
if (cm.msg_type == PRIVATE) formattedMessage.append("[PRIV:] ");
formattedMessage.append(cm.sender);
formattedMessage.append(": ");
formattedMessage.append(cm.message);
formattedMessage.append("\n");
ui->textEdit->append(formattedMessage);
}
What am I missing?
(PS: I know the code probably breaks about a hundred thousand of code conventions, but the deadline is pretty soon and I have to resort to kludges. It's just a school project, though).
You have a logical error in your code. You treat void IPCEventListener::run() as a method which is in a loop and is executing again ang again ang again but it's not. QThread::run() is method where you only initialize your thread and execute exec() function, to start event loop. It means that in current version of your application, you try to receive message just once and then your thread is just waiting for some events, without doing anything with them.
So what you need is an inifite loop in which you will try to receive messages. And don't forget to stop this loop while program closing.