Why is the uieditfield ValueChangingFcn function called twice?

13 visualizaciones (últimos 30 días)
Anais G
Anais G el 23 de Abr. de 2021
Editada: Voss el 27 de Sept. de 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

Respuesta aceptada

Mario Malic
Mario Malic el 24 de Abr. de 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 comentarios
Subhajit
Subhajit el 27 de Sept. de 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 el 27 de Sept. de 2023
Editada: Voss el 27 de Sept. de 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)!

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Interactive Control and Callbacks en Help Center y File Exchange.

Productos


Versión

R2021a

Community Treasure Hunt

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

Start Hunting!

Translated by