Is there a way to implement OnReady() callback in Qt4? - c++

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));

Related

QPlainTextEdit() ->setPlainText() keeps crashing

I'm trying to update a QPlainTextEdit() from either a button click, thread, etc. Somewhere from outside the MainThread and in Qt documentation it says it must used signals but I can't figure out how. If I try to do a CreateThread() or use a std::thread to update the
class MainWindow : public QMainWindow
{
Q_OBJECT
...
private slots:
handleButtonClick();
Thread();
...
private:
QPlainTextEdit *TextView;
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
...
TextView = new QPlainTextEdit();
TextView->setReadOnly(true);
TextView->setCursorWidth(0);
QPUshButton *UpdateButton = new QPushButton();
connect(UpdateButton, SIGNAL(released()), this, SLOT(handleButtonClick()));
....
}
MainWindow::handleButtonClick()
{
// eventually this will cause a crash, usually not imemdiately
TextView->insertPlainText("test");
}
MainWindow::Thread()
{
TextView->insertPlainText("test");
}
So as you can see, I want a way to update this QPlainTextEdit from outside the main thread without crashes. How can I do this? Thanks.
You are not allowed to do UI opeations like updating the text of a QTextEdit from outside the main thread. The solution to this is emitting a signal from the non-main thread, and have it connected to a slot in the main thread which does the UI work.

Qt C++ - How to pass data from a worker thread to main thread?

I am trying to perform interthread communication in Qt (C++). I have a worker thread which does some calculations and I want the workerthread to return its results to the main thread when done. I therefor use a connect, I know thanks to debugging, that the signal is successfully being emit but that it is the slot that isn t being executed and I don t understand why.
The relevant pieces of code:
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
workerThread = new QThread(this);
workerClassObj = new workerClass();
//connect for image
connect(workerClassObj, SIGNAL(mySignal(QPixmap)), this, SLOT(mySlot(QPixmap)));
//connect(&workerClassObj, workerClass::mySignal(QPixmap), this, webcamClass::mySlot(QPixmap));
connect( workerThread, SIGNAL(started()), workerClassObj, SLOT(getImage()) );
workerClassObj->moveToThread(workerThread);
}
void webcamClass:: foo()
{
workerThread->start();
}
void workerClass::getImage()
{
qint64 successFailWrite;
QImage img;
QPixmap pixmap;
... do some stuff with pixmap...
qDebug()<<"going to emit result";
emit mySignal(pixmap);
qDebug()<<"emitted";
}
void webcamClass::mySlot(QPixmap p)
{qDebug()<<"this message should be displayed"; }
The corresponding header files:
class workerClass : public QObject
{
Q_OBJECT
private:
public:
explicit workerClass(QObject *parent = nullptr);
signals:
void mySignal(QPixmap);
};
webcamClass::webcamClass(QObject *parent) : QObject(parent)
{
Q_OBJECT
public:
explicit webcamClass(QObject *parent = nullptr);
public slots:
void mySlot(QPixmap p);
private:
QThread *workerThread;
workerClass *workerClassObj;
};
The code above just outputs:
going to emit result
emitted
but unfortunately doesn t output this message should be displayed.
webcamClass belongs to the parent thread, while workerClass belngs to -you guessed it- the worker thread.
Could someone explain how to setup my connect so that mySlot() gets triggered?
Thanks!
In the code you pasted in pastebin.com/UpPfrNEt you have a getVideoFrame method that uses while (1). If this method is called, it runs all the time and blocks the event loop from handling signals. You can solve it in many ways, I think the best practice will be to replace the while(1) with something else.
If possible, I highly encourage you to use the new Signal Slot syntax:
connect( SOURCEINSTANCE, &CLASS::SIGNAL, TARGETINSTANCE, &CLASS::SLOT );
In your case, that could be:
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot );
Specificallyfor your case, if you want to pass Signals and Slots between threads, you have to be careful. First, check the connection type for the connect call, its acutally the last parameter.
connect( workerClassObj, &workerClass::mySignal, this, &webcamClass::mySlot, Qt::QueuedConnection );
For a detailed explanation look here:
http://doc.qt.io/qt-5/signalsandslots.html
If you want to pass custom types, you have to declare them as metatypes first.
Add e.G. this in your constructor:
qRegisterMetaType("MyDataType");
Please make sure, that your custom datatype has a default constructor and be aware that afaik, references cannot be passed across threads.

signal and slot in QT

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/

Using Qthread to run a function

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

Emit signal between two classes in Qt

A am trying to make a program that takes a signal from one class and with activation of that signal I want to activate a slot in second class.
In my case the first class is the mainWindow class, this class is subClass of QMainWindow, and in this class is the slot that I want to activate.
This is mainWindow.cpp:
mainWindow::mainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::mainWindow)
{
ui->setupUi(this);
}
mainWindow::~mainWindow()
{
delete ui;
}
void mainWindow::slotForStatusBarMessage(QString string)
{
statusBar()->showMessage(string);
}
The second class is the mainWidget class and it is a subclass of QWidget.
This is mainWidget.cpp:
mainWidget::mainWidget(QWidget *parent) :
QWidget(parent)
{
buttonAddNewRecord=new QPushButton("Add new record", this);
layoutButton=new QHBoxLayout();
layoutButton->addWidget(buttonAddNewRecord);
layoutMain=new QVBoxLayout();
layoutMain->addLayout(layoutButton);
functionDatabaseOpen();
setLayout(layoutMain);
}
The signal is emited from functionDatabaseOpen() function:
if (sqlDatabase.open())
{
emit signalForShowMessageInStatusBar("true");
}
else
{
emit signalForShowMessageInStatusBar("false");
}
I have made all the settings to the database but i didnt copy here because of space.
I have tried to make connection inside main.cpp but it seems it dosent work.
QObject::connect(mw, SIGNAL(signalForShowMessageInStatusBar(QString)), w, SLOT(slotForStatusBarMessage(QString)));
I cant make this signal/slot connection between classes to work. Can you give me any help.
If you have any question about the code please ask. Sorry for the bad english,I am not a native english speaker.
Thank you very much for your help.
You are emitting the signal from the constructor of mainWidget, and since the connection is only done after you return from that constructor, the signal doesn't go anywhere.
The easiest fix, not knowing what the rest of the code looks like, would be to move the call to functionDatabaseOpen() in main() after the signal/slot connection is made.