Commit 4f72e6fd authored by Artur Grunau's avatar Artur Grunau
Browse files

Update property widgets in the GUI thread

AbstractPropertyWidget's onPropertyChanged slot is invoked from non-GUI
threads. Previously, it would call updateWidgetFromProperty directly,
which resulted in Qt widgets being accessed from non-GUI threads. This
in turn led to random crashes when properties were modified quickly and
repeatedly from the GUI.

Now we invoke updateWidgetFromProperty via a signal-slot connection with
an internal signal, s_propertyChanged. This makes Qt take care of
queueing slot accesses in the GUI thread for us.

Fixes #36
parent 8b316f0c
......@@ -58,6 +58,7 @@ namespace campvis {
}
_property->s_changed.connect(this, &AbstractPropertyWidget::onPropertyChanged);
connect(this, SIGNAL(s_propertyChanged(const AbstractProperty*)), this, SLOT(updateWidgetFromProperty()));
}
AbstractPropertyWidget::~AbstractPropertyWidget() {
......@@ -70,6 +71,6 @@ namespace campvis {
void AbstractPropertyWidget::onPropertyChanged(const AbstractProperty* property) {
if (_ignorePropertyUpdates == 0)
updateWidgetFromProperty();
emit s_propertyChanged(property);
}
}
......@@ -62,24 +62,34 @@ namespace campvis {
*/
virtual ~AbstractPropertyWidget();
public slots:
protected:
/**
* Adds a widget to the local Qt layout.
*/
void addWidget(QWidget* widget);
AbstractProperty* _property; ///< The property this widget handles
/// Semaphore acts as flag whether the widget shall ignore incoming signals from properties being updated.
tbb::atomic<int> _ignorePropertyUpdates;
protected slots:
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void updateWidgetFromProperty() = 0;
AbstractProperty* _property; ///< The property this widget handles
/// Semaphore acts as flag whether the widget shall ignore incoming signals from properties being updated.
tbb::atomic<int> _ignorePropertyUpdates;
signals:
/**
* Internal signal used to update the property widget in a thread-safe way.
*
* This class' \ref onPropertyChanged() slot is invoked from non-GUI threads. As a result,
* \ref updateWidgetFromProperty() couldn't access any Qt widgets safely if it was called from there directly,
* because it would execute in a non-GUI thread. However, if we invoke \ref updateWidgetFromProperty() via
* a signal-slot connection with \ref s_propertyChanged(), Qt takes care of queueing slot accesses in the GUI
* thread for us.
*/
void s_propertyChanged(const AbstractProperty* property);
private:
/// Slot getting called when the property has changed, so that the widget can be updated.
......
......@@ -46,7 +46,6 @@ namespace campvis {
addWidget(_adjuster);
connect(_adjuster, SIGNAL(valueChanged(double)), this, SLOT(onAdjusterValueChanged(double)));
connect(this, SIGNAL(propertyValueChanged(double)), _adjuster, SLOT(setValue(double)));
property->s_minMaxChanged.connect(this, &FloatPropertyWidget::onPropertyMinMaxChanged);
}
......@@ -57,7 +56,7 @@ namespace campvis {
void FloatPropertyWidget::updateWidgetFromProperty() {
FloatProperty* prop = static_cast<FloatProperty*>(_property);
_adjuster->blockSignals(true);
emit propertyValueChanged(prop->getValue());
_adjuster->setValue(prop->getValue());
_adjuster->blockSignals(false);
}
......
......@@ -60,10 +60,6 @@ namespace campvis {
*/
virtual void updateWidgetFromProperty();
signals:
/// Signal emitted when the property's value changes
void propertyValueChanged(double value);
private slots:
/// Slot getting called when the adjuster's value changes
void onAdjusterValueChanged(double value);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment