Why is the uieditfield ValueChangingFcn function called twice?

13 vues (au cours des 30 derniers jours)
Anais G
Anais G le 23 Avr 2021
Modifié(e) : Voss le 27 Sep 2023
To get to know app designer I attempted to create an autocomplete thingy when using a uieditfield. The code is provided below as clear as I could. I cannot discover what's wrong with the code, but it's not working as expected and the callback function is called twice. When I put breakpoints in the callback function, it works as I expect it to (even though it's called twice), but without using breakpoints it doesn't. If I type anything in the uieditfield, then click somewhere else (shift focus), then continue typing in the uieditfield, that's when it gives the autocomplete for the previous value. I'm at a loss, does anyone understand?
clear, clc, close all
% Create figure
fig = uifigure;
% List of names
names = {'Bob';
'Eric';
'John';
'Phil';
'James';
'Anne';
'Suzanne';
'Karen';
'Eleanor';
'Janet';};
% Create table of names
namesTablePos = [28 28 504 203];
namesTable = uitable(fig, ...
'Position', namesTablePos, ...
'ColumnName', 'Names', ...
'Data', names);
% Create editfield
fieldPos = [224, 315, 150, 25];
field = uieditfield(fig, 'text', ...
'ValueChangingFcn', @(h,e) callbackAutoComplete(h,e), ...
'Position', fieldPos);
field.UserData = names;
% Create tree
tree = uitree(fig, ...
'SelectionChangedFcn', @(h,e) callbackSelectionChanged(h,e), ...
'Visible', 'off');
function callbackAutoComplete(src, ~)
% Get figure handle
tree = src.Parent.Children(1);
% Reset tree
tree.Visible = 'Off';
delete(tree.Children)
% Get field value
val = src.Value;
% If value is not empty, populate tree
if ~isempty(val)
% Get names
names = src.UserData;
% Filter names
indices = [];
for ix = 1:numel(names)
name = names{ix};
if contains(lower(name), lower(val))
indices = [indices ix];
end
end
% Set maximum visible suggestions
n = min(numel(indices), 3);
% If any, create nodes
if n > 0
% Set tree properties
fieldPos = src.Position;
treePos = fieldPos + fieldPos(4).*[0 -n 0 (n-1)];
tree.set(...
'Position', treePos, ...
'Visible', 'on');
% Add nodes
names = sort(names(indices));
for ix = 1 : numel(names)
uitreenode(tree, 'Text', names{ix});
end
end
end
end
function callbackSelectionChanged(src, ~)
% Get node value
val = src.SelectedNodes.Text;
% Set value to field
src.Parent.Children(2).Value = val;
end

Réponse acceptée

Mario Malic
Mario Malic le 24 Avr 2021
Hey Anais,
That's some nice usage of tree component, thanks for that!
Here are two lines that you need to change in your code. If you inspect the src.Value, it does not populate the value unless the focus is shifted away from the component, so it's better to use event.Value since it uses the values you expected.
function callbackAutoComplete(src, event)
val = event.Value;
Here's your code posted with these two lines so the answer is clear for someone else who may encounter this.
clear, clc, close all
% Create figure
fig = uifigure;
% List of names
names = {'Bob';
'Eric';
'John';
'Phil';
'James';
'Anne';
'Suzanne';
'Karen';
'Eleanor';
'Janet';};
% Create table of names
namesTablePos = [28 28 504 203];
namesTable = uitable(fig, ...
'Position', namesTablePos, ...
'ColumnName', 'Names', ...
'Data', names);
% Create editfield
fieldPos = [224, 315, 150, 25];
field = uieditfield(fig, 'text', ...
'ValueChangingFcn', @(h,e) callbackAutoComplete(h,e), ...
'Position', fieldPos);
field.UserData = names;
% Create tree
tree = uitree(fig, ...
'SelectionChangedFcn', @(h,e) callbackSelectionChanged(h,e), ...
'Visible', 'off');
function callbackAutoComplete(src, event)
% Get figure handle
tree = src.Parent.Children(1);
% Reset tree
tree.Visible = 'Off';
delete(tree.Children)
% Get field value
val = event.Value;
% If value is not empty, populate tree
if ~isempty(val)
% Get names
names = src.UserData;
% Filter names
indices = [];
for ix = 1:numel(names)
name = names{ix};
if contains(lower(name), lower(val))
indices = [indices ix];
end
end
% Set maximum visible suggestions
n = min(numel(indices), 3);
% If any, create nodes
if n > 0
% Set tree properties
fieldPos = src.Position;
treePos = fieldPos + fieldPos(4).*[0 -n 0 (n-1)];
tree.set(...
'Position', treePos, ...
'Visible', 'on');
% Add nodes
names = sort(names(indices));
for ix = 1 : numel(names)
uitreenode(tree, 'Text', names{ix});
end
end
end
end
function callbackSelectionChanged(src, ~)
% Get node value
val = src.SelectedNodes.Text;
% Set value to field
src.Parent.Children(2).Value = val;
end
  6 commentaires
Subhajit
Subhajit le 27 Sep 2023
Hi @Voss,
That is a nice hack to get rid of error. However, i still have to click twice to get the correct answer. Thank you for the solution. Have a nice day.
Voss
Voss le 27 Sep 2023
Modifié(e) : Voss le 27 Sep 2023
@Subhajit You're welcome!
I don't know why clicking twice is necessary; I noticed that too. If I were attempting to create this UI, I would probably try a uilistbox or uidropdown in place of the uitree (but maybe there's some reason a uitree is preferable - I don't know, I didn't try the uilistbox or uidropdown).
Anyway, you didn't ask about the clicking twice; you only asked about the error, so that's what I fixed.
Have a nice hack (and day)!

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Interactive Control and Callbacks dans Help Center et File Exchange

Produits


Version

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by