QT5 Slot not called in subclass - c++

I have a superclass BackgroundWorkerWithWaitDialog that manages a WaitDialog that implements a progress bar box with an "abort" button. It is used as a QObject in a QThread.
My intention is to derive any background task from BackgroundWorker and implement only the execute() command, polling for an aborted flag to stop it.
BackgroundWorkerWithWaitDialog is derived from BackgroundWorker that is a QObject, all classes are Q_OBJECT and the worker classes are able to update the gui using signals and slots. This communication (Worker to Gui Object) is working correctly.
The problem is that though WaitDialog responds to the pushbutton click, the aborted() signal is emitted from the WaitDialog but isn't received by the BackGroundWorker. (Gui -> Worker)
class WaitDialog : public QDialog
{
Q_OBJECT
public:
explicit WaitDialog(QWidget *parent = 0);
~WaitDialog();
public slots:
void setText(QString text);
void setProgress(bool shown, int max);
void enableAbort(bool enable);
void setProgression (int level);
signals:
void aborted();
private slots:
void on_cmdAbort_clicked();
private:
Ui::WaitDialog *ui;
};
void WaitDialog::on_cmdAbort_clicked()
{
qDebug() << "ABORT";
emit aborted();
}
...
/// BackgroundWorker is QObject-derived.
class BackgroundWorkerWithWaitDialog : public BackgroundWorker
{
Q_OBJECT
public:
explicit BackgroundWorkerWithWaitDialog(MainWindow *main, WaitDialog *dialog);
...
public slots:
virtual void abortIssued();
....
BackgroundWorkerWithWaitDialog::BackgroundWorkerWithWaitDialog(MainWindow *main, WaitDialog *dialog)
: BackgroundWorker(main),
mWaitDialog(dialog),
mAborted(false)
{
connect (this, SIGNAL(progress(int)), mWaitDialog, SLOT(setProgression(int)));
connect (this, SIGNAL(messageChanged(QString)), mWaitDialog, SLOT(setText(QString)));
connect (this, SIGNAL(progressBarVisibilityChanged(bool,int)), mWaitDialog, SLOT(setProgress(bool,int)));
connect (this, SIGNAL(abortButtonVisibilityChanged(bool)), mWaitDialog, SLOT(enableAbort(bool)));
connect (mWaitDialog, SIGNAL(aborted()), this, SLOT(abortIssued()));
}
void BackgroundWorkerWithWaitDialog::abortIssued()
{
// THIS IS NEVER EXECUTED
mAborted = true;
}
Is there something I am missing? I temporarily fixed this with a listener pattern, but frankly I don't like this hybrid fix.
Why isn't the abortIssued slot not called ?
Thanks in advance.
So to summarize:
BackgroundWorkerWithWaitDialog (BWWWD) derives from BackgroundWorker that inherits from QObject
BackgroundWorkerWithWaitDialog receive in the constructor a WaitDialog (WD) that is derived from QDialog
BWWWD in the constructor connect()s the waitDialog aborted() signal with the abortIssued() slot
WD emits the signal but abortIssued isn't called
BWWWD is executed in a separate QThread
It would worth saying that BWWWD class is derived by other SpecificWorker classes that implements specific functions that make use of the aborted() function to interrupt the processing.

Your question states:
i have a superclass BackgroundWorker that manages a WaitDialog that implements a progress bar box with an "abort" button.
In the BackgroundWorkerWithWaitDialog constructor you do not pass dialog to BackgroundWorker's constructor, nor do you use a BackgroundWorker member variable when you are setting up your connections.
Either your questions opening statement is wrong, or you are connecting to a dialog that is never used.

Related

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

How to connect two dialogs?

If i click on one dialog button on the other dialog will show some text, it doesnt have to be text basicly connection between two dialogs. Something that will help me about my problem.
If you have two QWidget (or inherited) objects represented as dialogs, then you should use an QObject::connect method. Learn about signals and slots in Qt. It looks like:
class DialogA : public QWidget {
Q_OBJECT
...
public slots:
void ShowSomeText(); // called when receive a signal
...
};
class DialogB : public QWidget {
Q_OBJECT
...
void SendTextSignal(); // sends a signal
...
};
// somwhere in code
DialogA da;
DialogB db;
connect(db, SIGNAL(SendTextSignal()), da, SLOT(ShowSomeText()));

SIGNALS and SLOTS in QT5

I've encountered a following issue:
I have a GUI element class and a Thread class. I would like to exchange signals between them. However it only works in one direction. I can successfuly send a signal from main GUI window to the thread. However when I want to send a signal from the thread to the process that calls the thread, but it doesn't work. Here is how I do it:
bool GfxMapItem::mapSwitch(int seqidx)
{
...
importMapThread_ = new ImportMapThread(sequence_->item(seqidx));
connect(GUI_UI->analExportButton, SIGNAL(clicked()), importMapThread_, SLOT(interrupt1()), Qt::QueuedConnection); //<-- this one works perfectly
connect(importMapThread_, SIGNAL(progress(int)), this, SLOT(loadMap(int)), , Qt::QueuedConnection); // <-- this one unfortunatelly doesn't
...
}
The thread code is very simple and it only emits the signal (I've check that it works when I connect the thread with itself).
void ImportMapThread::run()
{
QLOGX("Running ImportMapThread...");
QLOGINC;
emit this->progress(100);
QLOGX("Stopping ImportMapThread...");
}
The thread header looks like the one below:
class ImportMapThread : public InterruptibleThread
{
Q_OBJECT
private:
...
protected:
...
public:
ImportMapThread(SeqItem *p);
signals:
void progress(int value);
void progressReset(int value);
public slots:
virtual void interrupt1();
void loadMap();
protected:
virtual void run();
};
And the class that calls that thread looks like this:
class GfxMapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
...
signals:
void mouseOutside();
void mouseMove(const QPointF &pos);
private slots:
void loadMap(int);
protected:
...
};
Any ideas? Please, I've ran out of ideas.
I believe, you should call exec in your run-implementation. Exec starts event-loop which should allow to send signals.
Take a look at:
int QThread::exec() [protected] Enters the event loop and waits until
exit() is called, returning the value that was passed to exit(). The
value returned is 0 if exit() is called via quit(). It is necessary to
call this function to start event handling.
I hope this helps.
Solved! It turned out that only the GUI elements can communicate with the threads. The thread can be inherited from other type of the thread and there isn't any problem neither with the signals nor the slots. The problem was laying in the object GfxMapItem. For some reason it just couldn't handle normal communication.

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.