I wrote program which gets source code of web page from url but i have problem, because this code is prints on screen when program is ending and I can't use data which i downloaded. I think that the problem is because program waits for SIGNAL(finished()). Is any way to process downloaded data in my program before ending?
void Get::getCode()
{
networkManager = new QNetworkAccessManager(this);
link = "http://example.com/";
networkManager->get(QNetworkRequest(QUrl(link)));
connect(networkManager, SIGNAL(finished(QNetworkReply*)), &process, SLOT(replyFinished(QNetworkReply*)));
//QDesktopServices::openUrl(QUrl(link));
}
...
void Process::replyFinished(QNetworkReply* pReply)
{
QString source(pReply->readAll());
printf("%s\n", source.toStdString().c_str());
}
...
int main(int argc, char *argv[]){
QApplication a(argc, argv);
Get get; get.getCode();
MainWindow window;
printf("test point\n");
return a.exec();
//return 0;}
"test point" is first on screen and later html code.
The network manager runs asynchronous, which means that your main thread continues immediately after calling the get() method.
You can solve this by setting up an event loop which waits until the download is completed:
QEventLoop loop;
connect(networkManager, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec(QEventLoop::ExcludeUserInputEvents);
That should give you the expected result.
Related
I have an app which can run another exe files. Some buttons and connect to the executeable files. When i click the button, start running the another program... this is good, but remains open the main window and the program still running. I want to achive that the main window stop running (or disapear) when another program is running, and when i exit from the other app, run (or appear and run) the main process.
I tried this:
void MainWindow::RunSys(QString sh)
{
this->close();
QProcess ps;
if(ps.execute(sh)<0)
{
QMessageBox messageBox;
messageBox.critical(nullptr,"Error",sh + "Error!");
}
this->show();
}
//I call the function this way:
QString sh = settings->value("Run").toString();
connect(pButton, &QToolButton::clicked, [=] { RunSys(sh); });
It's working on Linux. Opens the executable program but the main program is till running on Windows. What can I do?
I could not reproduce the bug, we'll need you to provide a complete, minimal and reproducible example that illustrates the bug.
If it can help you, I've written the following sample code based on yours:
Header
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
QPushButton * pb;
public:
MainWindow();
void runShellCmd(const QString & cmd);
};
Implementation
MainWindow::MainWindow()
{
// Build the main window
resize(600, 400);
pb = new QPushButton("run cmd", this);
this->setCentralWidget(pb);
// Create the command
QString cmd("ping 127.0.0.1 -n 6");
// Connect the signal
connect(pb, &QPushButton::clicked, [=](){runShellCmd(cmd);});
}
void MainWindow::runShellCmd(const QString & cmd)
{
QProcess ps;
this->close();
int exit_code = ps.execute(cmd);
switch(exit_code)
{
// Do what you want with exit code
default:;
}
this->show();
}
Main function
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
And it worked fine.
EDIT:
I have understood what's wrong. Your example with calc.exe has whispered me the issue :)
Actually, QProcess::execute() blocks until the command call returns. In this case, it returns right after the launch, not when the windows is closed. So you got the expected behaviour.
I'm afraid that it will be way much harder to do it this way. Because calc.exe being an external program, except if you can read kind of closing signal from an external program, you would not be able to detect when it is closed.
I have to check whether my process has finished and I need to convert it to bool because I want to you if.
In MainWindow.h I have created an object
QProcess *action;
In mainwindow.cpp
void MainWindow:: shutdown()
{
action=new QProcess(this);
action->start("shutdown -s -t 600");
//and now I want to use if
if (action has finished)
{
QMessageBox msgBox;
msgBox.setText("Your computer will shutdown in 1 minute.");
msgBox.exec();
}
You should connect to the process's finished signal. Your code will get invoked whenever the process finishes. E.g.
// https://github.com/KubaO/stackoverflown/tree/master/questions/process-finished-msg-38232236
#include <QtWidgets>
class Window : public QWidget {
QVBoxLayout m_layout{this};
QPushButton m_button{tr("Sleep")};
QMessageBox m_box{QMessageBox::Information,
tr("Wakey-wakey"),
tr("A process is done sleeping."),
QMessageBox::Ok, this};
QProcess m_process;
public:
Window() {
m_layout.addWidget(&m_button);
m_process.setProgram("sleep");
m_process.setArguments({"5"});
connect(&m_button, &QPushButton::clicked, &m_process, [=]{ m_process.start(); });
connect(&m_process, (void(QProcess::*)(int))&QProcess::finished, [=]{ m_box.show(); });
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
Window window;
window.show();
return app.exec();
}
I'm using Websocket Echo Server Example in CLI and it works fine. I'm trying to connect to this server from my Qt GUI project. I have MainWindow class with an appropriate slot
void MainWindow::on_pushButton_clicked()
{
qDebug() << "Push btn clicked";
EchoClient client(QUrl(QStringLiteral("ws://localhost:1234")));
}
and EchoClient files from CLI Websocket Echo Client Example.
The main problem is that that I can't connect to the server when I push button on the form. However, I see debug message "Push btn clicked". It is supposed to be printed "Hello, world!". But nothing happens, no errors. Even signal void EchoClient::onConnected() is not fired.
But if I move EchoClient client(QUrl(QStringLiteral("ws://localhost:1234"))); to main.cpp it connects:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
EchoClient client(QUrl(QStringLiteral("ws://localhost:1234")));
return a.exec();
}
I am completely new in C++ and Qt.
Why this happens? Is it something with processing threads in UI? What should I know?
Qt 5.4.
inside your on_pushButton_clicked() function you are creating the EchoClient (which is asynchronous) in the stack of the function. As soon as the function exits, the EchoClient object is destroyed from the stack.
You can think about different solutions like creating a private field in the MainWindow class
private EchoClient *client;
then set it to null in the MainWindow constructor:
this->client = NULL;
and only at this point doing something like this in your click() routine:
void MainWindow::on_pushButton_clicked()
{
qDebug() << "Push btn clicked";
if (this->client == NULL)
{
this->client = new EchoClient(QUrl(QStringLiteral("ws://localhost:1234")));
}
else
qWarning() << "Carefull, the client is already running";
}
Then it is up to you taking care of the like cycle of the client object you have created.
Probably you have to think when you want to destroy it, probably via a "reset" button routine.
I suggest this reading: http://doc.qt.io/qt-4.8/qapplication.html#details
I'm trying to correct a large program for memory leaks and threads that are not stopped. I know I have some, but I'm not sure about how to properly identify and kill them, so I started playing with some canonical examples, and I'm already having those.
First I tried the simplest thing:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
return a.exec();
}
That gives me one (1) running thread in the Task Manager.
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne *w = new WorkerOne();
QTimer::singleShot(3456, w, SLOT(stop()));
return a.exec();
}
This one gives me 1 before starting the worker, then 2 until the thread actually starts (process is called), then 3 until the singleShot signal is captured and the worker deleted and then 2 again. So I'm having something loose there.
And this is the code for WorkerOne:
WorkerOne::WorkerOne(QObject *parent)
: QObject(parent)
, m_stop(false) {
QThread* thread = new QThread;
this->moveToThread(thread);
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
WorkerOne::~WorkerOne() {}
void WorkerOne::process() {
while(!m_stop) {
QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); loop.exec();
}
emit finished();
}
void WorkerOne::stop() {
m_stop = true;
}
void WorkerOne::errorString(QString err) { }
The platform is Qt 5.2.1 with mingw48_32 compiler.
I think I am following the steps in threading howto from Maya Posch's blog, but maybe I am missing something.
Your implementation of the worker object is literally upside down. It's QThread's job to spin the event loop. Your worker object should simply be driven by slot calls and incoming events. A processing busy loop idiom uses a zero-length timer to stay active while allowing the event loop to receive events and quit, with no need for extra flags.
Here's how to do it:
class WorkerOne : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void processChunk() {
...
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) processChunk();
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() { m_timer.start(0, this); }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne worker;
QThread thread;
thread.start();
worker.start();
worker.moveToThread(&thread);
a.connect(&thread, SIGNAL(finished()), SLOT(quit()));
QTimer::singleShot(3456, &thread, SLOT(quit()));
return a.exec();
}
When the timer times out, the thread's event loop quits, the thread finishes, the application's event loop is quit, and, finally, the thread and the worker get destroyed.
A zero-length timer is not really a timer, just an idiom that means: invoke me as soon as the event loop is entered and there's nothing else to do. Doing the below would be a premature pessimization as there's be a memory allocation per each round through the event loop - not using the timer would be worse!
class WorkerOne : public QObject {
Q_OBJECT
Q_INVOKABLE void processChunk() {
...
// A lame attempt to call ourselves again from the event loop.
// It works, but has lot more overhead than a zero-length timer!
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() {
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
};
i just asking myself how to restart my own qt application?
Can somebody please show me an example?
To restart application, try:
#include <QApplication>
#include <QProcess>
...
// restart:
qApp->quit();
QProcess::startDetached(qApp->arguments()[0], qApp->arguments());
I'm taking the other answers solutions, but better. No need for pointers, but there is a need for a ; after the while statement of a do { ... } while( ... ); construct.
int main(int argc, char *argv[])
{
const int RESTART_CODE = 1000;
do
{
QApplication app(argc, argv);
MainWindow main_window(app);
} while( app.exec() == RESTART_CODE);
return return_from_event_loop_code;
}
Assuming that 1337 is your restart code:
main.cxx
int main(int argc, char * argv[])
{
int result = 0;
do
{
QCoreApplication coreapp(argc, argv);
MyClass myObj;
result = coreapp.exec();
} while( result == 1337 );
return result;
}
myClass.cxx
qApp->exit(1337);
To restart a running Qt application (at least in Qt 5.15.2) you can do the following:
#include <QApplication>
#include <QProcess>
//...
QString program = qApp->arguments()[0];
QStringList arguments = qApp->arguments().mid(1); // remove the 1st argument - the program name
qApp->quit();
QProcess::startDetached(program, arguments);
Doing a real process restart without subclassing:
QCoreApplication a(argc, argv);
int returncode = a.exec();
if (returncode == -1)
{
QProcess* proc = new QProcess();
proc->start(QCoreApplication::applicationFilePath());
}
return returncode;
Edit for Mac OS like earlier example.
To restart call
QCoreApplication::exit(-1);
somewhere in your code.
Take a look at How to restart an application thread on qtcentre.org, where muisei gives this code
#define RESTART_CODE 1000
int main(int argc, char *argv[])
{
int return_from_event_loop_code;
QPointer<QApplication> app;
QPointer<MainWindow> main_window;
do
{
if(app) delete app;
if(main_window) delete main_window;
app = new QApplication(argc, argv);
main_window = new MainWindow(app);
return_from_event_loop_code = app->exec();
}
while(return_from_event_loop_code==RESTART_CODE)
return return_from_event_loop_code;
}
I just used the method described above and I noticed that my application crashes on restart.
...then I switched the following lines of code:
if(app) delete app;
if(main_window) delete main_window;
to:
if(main_window) delete main_window;
if(app) delete app;
and it behaves OK. For some reason the window must be deleted first.
Just a note for future readers.
EDIT: ...and a different approach for those who want a real process-restart: You can declare a myApp::Restart() method in your subclass of QApplication. The following version works OK on both MS-Windows & MacOS:
// Restart Application
void myApp::Restart(bool Abort)
{
// Spawn a new instance of myApplication:
QProcess proc;
#ifdef Q_OS_WIN
proc.start(this->applicationFilePath());
#endif
#ifdef Q_OS_MAC
// In Mac OS the full path of aplication binary is:
// <base-path>/myApp.app/Contents/MacOS/myApp
QStringList args;
args << (this->applicationDirPath() + "/../../../myApp.app");
proc.start("open", args);
#endif
// Terminate current instance:
if (Abort) // Abort Application process (exit immediattely)
::exit(0);
else
this->exit(0); // Exit gracefully by terminating the myApp instance
}
This slight variation on Rubenvb's idea works with PyQt. clearSettings is the method that triggers the restart.
class GuiMain
#Most of implementation missing
def clearSettings(self):
#Clearing the settings missing
QApplication.exit(GuiMain.restart_code)
restart_code = 1000
#staticmethod
def application_main():
"""
The application's main function.
Create application and main window and run them.
"""
while True:
app = QApplication(sys.argv)
window = GuiMain()
window.show()
ret = app.exec_()
if ret != GuiMain.restart_code:
break
del window
del app
Here is the code:
main.cpp:
int main(int argc, char *argv[])
{
int currentExitCode = 0;
do {
QApplication a(argc, argv);
MainWindow w;
w.show();
currentExitCode = a.exec();
} while( currentExitCode == MainWindow::EXIT_CODE_REBOOT );
return currentExitCode;
}
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
static int const EXIT_CODE_REBOOT;//THIS IS THE IMPORTANT THING TO ADD TO YOUR CODE
~MainWindow();
private slots:
void slotReboot();//AND THIS ALSO
//ALL THE OTHER VARIABLES
}
The slotReboot() is the slot that will receive the signal of the QAction I'm going to show in the mainwindow.cpp
mainwindow.cpp
First initialize EXIT_CODE_REBOOT :
int const MainWindow::EXIT_CODE_REBOOT = -123456789;
and declare a QAction pointer:
QAction* actionReboot;
then in the MainWindow constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
actionReboot = new QAction( this );
actionReboot->setText( tr("Restart") );
actionReboot->setStatusTip( tr("Restarts the application") );
connect( actionReboot, SIGNAL (triggered()),this, SLOT (slotReboot()));
}
And finally you need to send the signal (in the part of your code you need), in this way:
actionReboot->trigger();
I did the code I showed following these instructions: How to make an application restartable - Qt Wiki
You can use my open source library:
https://marketplace.qt.io/products/main-loop-wdt-for-qt-qml
It's a watchdog timer for the main qt loop, but I have a function for forced reboot, with different strategies: startdetached + exit, exec system call on Linux / macOS, and delayed restart (for example, exit and restart after 3 seconds)