Here's a sample of a SpinBox that writes its changes to underlying variables. The main problem that I'm having is valueChanged is called when the widget is constructed. Is there a more elegant way to do this? I think it's weird that I connected a widget to itself, but valueChanged isn't virtual.
class ValueWriterInt: public QSpinBox {
Q_OBJECT
public:
ValueWriterInt(vector<int*> const& value): myValue(value) {
QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
}
~ValueWriterInt() {}
private slots:
void valueChanged(int new_value) {
for (auto it = myValue.begin(); it != myValue.end(); ++it)
**it = new_value;
}
private:
vector<int*> myValue;
};
-
So what are you trying to accomplish here? Yep, valueChanged ain't virtual -- why should it be, your objects should directly connect their own slots to whatever signals they want to react to, no?
MSalters : Virtual calls are significantly more efficient than signal/slots. Doesn't matter a whole lot for anything UI-driven, though.Neil G : I am trying to build a parameters pane, where the custom widgets on the pane live in a tree. It is turning out to be a lot harder than I thought... -
I see no other alternative than to use SIGNAL-SLOT connections. However, I would change the name of the slot, so it doesn't have the same name as the signal.
It is intriguing how the slot is called even if there is no connection done yet. I suspect that changing the name of the slot will solve that issue.
Neil G : Two good points. Thanks. I ended up changing the name just to be sure. And, I figured out that the signal was being called when the widget was being inserted into the tree using setIndexWidget().Ariya Hidayat : It's perfectly fine if valueChanged(int) is called at the construction. It is after all **a signal**, and not a slot. -
I see nothing particularly weird about connecting a widget to itself. Having a single method of detecting and responding to data updates actually sounds like a good thing because you have fewer points of failure to check when you are debugging. In your specific case, it is causing some undesired behavior, but in general it is a fine solution.
Now, having expressed the opinion that a reflexive connection isn't inherently inelegant, I am going to suggest a less than "elegant" solution to prevent the calling of
valueChangedafter construction. You can have a flag to determine whether the object was just constructed and return early to prevent the code being run immediately after construction. In your example:class ValueWriterInt: public QSpinBox { Q_OBJECT public: ValueWriterInt(vector<int*> const& value): myValue(value), myAfterInit(true) { QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int))); } ~ValueWriterInt() {} private slots: void valueChanged(int new_value) { if (myAfterInit) { myAfterInit = false; return; } for (auto it = myValue.begin(); it != myValue.end(); ++it) **it = new_value; } private: vector<int*> myValue; boolean myAfterInit; };That isn't too bad of a solution. It will at least give you your desired behavior until (and if) you can find a more elegant method.
Neil G : Thank you. This is what I ended up doing, but it is extremely reassuring to have independent confirmation. valueChanged gets called a lot more often than I thought. For example, calling "setIndexWidget" causes valueChanged to be called on the widget. The bool helps there too. Thanks again!
0 comments:
Post a Comment