We have a QCheckBox object, when user checks it or removes check we want to call a function so we connect our function to stateChanged ( int state ) signal. On the other hand, according to some condition we also change the state of QCheckBox object inside code, and this causes the unwanted signal.
Is there any way to prevent firing signal under some conditions?
You can use the clicked signal because it is only emitted when the user actually clicked the check box, not when you manually check it using setChecked.
If you just don't want the signal to be emitted at one specific time, you can use QObject::blockSignals like this:
bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);
The downside of this approach is that all signals will be blocked. But I guess that doesn't really matter in case of a QCheckBox.
You can always block signal emission on QObjects using QObject::blockSignals(). Note that to be correct about things, you should remember the old state (returned from the function call), and restore it when you are done.
At my job, we prefer RAII for this sort of thing. A simple class to do so might look like this:
class SignalBlocker
{
public:
SignalBlocker( QObject *obj ) : m_obj( obj ), m_old( obj->blockSignals( true ) )
{
}
~SignalBlocker()
{
m_obj->blockSignals( m_old );
}
private:
QObject *m_obj;
bool m_old;
};
Edit: Starting with Qt 5.3, see QSignalBlocker (h/t to HappyCactus in comments)
While learning Qt, I ran into this problem with a set of interconnected widgets that I wanted to update "atomically". I liked #cjhuitt's solution, but found that it goes even better with a bit of syntactic sugar based on proxy objects. Here's the approach that I used...
First, I defined a class template for a blocker proxy object. Like Caleb's, this blocks the signals on construction, and then restores their previous state on destruction. However, it also overloads the -> operator to return a pointer to the blocked object:
template<class T> class Blocker {
T *blocked;
bool previous;
public:
Blocker(T *blocked)
: blocked(blocked),
previous(blocked->blockSignals(true)) {}
~Blocker() { blocked->blockSignals(previous); }
T *operator->() { return blocked; }
};
Next, I defined a small template function to construct and return a Blocker:
template<class T> inline Blocker<T> whileBlocking(T *blocked) {
return Blocker<T>(blocked);
}
Putting this all together, I'd use it like this:
whileBlocking(checkBox)->setChecked(true);
or
whileBlocking(xyzzySpin)->setValue(50);
This gets me all the benefits of RAII, with automatically paired blocking and restore around the method call, but I don't need to name any wrapper or state flags. It's nice, easy, and pretty darn foolproof.
You can QObject::disconnect to remove the corresponding signal-slot connection and can QObject::connect again once you are done...
In QObject derived classes, you can call blockSignals(bool) to prevent the object from emitting signals. So for example:
void customChangeState(bool checked)
{
blockSignals(true);
ui->checkBox->setCheckState(Qt::Checked);
// other work
blockSignals(false);
}
The above method would change the check state without clicked, stateChanged, or any other signals being emitted.
Qt5.3 introduced the QSignalBlocker class that does exactly what needed in an exception safe way.
if (something) {
const QSignalBlocker blocker(someQObject);
// no signals here
}
Even in QT5, its a bit cumbersome when there are many/several things to block. Here's a multi-object version that is concise to use:
class SignalBlocker
{
public:
SignalBlocker(QObject *obj)
{
insert( QList<QObject*>()<<obj );
}
SignalBlocker(QList<QObject*> objects)
{
insert(objects);
}
void insert(QList<QObject*> objects)
{
for (auto obj : objects)
m_objs.insert(obj, obj->signalsBlocked());
blockAll();
}
void blockAll() {
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals(true);
}
~SignalBlocker()
{
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals( m_objs[m_obj] );
}
private:
QMap<QObject*,bool> m_objs;
};
usage:
void SomeType::myFunction()
{
SignalBlocker tmp( QList<QObject*>()
<< m_paramWidget->radioButton_View0
<< m_paramWidget->radioButton_View1
<< m_paramWidget->radioButton_View2
);
// Do more work, ...
}
When some UI element should not respond to user it is appropriate to disable it. So that user would know that this element is not accepting input.
Related
I made a widget (QDataflowCanvas) based on QGraphicsView, where I connect the signal QGraphicsScene::selectionChanged() to the slot MainWindow::onSelectionChanged of my main window:
void MainWindow::onSelectionChanged()
{
// canvas is ptr to QDataflowCanvas, subclass of QGraphicsView
auto selNodes = canvas->selectedNodes();
auto selConns = canvas->selectedConnections();
...
}
The problem happens when I close my MainWindow and there is some item selected in the QGraphicsView.
I don't think I need to provide the complete code (although it can be found here), as I already isolated the cause of the crash.
This is what will happen (in order of causality):
destructor of MainWindow is called
destructor of QDataflowCanvas is called
destructor of QGraphicsView is called
destructor of QGraphicsScene is called, which triggers the removal of all items (with clear())
destructor of a QGraphicsItem is called
that will trigger a selectionChange event
the MainWindow::onSelectionChanged slot is called
method QDataflowCanvas::selectedNodes() is called, but the object is destroyed
crash!
which can be seen more in detail from the stack trace of the crash:
I found this workaround: if I disconnect the signal in MainWindow::~MainWindow, it will of course not crash:
MainWindow::~MainWindow()
{
QObject::disconnect(canvas->scene(), &QGraphicsScene::selectionChanged, this, &MainWindow::onSelectionChanged);
}
But this seems a rather atypical practice: I never found myself having to manually severe signal-slot connections because the program would otherwise crash.
There must be a more proper solution to this.
First of all, the name of your project is a mistake. The Q-prefixed namespace is taken. You should not be having any Q-prefixed classes in any project that uses Qt. You should rename the project to DataflowCanvas, for example.
There are three solutions:
Hold all children by value, order the children according to their dependencies. The QWidgetPrivate::deleteChildren called from QDataFlowCanvas will be a no-op, or at least it won't be touching objects you care about.
Use the old connect syntax when connecting to the MainWindow::onSelectionChanged slot. Note that when your slot was invoked, the mainwindow object was of the QWidget dynamic type, not MainWindow type. The connections made using the old connect syntax respect the dynamic type of the object, and a connection made to a slot of given class will guarantee that the object is of that class dynamically, i.e. at runtime.
Clear the selection in the destructor - then no futher selection changes will be handled.
The first solution makes everything explicit and is the one I'd use:
class DataFlowCanvas : public QGraphicsView {
...
private:
QDataflowModel *model_;
QDataflowTextCompletion *completion_;
QSet<QDataflowNode*> ownedNodes_;
QSet<QDataflowConnection*> ownedConnections_;
QMap<QDataflowModelNode*, QDataflowNode*> nodes_;
QMap<QDataflowModelConnection*, QDataflowConnection*> connections_;
bool showIOletsTooltips_;
bool showObjectHoverFeedback_;
bool showConnectionHoverFeedback_;
qreal gridSize_;
bool drawGrid_;
QGraphicsSecene scene_;
};
The scene is destructed before any other fields. Problem solved. You should hold everything else by value as well. E.g. completion_, etc. The pointer indirections are not useful.
The second solution highlights an unfortunate Qt bug. To wit -- in the code below, the old connect syntax will never invoke Derived2::aSlot2, because at the time the slot is invoked, the object isn't of the Derived2 type anymore:
#include <QtCore>
int ctr1, ctr2;
struct Derived1 : QObject {
Q_SLOT void aSlot1() { ctr1++; qDebug() << __FUNCTION__; }
Q_SIGNAL void aSignal();
~Derived1() { Q_EMIT aSignal(); }
Q_OBJECT
};
struct Derived2 : Derived1 {
Q_SLOT void aSlot2() { ctr2++; qDebug() << __FUNCTION__ << qobject_cast<Derived2*>(this); }
Q_OBJECT
};
int main() {
{
Derived2 d;
QObject::connect(&d, &Derived2::aSignal, &d, &Derived2::aSlot2);
QObject::connect(&d, SIGNAL(aSignal()), &d, SLOT(aSlot2()));
QObject::connect(&d, SIGNAL(aSignal()), &d, SLOT(aSlot1()));
}
Q_ASSERT(ctr1 == 1);
Q_ASSERT(ctr2 == 1);
}
#include "main.moc"
The output clearly demonstrates the problem:
aSlot2 QObject(0x0) <-- aSlot2 called but `this` is of `Derived1*` type!
aSlot1
I was taking it so simple :) What about just checking canvas pointer:
void MainWindow::onSelectionChanged()
{
if (!qobject_cast<QGraphicsScene*>(canvas))
return;
auto selNodes = canvas->selectedNodes();
auto selConns = canvas->selectedConnections();
...
}
I used qobject_cast to check if pointer canvas still exists. You can check in other (better) way. The code works.
// Example class
class A : public QObject
{
Q_OBJECT
void fun() {
Timer::SingleShot(10, timerSlot); //rough code
}
public slot:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a deleted
In this case after a is deleted and timer is fired, would it execute timerSlot()? I'm getting an extremely rare crash and not sure if it's because of something fishy in this logic.
Even if the timer fires, it won't trigger the slot. The docs of ~QObject state: All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue. The only way you can trigger the A::timerSlot and delete A at the same time is if you use threads.
You are not obligated to disconnect an object's signals and slots before deleting it.
The QObject destructor will clean up obsolete signal-slot connection for you, as long as you:
Inherit from QObject
Use the Q_OBJECT macro in your class definition
Following these conventions ensures that your object emits a destroyed() signal when deleted. That's actually what Qt's signals-and-slots system uses to clean up dangling references.
You can listen to the destroyed() signal yourself if you'd like to add some debugging code to track object lifecycles.
(Depending on the particular version of Qt/moc you are using, it's quite possible that code with a non-QObject using slots, or a QObject-derived class that doesn't have Q_OBJECT in its header will still compile but cause the timerSlot() method to be invoked on a garbage pointer at runtime.)
I'm getting a extremely rare crash due to timer out of object scope which I need to fire just once. I use QTimer::singleShot which is static method and does not pertain to an instance of QTimer object which I would release with the context it fires the signal to.
That is of course solved in QTimer class and desired behavior controlled by the instance of timer class with non-static QTimer::singleShot property set to true.
// declaration
QScopedPointer<QTimer> m_timer;
protected slots:
void onTimeout();
// usage
m_timer.reset(new QTimer);
m_timer->setSingleShot(true);
QObject::connect(m_timer.data(), SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer->start(requiredTimeout);
So, no crash should happen due to timer released with the context object.
Edit: This answer was in response to the original question which did not use QObject but had class A as a standalone class inheriting nothing. The question was later edited making this answer obsolete, but I'll leave it here to show what would be needed if not using QObject.
The only way you can do that is if you keep the object alive until the timer has fired. For example:
class A : enable_shared_from_this<A> {
void fun() {
QTimer::singleShot(10, bind(&A::timerSlot, shared_from_this()));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a goes out of scope, but its referent is kept alive by the `QTimer`.
The reason the above works is that you capture a shared_ptr to class A when setting the timer, and the timer will hold onto it (else it can't fire).
If you don't like or can't use recent C++ features or Boost:
struct Functor {
Functor(SharedPointer<A> a) : _a(a) {}
void operator() { a->timerSlot(); }
SharedPointer _a;
};
class A {
void fun(shared_ptr<A> self) {
QTimer::singleShot(10, Functor(self));
}
public:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun(a);
To reach certainty, you can stop the timer yourself:
class A : public QObject {
QTimer t;
A() { connect(Signal-Slots); }
~A() { t.stop(); }
fun() { t.start(10); }
...
};
I'm working on a image editing software which includes a few classes. But I need my code to be more generic. But I've got a big problem with my classes when it comes to connections.
QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSmartContrast()));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSaturation()));
I've got a Menu called "Effects", and when the user clicks the QAction actionSmartContrast, then the effect Smart Contrast is added to my effects window. The thing is, given that each effect has its own class, I have to create a function for each class as you can see in the code above. And this is very repetitive. I would like to avoid this problem by doing something like this:
QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new SmartContrast())));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new Saturation())));
Everything would be fine for the function addEffect() because it expects a pointer to an Effect object and both SmartContrast and Saturation inherit from Effect. The only problem is that it is impossible to pass variables in connect() like this. So I thought of subclassing QAction and creating a signal which would return the class I like everytime but again, how to tell my new Action class what class it should return? If I have a thousand effects, I won't subclass QAction a thousand times! I need to create a function which would take for example a pointer to a SmartContrast object and it will guess that it has to return a SmartContrast pointer everytime the Action is clicked. And that would still be possible to do it because of the inheritance from the class Effect. But I really can't figure out how to do that. Any help would be much appreciated. Thanks in advance!
Looks like QSignalMapper is exactly what you're looking for.
UPDATED:
Another way is to use lambda (if Qt version and c++ compiler allows):
QObject::connect(actionSmartContrast, &QAction::triggered, [effectsWindow](){ effectsWindow->addEffect(new SmartContrast()) });
There are several options.
If it is enough to have the base class pointer of the effects because you use e.g. virtual methods following solution should do:
You can create an intermedite class:
class Intermediate : public QObject
{
Q_OBJECT
public:
Intermediate(QObject* parent = 0) : QObject(parent){}
signals:
void triggerEffect(Effect*);
public slots:
void effectTriggered()
{
QAction* action = qobject_cast<QAction*>(QObject::sender());
if ( action ) {
std::map<QAction*,Effect*>::iterator it = m_mapping.find(action);
if ( it != m_mapping.end() )
{ emit triggerEffect( it->second ); }
}
}
public:
void registerActionEffectPair(QAction* action,Effect* effect)
{ m_mapping[action]=effect; }
private:
std::map<QAction*,Effect*> m_mapping;
};
To use your Effect base class as type for signals and slots, you have to register it as a metatype:
qRegisterMetaType<Effect*>();
Connect it:
QObject::connect(intermediateInstancePtr, SIGNAL(triggerEffect(Effect*),
effectsWindow, SLOT(addEffect(Effect*)));
And the connections of each action would look like:
intermediateInstancePtr->registerActionEffectPair( yourEffectAction, theEffectPtr );
QObject::connect(yourEffectAction, SIGNAL(triggered(bool)),
intermediateInstancePtr, SLOT(effectTriggered()));
Another one could be to use QObjects properties:
setProperty( "property", "value" )
Call this for each effect QAction and read the property in the slot "addEffect".
The property can be read by calling
QAction* action = qobject_cast<QAction*>(QObject::sender());
if ( action ){
QVariant val = action->property("property");
if ( val.isValid() )
{
//TODO
}
}
since Object::sender returns the sender which is responsible for the slot call.
Afterwards you can do a switch case or stuff like this to distinguish between the different effects.
I finally solved my problem! I subclassed QAction and added a signal to my new class which creates a new effect from the class I want depending on the property text(). Simple if blocks are enough. Thank you all for your answers!
I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum
To make a function of a class to be a slot, the class has to inherit from QObject. However, QObject takes up a quite large amount of memory. I am not sure how much it is and if the memory is for each class or each object. My code has many small data whose functions can be a slot sometime. I am wonder if there is a way to make a function of class to be a slot temporally when using it. After using it, the memory for the slot cost will be deleted. The following code illustrates the requirement.
class SmallData // size of 2 or 3 integers.
{
public:
virtual void F(); // use it as a slot.
virtual QMenu* createMenu(); // use this to create the context menu with
// an action connected to F()
...
};
// use the small data
vector<SmallData> vec(1000000); // the vector is put at a tree view. When an
// item in the tree view is selected, a context
// menu pop up with an action to run F().
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()), data, SLOT(F())); // How to make F() to be
// a slot just here.
// The action is from
// data->createMenu().
If you can use Qt5, you can connect signals to plain functions and static methods (which essentially are funnily named plain functions):
connect(action, &QAction::triggered,
&SmallData::statF);
Where action is a QAction instance, and SmallData::statF is a static method of SmallData.
Edit per Christian Rau's comment, to call a particular instance, you can also connect to lambda:
connect(action, &QAction::triggered,
[data]() { data->F(); });
Already with Qt4, you can use QSignalMapper to achieve much the same effect, with a few more objects. It allows you to add add a parameter (in this case, probably an integer index to your vec) to signal, based on which object emitted it. But in Qt4, receiver must still always be a QObject.
For using the signal slot mechanism, you won't get around QObject, but what you can do is create a temporary object that has a slot calling your function. You just have to care for properly releasing the object. Something like:
class Callback : public QObject
{
Q_OBJECT
public:
typedef std::function<void()> FunctionType;
Callback(FunctionType fn, bool oneShot = true, QObject *parent = nullptr)
: QObject(parent), fn_(std::move(fn)), oneShot_(oneShot) {}
public slots:
void call()
{
fn_(); //delegate to callback
if(oneShot_)
deleteLater(); //not needed anymore
}
private:
FunctionType fn_;
bool oneShot_;
};
Callback* makeCallback(FunctionType fn, bool oneShot = true, QObject *parent = nullptr)
{
return new Callback(std::move(fn), oneShot, parent);
}
You then just create a (more or less temporary) Callback object each time needed:
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()),
makeCallback(std::bind(&SmallData::F, data)), SLOT(call()));
With the oneShot parameter you can control if the slot should dissolve automatically once triggered.
The only problem is, if this slot is never called, you have a leaking Callback hanging around. To accomodate this, you can pass something meaningful into the parent argument, so that Qt cares for proper deletion at least at some later point in time:
SmallData* data = treeView.selectedItem();
connect(action, SIGNAL(triggered()),
makeCallback(std::bind(&SmallData::F, data), true, this), SLOT(call()));
This way you can also bind the lifetime of the callback object (and thus the signal-slot connection) to some other object (e.g. the action itself and deleting the action when no item is selected, or something the like).
Alternatively, you can also remember the Callback object for the currently selected item and care for proper deletion yourself, once it's delesected.
disclaimer: Beware that the above example contains plenty of C++11, but I'm not in the mood to rewrite this for C++03. Likewise can this solution be imporved further, maybe using a templated functor instead of a std::function (but if I remember correctly the Qt meta object system doesn't like templates that much).
EDIT: In the end the solution proposed by Frank Osterfeld in his comment might be a much simpler approach for your situation than my overly generic object lifetime madness above: Just connect the action to a single slot of a higher level object (your main widget or maybe the item model containing the data vector) and call F on the currently selected item:
connect(action, SIGNAL(triggered()), this, SLOT(callF()));
...
void MyController::callF()
{
treeView.selectedItem()->F();
}
I don't think that what you try to do is possible in Qt.
If you really don't want to inherit QObject, then I suggest you have a look at the boost signals and slots mechanism.