Updating listbox and variable changing to old value at the end of the function in MATLAB GUI
The below GUI simply lists some data in a listbox, plots it, and gives the user the option to delete entries from the listbox. I'm hitting my head against the wall trying to get to listbox updated correctly after the user deletes an entry (it should be obvious when you run it).
The 2 problems I have are:
While the callback to the pushbutton does indeed delete the entry correctly from array x, once the callback finishes, the array x reverts back to the original x array (thus, t开发者_开发百科he value somehow restores itself).
I try to use "drawnow" to refresh the listbox to reflect the current x array (which has been modified, at least where drawnow is issued below). Nothing changes though. How can I refresh the listbox with the new x array values?
----------------GUI code---------
function testgui
clear; close all;
% Create the data
x = (10:20)'; % example data
% Create a figure
f = figure('Name', 'GUI Test',...
'NumberTitle', 'off',...
'MenuBar', 'none',...
'Units', 'pixels',...
'Position', [100 100 700 800],...
'Visible', 'off');
% Create a set of axes
a = axes('Parent', f,...
'Units', 'pixels',...
'Position', [230 50 450 700]);
% Create a pushbutton for modifying x array
pb_x = uicontrol('Style', 'pushbutton', ...
'Parent', f,...
'String', 'Delete Selection',...
'Units', 'pixels',...
'Position', [50 7 100 35],...
'Callback', @pb_change_x);
plot(x,'bo'); % graph
xlabel('Index Number'); ylabel('Variable x');
% Create a listbox to hold the x values
y=strtrim(cellstr(num2str(x)));
lb = uicontrol('Style', 'listbox',...
'Parent', f,...
'String', y,...
'Units', 'pixels',...
'Position', [50 50 100 700],...
'Callback', @list_change);
set(f,'Visible','on')
function list_change(varargin)
% Runs when the selection in listbox is changed
curIdx = get(lb,'Value');
% Index the value
curVal = str2double(cell2mat(y(curIdx)));
% Get position of curVal in x
posVal = find(ismember(x,curVal));
% Clear all the children currently on the axes
delete(get(a,'Children'))
% Plot the one data point of interest
plot(posVal,curVal,'bo','MarkerFaceColor','b','MarkerSize',10)
xlabel('Index Number'); ylabel('Variable x');
% Plot all the data
hold on
plot(x,'bo')
hold off
end
function pb_change_x(varargin)
% Runs when DUT <<< pushbutton is clicked
% Obtain selected index
curIdx = get(lb,'Value');
% Index the value
curVal = str2double(cell2mat(y(curIdx)));
% Get position of curVal in x
posVal = ismember(x,curVal);
x(posVal) = []; % HELP (why doesn't value stick when this function returns?)
% Redraw figure (want listbox to update)
drawnow; % HELP (how to refresh listbox with current x array?)
% Clear all the children currently on the axes
delete(get(a,'Children'))
% Plot all the data
plot(x,'bo'); xlabel('Index Number'); ylabel('Variable x');
end
end
You have correctly identified the fix. More generally, I would say that you need to separately update each of the items that encode your GUI's state (i.e. each of the items stored independently by the GUI).
Specifically, your implementation separately stores to the GUI both 'x', your array of data, in the plot and 'y', the cell array that has strings for the listbox names for each item in 'x'. When you created your listbox, 'lb', you provided 'y' as the 'String' attribute. At that point the listbox is separately storing its own copy of 'y' independent of your 'y' and 'x' variables.
When you update your plot, you are resetting the GUI's value of 'x', but as you discovered you also need to update the listbox's 'String' attribute (its copy of 'y'). In this case, the way you chose seems most straightforward, but a more general approach is to repeat the steps used to generate 'y' from 'x' (after updating 'x') and then use "set(lb, 'String', y);" to reset the GUI's version of 'y'.
Hope that is helpful! :-)
It seems that you already fixed the problem. Nonetheless, I rewrote your example and tried to simplify it a bit:
function testgui2()
data = [1:11 ; 10:20]'; %'# data
handles = [];
%# create GUI
handles.hFig = figure('Name','GUI Test', 'NumberTitle','off', ...
'Units','pixels', 'Position',[100 100 700 800], ...
'MenuBar','none', 'Visible','off');
handles.hAx = axes('Parent',handles.hFig, ...
'Units','pixels', 'Position',[230 50 450 700]);
handles.hPB = uicontrol('Style','pushbutton', 'Parent',handles.hFig, ...
'String','Delete Selection',...
'Units','pixels', 'Position',[50 7 100 35],...
'Callback',@button_callback);
handles.hLB = uicontrol('Style','listbox', 'Parent',handles.hFig, ...
'String',data(:,2), 'Value',1, ...
'Units','pixels', 'Position',[50 50 100 700], ...
'Callback',@listbox_callback);
set(handles.hFig, 'Visible','on')
%# plot data and highlighted point
handles.hPlot = plot(data(:,1), data(:,2), 'bo');
handles.hLine = line('XData',data(1,1), 'YData',data(1,2), ...
'Marker','o', 'MarkerSize',10, 'Color','b', 'MarkerFaceColor','b');
xlabel('Index Number'), ylabel('Variable x')
set(handles.hAx, 'XLimMode','manual', 'YLimMode','manual') %# fix limits
%# callback function for button
function button_callback(varargin)
%# get current selection
selected = get(handles.hLB, 'Value');
if selected==0, return, end
%# remove data point
data(selected,:) = [];
%# update the listbox
set(handles.hLB, 'String',data(:,2))
set(handles.hLB, 'Value',min(selected,size(data,1)))
%# update plot
set(handles.hPlot, 'XData',data(:,1), 'YData',data(:,2))
listbox_callback()
end
%# callback function for listbox
function listbox_callback(varargin)
%# get current selection
selected = get(handles.hLB, 'Value');
if selected==0, selected = []; end
%# update plot (highlighted point)
set(handles.hLine, 'XData',data(selected,1), 'YData',data(selected,2))
end
end
精彩评论