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.
Related
I am trying to capture output of my Qt application but without success.
(I am calling an external lib that outputs to console, and I want to show this in my UI. Its NOT a QProcess, its a calss instance in my own process).
The problem: my lambda slot when writing to std::cout never gets called.
Here is my code distilled to a small testable application.
This is my latest attempt, and so far I am getting the "furthest" with it meaning, that the std::cout output is successfully redirected to the QFile.
What I don't understand however, is why the QTextStream connected to this file is not being triggered?
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <iostream>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QFile file("output.txt");
file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate);
// Redirect stdout to the QFile
std::freopen(file.fileName().toStdString().c_str(), "w", stdout);
QTextStream stream(&file);
std::string output; //to spy on in debugger
//this lambda never gets called!?
QObject::connect(&file, &QFile::readyRead, [&stream,&output] {
// Read from the QTextStream whenever new data is available
output += stream.readLine().toStdString();
qApp->quit();
});
//This succefully writes to the QFile on disk
QTimer::singleShot(100, [] {
std::cout << "This will be written to output.txt" << std::endl<<std::flush;
});
app.exec();
// Close the stream
std::fclose(stdout);
file.close();
}
My previous attempts are listed below, and are still not answered, so if you know how to fix any of the approaches, I will be really thankful!
Note at the end of the code, I am outputting directly to std::cout and to the QTextStream.
All of these outputs are seen on the console, including the output to stream - which means, that QTextStream object is correctly initialized with stdout.
Any ideas why the lambda slot is not getting called?
(I am aware of the recursion that will happen in the lambda due to outputting to stdout in it. But as this is just a test code its ok - the problem is that the lambda is not getting called at all)
#include <QCoreApplication>
#include <iostream>
#include <QTextStream>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QTextStream stream(stdout);
QObject::connect(stream.device(), &QIODevice::bytesWritten, [&stream](qint64 bytes) {
// This lambda function is called when new data is available to be read
std::cout<<"in lambda"<<std::endl;
});
QTimer::singleShot(100, [&stream]{
std::cout << "Hello, world!" << std::endl<<std::flush;
std::cout << "This is some output." << std::endl<<std::flush;
stream<< "Stream output\n";
stream.flush();
});
return app.exec();
}
After some more thought, it occurred to me to try listening on stdout with QSocketNotifier.
With this approach, the notifier slot gets triggered, however, two things:
The notifier slot gets called before the QTimer slot - repeatedly like in an endless loop.
I get nothing from the stream which is really confusing me - I am being notified when stdout is being written to (even though nothing is writing to it, yet) and am I getting nothing when trying to read that data? (the fact that I get nothing is not that surprising since I didn't write anything (yet) to stdout it's more the fact it is being triggered all the time)
Anyone knows how to explain this?
Here is the code:
#include <QCoreApplication>
#include <iostream>
#include <QTextStream>
#include <QTimer>
#include <QSocketNotifier>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QTextStream stream(stdout);
int stdoutFd = fileno(stdout);
std::string output; //allows me to spy the content in the debuger
QSocketNotifier notifier(stdoutFd, QSocketNotifier::Write );
QObject::connect(¬ifier, &QSocketNotifier::activated, [&stream, &output] {
auto s = stream.readAll();
output += s.toStdString();
});
QTimer::singleShot(100, [&stream]{
std::cout << "This is some output." << std::endl<<std::flush;
stream << "Stream output\n";
});
return app.exec();
}
Many thanks in advance!
I have managed to achieve what I wanted, not very elegant, but it works.
I am putting my solution here for others that might also encounter this problem.
On one hand I like this solution since its basically pure C++ and does not require Qt.
On the other, it requires polling, which is quite "clunky".
Thus, I am leaving my OP open, with the hope that a more elegant solution will be offered, and I am curious as to why my Qt solutions didn't work.
This solution uses std::stringstream and std::streambuf.
I am putting here in a simple example main(), you can then adapt it to what ever application you have as it is really simple.
https://onlinegdb.com/AixVsxUyy
#include <sstream>
#include <iostream>
int main(int argc, char *argv[]) {
//Redirect stdout to streambuf - this "grabs" the stdout
std::stringstream buffer;
std::streambuf *streamBuff = std::cout.rdbuf(buffer.rdbuf());
std::cout << "this is redirected to streambuf" << std::endl;
//Read our buffer
std::string text = buffer.str();
// Release stdout back to original buffer
std::cout.rdbuf(streamBuff);
std::cout << "Grabbed text:" << text << std::endl;
std::exit(0);
}
Since this is synchronous, I resorted to polling buffer.str().
If anyone knows how can I be notified when streambuff has new data, please share.
Note:
When polling, if between the calls no new data was written to stdout, the same string will be read again as the buffer is still intact.
If you want to clear the buffer when you read it call:
buffer.clear();
buffer.str("");
I hope this helps someone!
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;
}
So I have a c++ program here utilizing wiringPi to sleep a thread until a button press (on a rapsberryPi using the GPIO), but when the button is pressed it can often print the message multiple times. I tried to remedy this by sleeping for a few seconds within the loop but this didn't help leading me to believe that it has something to do with how the interrupt generation calls the function. Any advice for how I can solve this so the function is only ran once per button press?
#include <stdlib.h>
#include <iostream>
#include <wiringPi.h>
#include <unistd.h>
void printMessage(void) {
std::cout << "Button pressed! hooray" << std::endl;
}
int main(int argc, char const *argv[]) {
wiringPiSetup();
while(true) {
wiringPiISR(3, INT_EDGE_FALLING, &printMessage);//3 is the wiringPi pin #
sleep(3);
}
}
I think you only have to set the ISR once (call wiringPiISR once). After that just sleep forever (while(1)sleep(10);). You seem to have debounced your button using a print statement. Debouncing can often be a matter of timing, and printing takes a few microseconds causing the button to be "sort of" debounced. It can however still do some bouncing
For more debouncing info see this SO page
I am not familiar with the Raspberry-Pi, but if the code can directly sense the button state (instead of using a triggered interrupt) do something like this to react only on the enabling transition:
int main (...)
{
writingPiSetup ();
bool last_state = false;
while (true)
{
bool this_state = wiringPiDigital (3); // use correct function name
if (last_state == false && this_state == true) // button freshly pressed
{
std::cout << "Button freshly pressed" << std::endl;
}
last_state = this_state;
}
}
However, it is quite possible that the hardware is not debounced. So inserting a little bit of delay might be called for. I would experiment with delays in the 10 to 100 millisecond range depending on the particulars of the application.
I've recently started working with Qt and am trying to play a sound file using QMediaPlayer.
My program compiles and runs but the sound file is not played, the QMediaPlayer seems stuck in the QMediaPlayer::LoadingMedia state.
Also - and possibly related - the QMediaPlayer doesn't ever seem to emit its mediaStatusChanged or its error signals (though perhaps this is me not connecting them properly?)
When I run the program as below, it reaches the while loop and never leaves. If I query for player->mediaStatus() inside the loop, it constantly returns 2 (QMediaPlayer::LoadingMedia).
When I run it with the while loop omitted, the program continues to run until it reaches end of execution with no run-time errors but - as you may expect - the file is not played.
Interestingly, the two couts before the while loop, which report player's mediaStatus and state show that the mediaStatus changes from 1 (in the first instance, before setting the media) to 2 (after setting the media) but my ChangedStatus slot is never called, despite connecting to the mediaStatusChanged at the start of the run function.
Running: Debian Jessie, Qt5.7/Qt5.9
AudioPlayer.h
#include <QThread>
#include <QMediaPlayer>
class AudioPlayer : public QThread {
Q_OBJECT
public:
AudioPlayer();
public slots:
void ChangedStatus(QMediaPlayer::MediaStatus);
void MediaError(QMediaPlayer::Error);
protected:
void run();
};
AudioPlayer.cpp:
AudioPlayer::AudioPlayer(){}
void AudioPlayer::run()
{
QMediaPlayer* player = new QMediaPlayer();
connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(ChangedStatus(QMediaPlayer::MediaStatus)));
connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(MediaError(QMediaPlayer::Error)));
std::cout << "Got player!" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
player->setMedia(QUrl::fromLocalFile("/home/me/test.wav") );
std::cout << "Set source" << std::endl;
std::cout << "\n\n\tPlayer state: " << player->state() << "\n\tMediaState: " << player->mediaStatus() << std::endl;
while(player->mediaStatus() != QMediaPlayer::MediaStatus::LoadedMedia)
{//
}
player->setVolume(100);
std::cout << "Set volume" << std::endl;
player->play();
std::cout << "Played" << std::endl;
}
void AudioPlayer::MediaError(QMediaPlayer::Error error)
{
std::cout << "Media Error: " << error << std::endl;
}
void AudioPlayer::ChangedStatus(QMediaPlayer::MediaStatus status)
{
std::cout << "Status changed to: " << status << std::endl;
}
main.cpp:
#include "audioplayer.h"
using namespace std;
int main()
{
cout << "Hello World!" << endl;
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
std::cout << "myAudioPlayer started. Waiting...." << std::endl;
myAudioPlayer.wait();
std::cout << "myAudioPlayer returned." << std::endl;
return 0;
}
Extra Info:
Now, initially, I hadn't used QThread and was trying to do this all in main.cpp (just declaring a QMediaPlayer and attempting to set the media and play) but this was giving me QObject::startTimer: timers cannot be started from another thread warning run-time errors in a couple of places (declaration of the QMediaPlayer and, I think, the play command), so I adopted the above approach - although I'm not sure that subclassing QThread is, necessarily, the best way. This is also why everything (declarations etc.) is done in the run function - having the QMediaPlayer as a member of AudioPlayer and initialising it in the constructor gave the same error.
I have compiled and run Qt's Player example (from multimediawidgets) and, by browsing and selecting my test.wav, it can play the file so I don't think it's a compatibility issue. I looked through the Player example source but couldn't see anything jumping out which I had missed and which looked like the cause of my problem.
You should create an QApplication object and use it's message loop. I would suggest you to test following:
#include "audioplayer.h"
using namespace std;
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
AudioPlayer myAudioPlayer;
myAudioPlayer.start();
return a.exec();
}
You will at least get your signals raised. If the media state reaches QMediaPlayer::StoppedState or any error occured, you could call QApplication::instance()->quit() to stop your application.
Edit: Better use the new style connections like:
connect(player, &QMediaPlayer::mediaStatusChanged, this, &QMediaPlayer::ChangedStatus);
It is more reliable and you don't have to register specific parameter types like QMediaPlayer::MediaStatus with Q_DECLARE_METATYPE()
Because QMediaPlayer class contains another method called error with a different signature, signal connection is a bit more complicated. This is because the compiler don't know which error method you are referring to. In this case static_cast is the way to solve this ambiguity:
connect(
player,
static_cast<void(QMediaPlayer::*)(QMediaPlayer::Error )>(&QMediaPlayer::error),
this,
&AudioPlayer::MediaError
);
Please note, a Wave file is only a container file that can contain an arbitrary compressed data stream. It may be necessary to install the appropriate operating system multimedia codec first. In Microsoft Windows Qt-Framework relies on installed multimedia codecs (.ax file).
Your AudioPlayer::run method will end without waiting for the media being played. So you should wait for the Stopped status some where before the thread ends. However it is better not to use the run method directly but using QThreads message loop instead.
class AudioPlayer : public QThread {
public:
AudioPlayer() : _Player(nullptr) {
moveToThread(this); // AudioPlayer object become part of this new thread
}
public slots:
void setVolume(int);
void load(QString Media);
// ...
void play() {
// Never directly access any members since they may belong to a different thread
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "play", Qt::QueuedConnection);
} else {
_Player->play();
}
}
void stop() {
quit(); // Quiting thread message loop
}
private:
QMediaPlayer* _Player;
void run() {
_Player = new QMediaPlayer(this);
connect(...) // All connections go here...
int Result = QThread::exec();
_Player->stop();
delete _Player;
}
private slots:
void HandleStatusChange(QMediaPlayer::MediaStatus Status) {
emit statusChanged(Status); // Redirect so that the main application can handle this signal too
}
signals:
void statusChanged((QMediaPlayer::MediaStatus);
};
I use the following code to talk to a USB-serial port device:
#include "masterthread.h"
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include "Windows.h"
#include "Psapi.h"
#include <QDebug>
QT_USE_NAMESPACE
MasterThread::MasterThread(QObject *parent)
: QThread(parent), waitTimeout(0), quit(false)
{
}
MasterThread::~MasterThread()
{
mutex.lock();
quit = true;
cond.wakeOne();
mutex.unlock();
wait();
}
void MasterThread::run()
{
bool currentPortNameChanged = false;
QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(57600);
serial.setStopBits(static_cast<QSerialPort::StopBits>(1));
serial.setDataBits(static_cast<QSerialPort::DataBits>(8));
serial.setParity(static_cast<QSerialPort::Parity>(0));
serial.open(QIODevice::ReadWrite);
//Tell the serial port connected device to start talking
//--------------------------------------
const char init[] = { 0x0d, 0x0d, 0x0d };
serial.write(init, sizeof(init));
const char* cmd = "mavlink stop\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "uorb start";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "sh /etc/init.d/rc.usb\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 4);
serial.waitForBytesWritten(100);
int i = 0;
int j = 0;
forever
{
//Write test data out
//-----------------------------
QByteArray test(2000, 't');
serial.write(test);
bool check = serial.waitForBytesWritten(100);
if (!check)
{
qDebug() << "FAIL: " << j++;
}
if (serial.waitForReadyRead(20))
{
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
qDebug() << response;
}
QThread::msleep(20);
//Print memory usage
//---------------------------------------------------
if (i++ % 10 == 0)
{
PROCESS_MEMORY_COUNTERS memcount;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) return;
qDebug()<<"----------------------------" << memcount.WorkingSetSize / 1024 << "KB memory used";
}
} // end foever
qDebug() << "Exiting forever loop";
}
with a simple main.cpp as:
#include <QApplication>
#include "masterthread.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MasterThread thread;
thread.start();
return app.exec();
}
But the memory usage keeps increasing, like 5~10MB per hour as if there are some leakage.
The device is suppose to be connected for days and weeks...
What am I doing wrong here? I am on Qt5.6 windows7 debug
Many Qt Components have an implicit dependency on its event loop.
While you are starting the main threads event loop with the call to app.exec(); you are not handling events generated by the QObjects created in the QThread MasterThread thread;. The details and nuances of Event handling in Qt are very well described on this page: https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects
But the solution boils down to: if you want to be able to process queued up Qt events in a thread where you are processing some long-running task you should call QCoreApplication::processEvents(); from time to time. This will prevent Qt events from endlessly queueing up.
EDITED after looking on the code Qt 5.7,5.6,5.5 and reading docs.
As an answer is already accepted, I would just add some thoughts here as it's too long for comments.
Keep things short - an answer you accepted is wrong..
There are two sides of the story. And as SO answers often taken 'as it is as long as they work' I'd like to explain myself...
If you look on a code provided - there is nothing wrong with it. All objects are properly stack allocated and should be destroyed automatically.
Point is that QtSerial uses deleteLater() and then a question - how to delete those allocations properly.
If any module/object/code uses deleteLater() it requires an event loop, if deleteLater() called on a thread without event loop, object will be deleted after thread is terminated. As long as there is no event loop running for code above, processEvents will no work.. actually processEvents() is not something which is used for this, because a whole idea to return from the context which is called deleteLater() and have a next run, and that's checked in the Qt Source Code, so calling processEvent() straight after without incrementing loop count will do nothing at all, that's why answer you accepted is totally wrong.
Conclusion:
If any object requires event loop running it should be EXPLICITELY stated in the documentation as there is nothing wrong in using QIODevice in sync mode outside event loop.
So at my opinion,point is - its a bug in the QT Serial itself which I suggest you report.
In general it's really wrong practice for Qt to run never-ending loops..
It's much much better and cleaner to use QObject Worker tactic which is pushed to the thread, have proper even loop running etc.
For small 'threaded' tasks it's much better to use QtConcurrent.
Proper Workaround:
you will have a thread with properly running event loop and a timer firing at 20ms to do your things
// main thread:
class Worker: public QObject {
public:
Worker();
public slots:
onInit() {
// initialize everything
startTimer(20);
}
protected:
void timerEvent(..) {
// do your things every 20ms
}
}
...
QThread * pWorkerThread = new QThread();
pWorkerThread->setObjectName(QString("Serial"));
Worker * pWorker = new Worker();
Worker->setObjectName(QString("Common Storage Impl"));
Worker->moveToThread(WorkerThread);
connect(pWorkerThread, SIGNAL(started()), pWorker, SLOT(onInit()));
connect(pWorkerThread, SIGNAL(finished()), pWorker, SLOT(deleteLater()));
connect(pWorkerThread, SIGNAL(finished()), pWorkerThread, SLOT(deleteLater()));
pWorkerThread->start();
...