Consider functions like below:
class1::class1()
{
class3 obj3 = new class3(this);
}
void class1::function1()
{
class2 *obj2 = new class2();
connect(obj3, SIGNAL(sig()), obj2, SLOT(slt()));
}
void class3::function2()
{
emit sig();
}
I am invoking function1() multiple times.
function2() is also triggered multiple times
What I want is, whenever sig() is emitted slt() should be called, but what's happening is, first time when sig() is emitted slt() is being called number of times function1() is invoked.
Next time when sig() is invoked slt() is not called.
It would be a great help, if somebody can help me achieve this.....
You should only call connect once. Move your code that calls connect to a different function that is only called once.
So I´m not sure you understand what you are doing or what you want. So I´ll explain what is happening and then we can rethink what you want. Qt is working as expected. You said you want the slot to be called whenever the signal is emitted. That is exactly what your code is doing.
Now the question is ... are you aware that you create a new instance of your class2 each time function1 is called? Are you sure you didn´t just want a single instance of class2? Because that would then behave more in the way that you want it to.
class2 *obj = 0;
void class1::function1()
{
if(!obj)
{
obj = new class2();
connect(this, SIGNAL(sig()), obj, SLOT(slt()));
}
}
void class2::function2()
{
emit sig();
}
Since I have no idea where you create an object of class1, I just gave you something based on what you gave us. This should behave in the way you want it to. If that confuses you, I would suggest you should google some tutorials on learning C++, or object oriented programming (OOP) for that matter. Unfortunately I cannot recommend you any books/tutorials or else I would.
I hope this helps you.
Related
I have an annoying issue with Qt and multi threading. Below I have created some simplified code. In my real code, the principle is exactlty the same but way too complex hence for using a simplified version.
The problem is that the application randomly crashes during different points at the run-time with different messages:
free(): invalid pointer
double free or corruption
The crash is triggered from within Qt, I will explain at the end of the post.
Here is how the code works.
So, I have classA that starts a thread:
class classA
{
public:
void start();
boost::function<void (std::string)> __ptr; // for callback
private:
boost::thread * thread;
void run();
};
void classA:start()
{
thread = new boost::thread(&classA::run, this); // start the thread
}
and here is the actual method that runs in the separate thread:
void classA::run()
{
for (int i = 0; i < 50000; i++)
{
static int count = 0;
__ptr("test123" + std::to_string(++count));
}
}
In my QDialog inherited class, I have a simple method that assigns the boot::function so I have declared another boost::function ptr. The problem is not with the ptr, it is with Qt, read on, the call back works just fine...
class myClassB : public QDialog
{
Q_OBJECT
public:
explicit myClassB (QWidget *parent);
classA ca;
private:
boost::function<void (std::string)> __ptr;
void mycallback(std::string);
};
In the constructor of myClassB, I am assigning my call back to boost::function like this (like I said, the callback works fine).
myClassB::myClassB()
{
this->__ptr = ( boost::bind( &myClassB::mycallback, this, _1 ) );
ca.__ptr = __ptr;
}
Here is where the problem starts. In my callback within my classB QDialog, I emit a Qt signal
void myClassB::mycallback(std::string txt)
{
emit sig_qt_data_received(txt);
}
This signal gets connected in my classB's constructor:
connect(this, SIGNAL(sig_qt_data_received(std::string)), this, SLOT(data_received(std::string)), Qt::DirectConnection);
and finally, the implementation of the Qt slot:
void myclassB::data_received(std::string txt)
{
ui->lbl_status->setText(txt);
}
This is where the problem is:
If you remove ui->lbl_status->setText(txt);, the program works flawlessly, it never crashes, if you leave it, it randomly crashes:
free(): invalid pointer
double free or corruption
It appears that the problem is within Qt as when I remove the setText() references, it does not crash and I have followed just about every GUI multi-threading procedure I have found and I don't know what I am doing wrong.
To connect the Qt signal, I am using Qt::DirectConnection and if I use Qt::AutoConnection it will work without a crash but sometimes the whole UI freezes (Edit: this is incorrect, see my answer).
I hope someone can help. If you need more code / real code, let me know, I will write an actual runnable code that you can run and compile but the fundamentals are the same, that's how the code works.
I don't want to be using QThread.
Resolved! Qt::DirectConnection was the culprit, now I use Qt::AutoConnection and it never crashes and according to the docs it is the default:
(Default) If the receiver lives in the thread that emits the signal,
Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
The connection type is determined when the signal is emitted.
G.M's response above gave me the hint (Thanks):
the fact that explicitly specifying the connection type as
Qt::DirectConnection changes the behaviour suggests you've almost
certainly got a race condition due to threading
Also thank you jpo38 for suggesting / replying anyway.
Now I know I said sometimes it would freeze but no, that's incorrect, it never freezes, I had confused things.
Is this a correct way terminate the thread ...
if(m_ReviewImageThreadLoader !=NULL)
{
m_ReviewImageThreadLoader->quit();
m_ReviewImageThreadLoader->wait();
m_ReviewImageThreadLoader->terminate();
delete m_ReviewImageThreadLoader;
m_ReviewImageThreadLoader = NULL;
qDebug()<<"m_ReviewImageThreadLoader closed"<<endl;
}
... where m_ReviewImageThreadLoader is the thread object.
The answer to your question depends to a large extent on the nature of the work being done on your thread. If the usage is something like...
QThread *m_ReviewImageThreadLoader = new QThread;
MyObject *mo = new MyObject;
mo->moveToThread(m_ReviewImageThreadLoader);
m_ReviewImageThreadLoader->start();
then your code should be fine (although you really shouldn't need the call to terminate()).
If, on the other hand, m_ReviewImageThreadLoader is of a type derived from QThread and has explicitly overridden QThread::run then you'll need to supply more information before your question can be answered.
Have you tried your code? Does it appear to work?
I gathered a code of an application called calendar from the base of examples of the Qt Framework. I am trying to learn from it and add there some functionality. The problem right now that I've got is that I want to implement two function to the two button that I created ( one for increase counting of the days and the second for decrease ).
The code that I added to the function for increasing the days is:
void MainWindow::forward(int *click_forward)
{
click_forward++;
}
and the code added to the function for decreasing the days:
void MainWindow::backwards(int *click_backwards)
{
click_backwards--;
}
In the constructor I defined a variable named click which of the int
type, and I sent this variable to the both function by reference:
forward(&click);
backward(&click);
In the header file, in the public slosts area these both functions are
defined as:
void forward(int *click_forward);
void backwards(int *click_backwards);
I also implemented two SIGNAL-SLOT connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward(int
&click)));
QObject::connect(beforebtn, SIGNAL(clicked()), this,
SLOT(backwards(int &clickt)));
But for some reasons when I compile the project I receive an information that:
QObject::connect: No such slot MainWindow::forward(int &click)
QObject::connect: No such slot MainWindow::backwards(int &clickt)
I wanted to use pointers in these two functions, just to work on the original variable itself not on the copy.
Could I please ask you to point me out what I am doing wrong.
Thank you,
The problem is that your signal and slot(s) have different signatures: signal has no arguments, but slot has an argument of pointer type. Besides, even if your signals connections would work, the execution of such code wouldn't do anything useful (at least) as you modify the temporary defined variables click_backwards etc.
I would solve this in the following way:
Define the class member variables and slots:
class MainWindow
{
[..]
private slots:
void forward();
void backwards();
private:
int click_forward;
int click_backwards;
}
Define slots:
void MainWindow::forward()
{
click_forward++;
}
void MainWindow::backwards()
{
click_backwards--;
}
And finally establish connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward()));
QObject::connect(beforebtn, SIGNAL(clicked()), this, SLOT(backwards()));
if you do your signals and slots like this, then you get a compiler error instead of a run time error, which i personally find very helpful since it will just tell you that they wont connect because of incompatible signals/slots
QObject::connect(nextbtn, &QPushButton::clicked, this, &MainWindow::forward);
By the way, you're not increasing the value of the integer, you're increasing the pointer.
That's a bug waiting to happen.
I am very new to Qt; please help me to solve the problem.
I am using a thread to perform intensive operations in the background. Meanwhile I want to update the UI, so I am using SIGNALS and SLOTS. To update UI I emit a signal and update UI.
Let us consider below sample code,
struct sample
{
QString name;
QString address;
};
void Update(sample *);
void sampleFunction()
{
sample a;
a.name = "Sachin Tendulkar";
a.address = "India"
emit Update(&a);
}
In the above code we are creating a local object and passing the address of a local object. In the Qt document, it says that when we emit a signal it will be placed in the queue and late it will be delivered to the windows. Since my object is in local scope it will be delete once it goes out of the scope.
Is there a way to send a pointer in a signal?
You're insisting on doing the wrong thing, why? Just send the Sample itself:
void Update(sample);
//...
sample a("MSalters", "the Netherlands");
emit Update(a);
Unless you've determined that this code is a performance bottleneck you would be better to just pass a copy of the object rather than a pointer.
Really, I mean it.
However, if you must use pointers then use a boost::shared_ptr and it will delete itself.
void Update(boost::shared_ptr<sample> s);
void sampleFunction()
{
boost::shared_ptr<sample> a = boost::shared_ptr<sample>(new sample());
a->name = "Sachin Tendulkar";
a->address = "India"
emit Update(a);
}
I was working for a while with different C++ GUI frameworks (e.g. Qt, wxWidgets, also some proprietary) but cannot decide for myself regarding the topic described below.
As discussed in several questions/answers here, direct use of delete this is valid in C++ (as long as you don't dereference this any more), but it is in most cases not good idea.
But in some cases, object invokes its destructor indirectly. This situation specifically often arise in event drive systems (GUI applications come to mind first).
class Kernel {
public:
void Start() {
_window = new Window();
}
void OnCloseButton() {
if (_window) {
_window->Close();
delete _window;
_window = NULL;
}
private:
MyWindow * _window;
};
class MyWindow
{
public:
MyWindow(Kernel & kernel) : _kernel(&kernel) {
Connect(my_button_close_event, this, OnCloseButtonClicked);
}
OnCloseButtonClicked() {
// This call actually calls destructor of this object.
_kernel->OnCloseButton();
// If we access any fields of Window here, we're going to have problems
}
private:
Kernel * _kernel;
};
Notice: I did not try to compile the code - it may have typos or bad practices. But it should illustrate the idea.
So, the question is: Is it OK to do something like in the example above: the handler of the event calls some other function (method of its owner), which indirectly deletes this?
Or should I better make the Kernel class event aware and connect the event from the button directly to the method in the Kernel and then we do not have this situation of indirect call to delete this.
Thanks in advance.
It's possible to do so since the Window instance is created by the Start() method but it's a bad practice in Object Oriented Programming.