I want to run a function of a class as a thread continuously,till the object of the class is destroyed.
client.h
class client:public QWidget
{
Q_OBJECT
public:
//some declarations
client();
void setclientui();
//some ui elements
void receiveme(); //i want this function to be run as a thread
//It has to be run continuously to receive
//messages from socket and when a message is
//received ,it must display it in the gui.
public slots:
int prework();
void sendme();
};
Note:receiveme() uses recv() of tcp sockets which gets blocked until message is received.
client.cpp
void receiveme(){
while(1){
if(recv(sockfd,receivebuf,1024,0)<0)
{
qDebug()<<errno;
break;
}
receivebuf[20]='\0';
qDebug()<<receivebuf;
outputbox->append(a);
}}
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
Dialog* newdialog;//join a new chat
QString ipp,portt;
QTabWidget *wdg;
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void receivesocketaddress();
void on_actionJoin_a_chat_triggered();
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
wdg=new QTabWidget;
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionJoin_a_chat_triggered()
{
newdialog=new Dialog();
newdialog->setWindowTitle("Join a chat");
newdialog->setModal(true);
qDebug()<< QObject::connect(newdialog->conne,SIGNAL(clicked()),this,SLOT(receivesocketaddress()));
newdialog->exec();
}
void MainWindow::receivesocketaddress()
{
client *aclient=new client;
aclient->iptoconnect=newdialog->ip->text().toLocal8Bit().data();
aclient->porti=newdialog->port->text().toLocal8Bit().data();
if(aclient->prework()==0)//ie connected
{
newdialog->close();
wdg->addTab(aclient,tr("new chat"));
setCentralWidget(wdg);
//here the ui is shown.Now the aclient->receiveme() should
//running
}
else
{
newdialog->displayerror();
layout->addWidget(error,3,0,2,2);
qDebug()<<"cud not connect";
}
}
If aclient->prework()==0 then a gui is displayed but how can i run aclient->receiveme() at this time as a thread so that it is continuously running and reading messages from socket.If a message is received,it should be displayed in the gui.
Without thread the gui would freeze.I tried to use QThread::movetothread() but i receive the following error
QThread::cannot move object with parent
and to use subclass method, client class must inherit QThread but since it is already inheriting QWidget,the following error is thrown
call to QObject is ambiguous
How can i use QThread here?
Widgets can run only within GUI thread, so you need to implement client as QObject subclass and communicate with UI via signal/slot connection. Qt wont allow you to do outputbox->append(a) in non UI thread (Supposing that outputbox is some QWidget here);
You probably don't even need to use threads here - Qt provides it's own socket classes with event (signal/slot) based API;
If you still need to use recv() in different thread, you need to subclass QThread (one approach) or QObject (another approach); In both cases you need to have signal like messageReceived(QByteArray) that will be connected to slot in your UI object that will handle message; So receiveme() slot might looks like:
void client::receiveme()
{
while(1){
if(recv(sockfd,receivebuf,1024,0)<0)
{
qDebug()<<errno;
break;
}
receivebuf[20]='\0';
QByteArray msg(receivebuf);
emit messageReceived(msg);
}
}
This article might help
Related
i have a problem in working signal and slot in QT framework .
my slot is not working .
here is the code .
connect(&th,SIGNAL(change()),this,SLOT(closeWindow()));
this->moveToThread(th);
closeWindow();
th.start();
"th" is a var from a class like this :
class Thread : public QThread
{
public :
Thread();
bool pause,flag;
QString URL;
QFile *mFile;
void run();
void RESUME();
void PAUSE();
bool Check();
bool Check2();
signals:
void change();
QString myTxt;
};
"change" is the signal
and here is the code of my MainWindow :
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Thread th;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
public slots:
void closeWindow();
};
and here is the constructor for MainWindow
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&th,SIGNAL(change()),this,SLOT(closeWindow()));
th.start();
}
the signal is Ok . but the Slot is not Working .
can You guide me ?
I think the main issue is that the receiving object lives in a dead thread.
Your Thread instance lives on the application thread, while your MainWindow lives on the thread created by your Thread instance. However as you have reimplemented QThread::run(), you do not have an event loop on this thread and the slot can never be invoked.
Check Qt documentation for details:
Threading Basics
Threads and QObjects
Also you have some big issues in your code:
Missing Q_OBJECT macro in Thread definition (but you might have removed it while copy/pasting otherwise you wouldn't be able to emit the signal).
You must not call moveToThread() on object derived from QWidget (e.g QMainWindow). QWidgets must live on the application thread.
You generally cannot mix using moveToThread() and reimplementing run().
When using moveToThread() you are using the thread event loop to make QObjects living on this thread (i.e moved to this thread) live.
When reimplementing QThread::run(), people generally want to execute a single function on a thread. This will lead to a thread being created, the function executed and the thread destroyed without running an event loop. And no event loop mean that if a QObject lives on this thread, it will not received inter-thread slot invokations.
NB: Using moveToThread() is the correct/intended way to use QThread. Reimplementing QThread::run() will work and can be found in Qt documentation but isn't generally recommended and you might be better of using QThreadPool.
More readings: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
I have been debugging some code which seems to be locking the main thread when the GUI is not visible. I have stripped it right back to the following code snippet and I have identified that a problem exists around my implementation of QTimer::singleShot.
To replicate the issue I set the timer to 1 (millisecond) start the application looping and send the app window to to the background. Eventually the app will grind to a halt until the UI is brought into the foreground.
If I set the timer to 0, it then the runs flawlessly regardless of where the main app window is located, I have increased the loop size as far as 4 million without issue.
I guess what I am stuck with is, what is the difference between
QTimer::singleShot(1, this, SLOT(emptyListOfAnotherObjects()));
and
QTimer::singleShot(0, this, SLOT(emptyListOfAnotherObjects()));?
Why would one block the main thread over the other?
For what it is worth running this loop in a different thread, keeping the GUI separate, results in the same issue.
class AnotherObject : public QObject
{
Q_OBJECT
public:
AnotherObject();
void process();
signals:
void done();
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void start(bool);
private slots:
void emptyListOfAnotherObjects();
void delayEmptyOfAnotherObject();
private:
QList<AnotherObject*> m_listOfAnotherObject;
Ui::MainWindow *ui;
};
==
AnotherObject::AnotherObject()
{
qDebug() << "CTOR AnotherObject" << this;
}
void AnotherObject::process()
{
emit done();
deleteLater();
}
//==
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->start, SIGNAL(clicked(bool)), this, SLOT(start(bool)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::start(bool)
{
for(long i=0; i<40000; i++){
m_listOfAnotherObject.append(new AnotherObject());
}
emptyListOfAnotherObjects();
}
void MainWindow::emptyListOfAnotherObjects()
{
if(m_listOfAnotherObject.isEmpty()) {
qDebug() << "List empty, done.";
return;
}
AnotherObject* i = m_listOfAnotherObject.takeFirst();
connect(i, SIGNAL(done()), this, SLOT(delayEmptyOfAnotherObject()));
i->process();
qDebug() << m_listOfAnotherObject.count();
}
void MainWindow::delayEmptyOfAnotherObject()
{
QTimer::singleShot(1, this, SLOT(emptyListOfAnotherObjects()));
}
Thanks
Update:
Sorry, should have added that this is Qt 5.2 on OSX.
App Nap is likely the cause of this problem.
I suspect that using invokeMethod places a message on the thread's event queue, which prevents the app from napping. In contrast, using QTimer waits and checks the timeout, so an empty event queue will allow it to enter the nap state.
Anyhow, it is possible to disable app nap from within your application, as described here.
As you're using Qt, you'll want to use a .mm file to encapsulate the objective-c code.
I'm having some issues with Qt threading to allow the threaded part to update the GUI of my program. Seems like it's a known "problem" with Qt, so I found multiple tutorials, but I don't understand why my example here is not working.
I inherited from QThread as follow:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(capture_loop()));
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
this, SLOT(receivePacket(Packet*)));
}
signals:
void sendPacket(Packet*);
public slots:
void capture_loop() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit(sendPacket(packet));
std::cout << "Sending packet!" << std::endl;
}
}
};
And here is the CaptureHandler:
class CaptureHandler: public QWidget {
Q_OBJECT
public:
CaptureHandler() {
start = new QPushButton("Capture", this);
thread = new CaptureThread(this, start);
thread->start();
}
public slots:
void receivePacket(Packet *packet) {
std::cout << "Packet received!" << std::endl;
/*
Here playing with layout etc...
*/
}
private:
QPushButton *start;
CaptureThread *thread;
};
I think the signals and slots are ok, because it displays on the terminal
Sending packet!
Packet received!
Sending packet!
Packet received!
Sending packet!
Packet received!
But in the receivePacket slot, i'm trying to modify my GUI, and it does not work. The GUI just freeze, and all I can do is CTRL+C on terminal.
So i think my capture_loop, which is an infinite loop for the moment, is blocking the program, which means my thread has not started.
But I called thread->start().
I even tried to start the thread in CaptureThread constructor, by calling this->start(), but the result is the same.
Any idea?
Your using QThread wrong. By just creating the thread, it will not execute on the thread. you will need to do it inside the QThread::run function (by overriding it), since thats the only one that will run on the new thread. Please notice, that as soon as you return from this function, the thread will exit.
If you want to use your own loop inside the QThread::run function (instead using Qts default event loop), the thread won't be able to receive signals inside the run-function!
Here an example on how to use QThread:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
//calling "start" will automatically run the `run` function on the new thread
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(start()));
//use queued connection, this way the slot will be executed on the handlers thread
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
handler, SLOT(receivePacket(Packet*)), Qt::QueuedConnection);
}
signals:
void sendPacket(Packet*);
protected:
void run() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit sendPacket(packet) ;//emit is not a function
qDebug() << "Sending packet!";//you can use qDebug
}
}
};
I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);
The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.
In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.
In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.
I want to do something which will access network when a QMainWindow is ready.
I suppose I should not do it in the constructor, so I try to find a signal the widget will get and try to implement something like a OnReady() call back in other UI library. But I still can not find a way to do this.
Thanks a lot in advance.
If I understand correctly, you need to do something as soon as the application's event loop is ready to process events.
The reason you can't do it in the constructor because the application's event loop isn't ready until some time after the constructor has finished running.
What you can do is create a slot in your MainWindow class containing the code you want to run, set up a single-shot timer in the constructor, and have that timer call your slot. For example:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void doStuff(); // This slot will contain your code
// ...
// ...
// ...
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QTimer::singleShot(0, this, SLOT(doStuff())); // This will call your slot when the event loop is ready
// ...
// ...
// ...
}
void MainWindow::doStuff()
{
// This code will run as soon as the event loop is ready
}
Alternative way is to use QMetaObject::invokeMethod with a queued connection. If you use invokeMethod you can also pass an argument.
QMetaObject::invokeMethod(
this,
"onReady",
Qt::QueuedConnection,
Q_ARG(QString, argument));