enthought / enthought/traitsui
ArrayEditor not updated for changes from observer
- Dominant language
- Python
- Stars
- 306
- Forks
- 99
- PR merge metrics
- No merged PRs in 30d
Description
When editing a cell of an array with an `ArrayEditor`, sometimes it's useful to be able to monitor the modified array for changes and to make changes to other cells in the array as a result of a change to an edited cell. Currently, the array editor doesn't show the result of those changes (though the read-only array editor does).
Below is a code example, cut down from something more real. This shows a 2-by-2 array of values. The intent is that in "locked" mode, when one array entry is changed, all corresponding model values should be updated, while in unlocked mode, only the target value is updated.
The read-only view of the array shows the actual values held in the array, but the editable view doesn't get updated for new values. Here's a screenshot showing that:

```python
import numpy as np
from qt_binder.loopback_guard import LoopbackGuard
from traits.api import (
Array,
Bool,
Float,
HasStrictTraits,
Instance,
List,
observe,
)
from traitsui.api import HGroup, Item, ModelView, VGroup, View
class Member(HasStrictTraits):
girth = Float()
class Gang(HasStrictTraits):
members = List(Instance(Member()))
class ExtentsView(ModelView):
model = Instance(Gang)
locked = Bool(True)
display_girths = Array(shape=(2, 2), dtype=np.float64)
_guard = Instance(LoopbackGuard, args=())
@observe("model:members:items:girth")
def _update_displayed_array_when_girths_change(self, event):
index = self.model.members.index(event.object)
new_display_girths = self.display_girths.copy()
new_display_girths.flat[index] = event.new
with self._guard("model"):
self.display_girths = new_display_girths
def _display_girths_default(self):
girths = [member.girth for member in self.model.members]
return np.array(girths).reshape((2, 2))
@observe("display_girths")
def _update_model_on_edit(self, event):
# If this was triggered by a model change, do nothing
if "model" in self._guard:
return
# Figure out which value changed
old = event.old.ravel()
new = event.new.ravel()
(changed,) = np.where(old != new)
# Don't try to deal with the case where multiple values changed
# simultaneously, or no values changed.
if len(changed) != 1:
return
index = changed[0]
value = new[index]
if self.locked:
# Keep all girths in lockstep.
for member in self.model.members:
member.girth = value
else:
# Update only the edited value
self.model.members[index].girth = value
view = View(
HGroup(
VGroup(
Item("locked"),
Item("display_girths"),
Item("display_girths", style="readonly"),
),
),
)
if __name__ == "__main__":
members = [
Member(girth=1.2),
Member(girth=5.6),
Member(girth=2.7),
Member(girth=3.4),
]
star = Gang(members=members)
girths_view = ExtentsView(
model=star,
)
girths_view.configure_traits()
```
The immediate cause seems to be the `_busy` flag in the array editor implementation.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.