Jens Boldsen
Jens Boldsen

Reputation: 1275

Matlab GUI: waiting for value update before KeyPressFcn call

I'm writing a GUI in Matlab, which among other functionalities should allow you to write a text in an edit-uicontrol, and then add that text to a list when pressing the enter key.

I am using the KeyPressFcn method for the edit box to test whether enter is pressed, and my problem is that it does not update the String value of the edit uicontrol, so the string added to the list is not actually the one I just entered, but a previous incarnation of the string in the edit.

Now I have already searched for solutions to this problem and found a solution, but I would very much prefer a solution strictly contained in Matlab - that is not referring to java.

Is this is possible? And if it is, how?

A minimal working example:

function [fig] = tmpGUI()
    fig = figure('MenuBar','none');
    handles.fig = fig;
    handles.edit = uicontrol(fig,'Style','edit','Units','Normalized','Position',[.05,.75,.9,.2],'Backgroundcolor','white','String','','KeyPressFcn',@edit_KeyPressFcn);
    handles.list = uicontrol(fig,'Style','listbox','Units','Normalized','Position',[.05,.05,.9,.65],'Backgroundcolor','white','String','First element in list');
    guidata(fig,handles);
    uicontrol(handles.edit);
end

function edit_KeyPressFcn(hObject, eventdata)
    handles = guidata(hObject);
    switch eventdata.Key
        case 'return'
            str = get(handles.edit,'String');
            liste = cellstr(get(handles.list,'String'));
            liste{end+1} = str;
            set(handles.list,'String',char(liste),'Value',numel(liste));
    end
end

Edit: I'm running Matlab R2014a.

Upvotes: 1

Views: 1233

Answers (2)

Hoki
Hoki

Reputation: 11812

The callback property of the edit uicontrol will be triggered when you press enter, so it would be easier to use this callback instead of the KeyPressFcn.

Just when you enter the callback, check that the last character pressed was enter. If yes update your list, if not just do nothing and go on.

This example seems to do what you asked. Let me know if they are other conditions to be checked.

function [fig] = tmpGUI()
    fig = figure('MenuBar','none');
    handles.fig = fig;
    handles.edit = uicontrol(fig,'Style','edit','Units','Normalized','Position',[.05,.75,.9,.2],'Backgroundcolor','white','String','','Callback',@edit_callback);
    handles.list = uicontrol(fig,'Style','listbox','Units','Normalized','Position',[.05,.05,.9,.65],'Backgroundcolor','white','String','First element in list');
    guidata(fig,handles);
    uicontrol(handles.edit);
end

function edit_callback(hObject, evt)
    handles = guidata(hObject);
    %// just check if the last key pressed was "enter"
    %// if yes, update the list 
    if double(get(gcf,'currentcharacter'))==13
        str = get(handles.edit,'String');
        liste = cellstr(get(handles.list,'String'));
        liste{end+1} = str;
        set(handles.list,'String',char(liste),'Value',numel(liste));
    end
    %// if not, the callback has been trigerred by a click somewhere else
    %// this is not a validation condition to update the list so we just
    %// do ... nothing
end

Edit: To add more information, the Matlab edit uicontrol are not updated internally before they are validated. The value in the edit will only be validated by (i) The enter key is pressed, or (ii) the txtbox looses focus (user click somewhere else).

In your initial case you are intercepting the enter key and executing code, but because you intercepted the enter key, the textbox didn't validate yet and in its internal memory it still have the old value, so your interception code capture the old value. Remembering a older question I answered relating to these textbox, there is not Matlab way of forcing the textbox to validate its content programmatically without using some java tricks.

So in your case (you want to react to the enter key), it is possible in pure Matlab thanks to the callback mechanics. If you want to execute some code when reacting to any other key, then you will have to force the textbox validation programmatically which can only be done by calling java methods (actually the link you mentioned in your original post is quite neat, the way I found before was quite more convoluted).

Upvotes: 1

memyself
memyself

Reputation: 12638

The problem with your solution is that the keypressfunction is called every time you enter a single character. Use a Callback instead:

function [fig] = tmpGUI()
    fig = figure('MenuBar','none');
    handles.fig = fig;
    handles.edit = uicontrol(fig,'Style','edit','Units','Normalized','Position',[.05,.75,.8,.2],'Backgroundcolor','white','String','', 'Callback',@edit_KeyPressFcn);
    handles.list = uicontrol(fig,'Style','listbox','Units','Normalized','Position',[.05,.05,.9,.65],'Backgroundcolor','white','String','First element in list');

    guidata(fig,handles);
    uicontrol(handles.edit);
end

function edit_KeyPressFcn(hObject, eventdata)

    handles = guidata(hObject);
    str = get(handles.edit,'String');

    % ignore empty strings
    if isempty(str)
        return;
    end

    liste = cellstr(get(handles.list,'String'));
    liste{end+1} = str;
    set(handles.list,'String',char(liste),'Value',numel(liste));

end

Upvotes: 1

Related Questions