MATLAB Answers

How can I invoke a function from within App Designer when using a DeleteFcn or CloseRequestFcn from a MATLAB figure that is separate from the App GUI?

65 views (last 30 days)
Allen
Allen on 23 Aug 2019
Answered: Allen on 26 Jan 2020
I am trying to find a work around to the lack of axes callback usage from within an App Deisnger axes. Ultimately, I want to assign a KeyPressFcn to allow me to manual shift data along the x-axis when pressing left- and right-arrow keys. I am also selectively performing this x-axis shift on only visible lines, were line visibility can be toggled 'on/'off' using the axes legend's ItemHitFcn. Currently, I am copying axes objects to a new figure outside of App Designer were I can acheive this, and can even obtain the new XValues via one of the app's ButtonGUI callbacks, but would much prefer to invoke the button's callback automatically when the figure is closed.
Attempted:
% Figure creation from app
hFig = figure;
hAx = axes;
hLin = plot(hAx,X,Y);
hFig.DeleteFcn = @(app,event) UpdateAxesButtonPushed(app,event,hLin.XData);
Button callback function:
methods (Access = public)
function UpdateAxesButtonPushed(app, event, newX)
% First verifies that the source of the event is the callback
app.UIAxes.Children(1).XData = newX;
end
end
Code for an additional attempt is provided code section below in better detail. Also, the error that appears is same for all attempts and is as follows.
Undefined function 'UpdateAxes' for input arguments of type 'matlab.ui.Figure'.
Error using MyApp/UpdateAccPlot (line 221)
Error while evaluating Figure CloseRequestFcn.
methods (Access = public)
function UpdateAccPlot(app, event)
% Create figure with user defined CloseRequestFcn
hFig = figure('WindowState','maximized','CloseRequestFcn',@UpdateAxes);
hAx = axes(hFig);
% Plot data
hLin = plot(hAx,app.Data.Time,app.Data.UnfilteredAcc,...
app.Data.Time,app.Data.FilteredAcc);
hLin(1).Color = [0,0.447,0.741];
hLin(2).Color = [0.929,0.694,0.125];
hold(hAx,'on')
plot(hAx,app.Pulse.Time,app.Pulse.Max,'r',...
app.Pulse.Time,app.Pulse.Nom,'--k',...
app.Pulse.Time,app.Pulse.Min,'r')
hold(hAx,'off')
hLeg = legend(hAx,{'Unfiltered Data','Filtered Data',...
'Upper Limit','Nominal Pulse','Lower Limit'});
hAx.XLim = app.Pulse.Time([1,end]);
% Assign callbacks to new figure plot
app.hGUI = hLin;
hLeg.ItemHitFcn = @LineVisible;
hFig.KeyPressFcn = @(src,event) LineShift(src,event,hLin);
grid on
title(hAx,'Shock Pulse Acceleration')
xlabel(hAx,'Time (sec)')
ylabel(hAx,'Acceleration (g)')
waitfor(hFig);
app.Data.Time = getappdata(0,'Time');
app.Data.Time = getappdata(0,'Unfiltered');
app.Data.Time = getappdata(0,'Filtered');
end
function UpdateAxes(~, ~)
hLin = findobj(gcf,'Type','line');
idx{1} = arrayfun(@(a) strcmp(a.DisplayName,'Unfiltered Data'),hLin);
idx{2} = arrayfun(@(a) strcmp(a.DisplayName,'Filtered Data'),hLin);
setappdata(0,'Time',hLin(idx{1}).XData)
setappdata(0,'Unfiltered',hLin(idx{1}).YData)
setappdata(0,'Filtered',hLin(idx{2}).YData)
closereq
end
end

  1 Comment

Ganesh Regoti
Ganesh Regoti on 22 Oct 2019
Hi Allen,
I tried replicating the same functionality as per my understanding and is working fine for me. It would help me further if you can share the script of app designer and callback functions if possible.

Sign in to comment.

Accepted Answer

Allen
Allen on 26 Jan 2020
Ended up solving the problem myself by using a State Button to change the KeyPressFcn for the UIFigure. It requires a little tricky with programatically triggering mouse-button presses at specific locations on the screen using an undocumented java robot, but otherwise works fantastically. This allows me to shift data within the UIAxes and without the need to duplicate the plot in a separate Figure axes.
% Value changed function: spb_AlignData
function spb_AlignDataValueChanged(app, event)
value = app.spb_AlignData.Value;
if value==1 && isempty(app.Data.Time)
app.spb_AlignData.Value = 0;
return
elseif value==0 && strcmp(app.spb_AlignData.Text,'Apply Changes')
% Prompt user to select action
qans = questdlg('Do you want to Apply or Discard alignment changes?','Update Axes','Apply','Discard','Apply');
if strcmp(qans,'Apply') % User selected to apply changes to the plot
% Determine active axes
if strcmp(app.tbg_AxesTabs.SelectedTab.Title,'Acceleration')
hAx = app.ax_Acc;
elseif strcmp(app.tbg_AxesTabs.SelectedTab.Title,'Velocity')
hAx = app.ax_Vel;
end
% Update values and UIAxes
fidx = arrayfun(@(a) strcmp(a.DisplayName,'Filtered Data'),hAx.Children);
uidx = arrayfun(@(a) strcmp(a.DisplayName,'Unfiltered Data'),hAx.Children);
app.Data.Time = hAx.Children(fidx).XData(:);
if strcmp(app.tbg_AxesTabs.SelectedTab.Title,'Acceleration')
app.Data.AccFiltered = hAx.Children(fidx).YData(:);
app.Data.AccUnfiltered = hAx.Children(uidx).YData(:);
elseif strcmp(app.tbg_AxesTabs.SelectedTab.Title,'Velocity')
app.Data.VelFiltered = hAx.Children(fidx).YData(:);
end
elseif ~strcmp(qans,'Discard') % User closed dialog box. Resume shifting data.
app.spb_AlignData.Value = 1;
return
end
% Update UIAxes
app.spb_AlignData.Text = 'Align Data';
UpdateAccPlot(app)
UpdateVelPlot(app)
elseif value==1
hMB = msgbox(['Use the <Arrow Keys> to adjust the position of the Filtered and Unfiltered Data. ',...
'Hold <Ctrl> + <Arrow Keys> to move in smaller increments.']);
uiwait(hMB)
% Disable GUI objects to prevent unwanted selections when in AlignData mode
types = {'uinumericeditfield','uibutton','uicheckbox','uidropdown'};
for i=1:length(types)
arrayfun(@(a) set(a,'Enable','off'),findall(app.UIFigure,'Type',types{i}));
end
% Simulate left mouse-button press/release to remove focus from the AlignData button.
% Necessary for KeyPressFcn to work properly.
iPos = get(groot,'PointerLocation'); % Get current mouse position
set(groot,'PointerLocation',app.UIFigure.Position(1:2)+2) % Move mouse to near lower-left extent of UIFigure
import java.awt.Robot; % Create java robot
import java.awt.event.*; % Create java input event
mouse = Robot;
mouse.mousePress(InputEvent.BUTTON1_MASK);
mouse.mouseRelease(InputEvent.BUTTON1_MASK);
set(groot,'PointerLocation',iPos)
return
end
% Re-enable disabled GUI objects
types = {'uinumericeditfield','uibutton','uicheckbox','uidropdown'};
for i=1:length(types)
arrayfun(@(a) set(a,'Enable','on'),findall(app.UIFigure,'Type',types{i}));
end
end

  0 Comments

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!