How to implement a modal pop-up window on an app (mlapp)? - matlab-app-designer

I want to create a modal popup window, containing a number of uiedit, uimenu and uipushbutton controls. This modal popup window should appear on top of a MATLAB app (built with the app designer; not with GUIDE). The parent app UIFigure should be grayed out while the modal popup is active, similar to what happens when a uiconfirm dialog box is opened. Is there an undocumented way or some other workaround to implement this type of UI element?
The idea is that the user clicks on a "settings" button on the main app and the modal dialog pops up, while deactivating the main app controls, to allow adjustment of settings.

Have a look at the documentation for uiwait which explains exactly how to achieve your desired effect.
In the interest of adhering to best practices for providing meaningful answers, I might approach this problem as follows.
Create a callback for the "settings" button which:
"grays out" desired main app's UI elements by setting their Enable property to 'off'
instantiates the *.mlapp you've created for the settings UI
From here, there are a number of possibilities. One approach would be to uiwait on the settings mlapp's UIFigure since, by default, it is contained in a public property of the mlapp definition. If you want to wait until the settings UI is closed, you can get away with, simply, uiwait(settingsApp.UIFigure);. Once the settings UI is closed, you can re-enable all your main app components to un-"gray" them.
For example, your "Settings button" callback could look like:
function onRequestSettings(app, event)
% set main figure's UI elements gray
% Assuming you want all elements gray
set(app.UIFigure.Children, 'Enable', 'off');
% create the settings UI by instantiating it here
settingsApp = settingsUI();
% wait until the figure closes
uiwait(settingsApp.UIFigure);
% ... SEE NOTE BELOW CODE BLOCK! ... %
% Now that the settings UI is closed,
% set main figure's UI elements back to normal.
% Again, assuming all elements here
set(app.UIFigure.Children, 'Enable', 'on');
end
Note:
While the above code block will produce your desired behavior, I have not shown how to share the data between the settings app and the main app.
I assume, since you do not explicitly ask for this, that you have some way in mind. If not, I will point you to the documentation for creating multi-window apps and sharing data within app designer and also to this answer. Alternatively, you can leverage the fact that mlapps are members of the handle super-class and thus have a builtin event, ObjectBeingDestroyed. You can construct a listener (see addlistener and this) for this event and bind it to a method in your main app which then updates the main app according to changes made on the settings app.
Alternatively:
If the settingsUI is stored in a property of the main app, say app.settingsUI, and is instantiated, but perhaps hidden, by the main app's startupFcn, then instead of re-instantiating every time the "Settings button" is pressed you could simply bring it forward with figure(app.settingsUI.UIFigure);. Then make it "modal" with uiwait(app.settingsUI.UIFigure); and override the settingsUI closeRequestFcn to release the code execution halt with uiresume. The close callback could look like:
classdef settingsUI < matlab.apps.AppBase
...
function UIFigureCloseRequest(app,event)
% override close request to prevent deleting the app
% hide the settings window to appear as though it was closed
app.UIFigure.Visible = 'off';
% resume code execution so that main app can continue to run.
uiresume(app.UIFigure);
end
...
end
-Cheers

Related

Programmatic Method of Handling Matlab Dialog Windows

I have a rather large Matlab program that is GUI based. I am looking into creating automated tests for it, as the current way of checking for bugs before a release is simply using all its functionality like a user would.
I would rather not use a GUI testing program that just records clicks and what not, so I was thinking of adding testing code that would call the button callbacks directly. The problem that I have run into with this is that we have a lot of warndlg and msgbox popups, and I would like my tester code to be able to see these.
Is there any way for Matlab code to tell if a function it called created a warndlg or msgbox? If so, is there any way to click 'ok' on these popups?
In a similar vein, is it possible to handle popups that block code execution (using uiwait or an inputdlg)?
If it matters I didn't use GUIDE, and all the GUI elements are created programmatically
Two ways. The first one is more elegant
Let the functions return an extra variable and return the status of the function. For example, 1: success, 2: success with warning, 3: error...
Create some global variables and make the function change them if a warndlg or msbgbox shows up. The main window would then check if the status of the global variable.
You can tell if a warning dialog was created by looking for it's tag using the findobj function. A warning dialog created using warndlg will have the tag "Msgbox_Warning Dialog". So code like this would tell you if the warning dialog exists:
set(0,'ShowHiddenHandles', 'on')
h = findobj('Tag', 'Msgbox_Warning Dialog');
warn_exists = ~isempty(h)
set(0,'ShowHiddenHandles', 'off')
to close the warning dialog, you can call delete, like this:
delete(h)
For the message box, I would store the handle when you create a message box, then look at the children to find the buttons, then look at their callbacks. You should be able to call the callbacks to simulate picking a button.

How to block GUI while function with output executes?

I am creating a MATLAB application in GUIDE and now I'm facing a problem. I need to call a function that takes a long time to execute and returns a value but while executing the function I want the GUI to wait for the returned value.
I tried with waitfor but this way I can still interact with the GUI and I can't take the returned value...
waitfor(function);
I can think of something that disables all the GUI then enables it back but I have both enabled and disabled objects...
Do you know any solution to this problem?
A simple solution is to create a modal dialog box with a message "Please wait..." just before executing your long-running function, and then to close the dialog box just after it completes. A modal dialog will be in front of the GUI, and will not allow interactions with the window behind.
It's possible for the user to click the "Close" button on the dialog, but you can override this by setting the "CloseRequestFcn" property of the dialog, so that the close button does nothing (unfortunately you can't easily hide the button).
I like the modal dialog proposed by Sam Roberts. There is no mystery and it is user friendly.
Another dirty and easy solution may be to hide the GUI completely, if it is okay:
set(hFig, 'Visible', 'off');
And set it to 'on' after done. It will be good practice to make sure to set it to 'on' in catch block, to avoid disappearing GUI due to error during execution.

How can I disable the Close button of a waitbar in MATLAB?

I want to create a waitbar that should be processed without any interruption. How can I achieve this?
I have tried setting
h=waitbar(0,'please wait','CreateCancelBtn','setappdata(gcbf,''Cancel'',0)');
This disables the Close button on the waitbar, but it also shows me a Cancel button too. I don't want that button.
When you use the CreateCancelBtn option of waitbar, it creates a Cancel button, takes the string you supply, and then sets that string to be both the Callback of the Cancel button (i.e. the thing that happens when you press the button) and the CloseRequestFcn of the figure window (i.e. the thing that happens when you click the Close button on the window frame).
You can avoid this by just directly setting the CloseRequestFcn of the figure window yourself:
h = waitbar(0,'Please Wait...');
h.CloseRequestFcn = '';
The Close button is now disabled.
Bear in mind that the CloseRequestFcn is also what gets executed when you call close(h), so you now won't be able to close it with close(h). You can either call delete(h) instead, or you can make sure that before you call close(h) you reset the CloseRequestFcn back to the default, which is the buit-in function closereq (type edit closereq to see what this does, it basically just calls delete anyway).
Hope that helps!

Enabling and Disabling GUI button Matlab

This is a very strange problem, because I am quite sure the logic is proper but it is still not working. So when the GUI starts, in the starting function, I set most of the buttons to be inactivated using the following line of code for every button, Kbutton, Bbutton etc..:
set(handles.Kbutton,'Enable','off');
set(handles.Bbutton,'Enable','off');
Then, when the user clicks on any cell in the uitable, I use the cell selection callback to get the info about the contents of the cell, and re-activate the buttons that can be used from then on:
set(handles.Kbutton,'Enable','on');
set(handles.Bbutton,'Enable','on');
And till now everything is ok.
So then the user clicks on a button, say Kbutton, and the underlying function is executed thanks to the button's callback function. Once the method is ready I would like to return the buttons to their initial state i.e. inactivated. So logic tells me, re-put the initial line of code at the end of the callback function and done:
set(hObject,'Enable','off');
drawnow;
set(handles.BButton,'Enable','off');
drawnow;
Where the first line of code in the above snippet, refers to the button who fired the callback and BButton is any other button in the GUI.
For some strange reason only the second one is being enabled off. I.e. the button that fired the callback is staying enabled on :/
Has anyone encountered the same problem?
Any ideas?
Thanks in advance
Try changing
set(hObject,'Enable','off');
to
set(handles.Kbutton,'Enable','off');
You click on tools =>gui options =>Generate FlG file and MATLAB file

How to implement a button into Simulink Subsystem Mask?

As I need to specify a local variable to a Subsystem, I created a mask. Doing that I lose the easy access to the subsystem. Right-click and navigating to "Look under mask" is supposed to be too complicated.
So I thought about a workaround and built the following:
The dialog callback code behind the "Get deeper!" checkbox is:
myParameter = %Parameter set by checking Get deeper!
path = gcb(gcs);
if strcmp(get_param(gcb,'myParameter'),'on')
open_system(path,'tab');
end
Everytime when I check the box, the subsystem gets opened and also by every double click on the subsystem, in case the box was checked before. Hence the code does what it should, but thats actualy not the common way how one would realize/visualize something like this.
What I want is a button "Look under mask" in my mask - so the subsystem just gets opened by clicking on that button. Basically the button should call the function: open_system(gcb(gcs),'tab'). Looks so easy, but Simulink doesn't offer me any option to implement this. Can anybody help?
The main issue whith the current solution is also that with every execution of the model all subsystems open up, where the box is checked. That's not the idea.
Matlab 2012b adds exactly what you want: masked blocks have a button on the botton left that is a shortcut to "Look under mask".
Unfortunately, I don't think it is possible to add a button in a mask.
You may want to change your function to automatically set the "Get deeper!" checkbox off after the user clicks on it. That would avoid the automatic opening of the subsystems when the model is loaded. You could do that adding set_param(path,'myParameter','off') just after the open_system(path,'tab');
Finally, as another workaround, you may want to set the OpenFcn callback to call open_system(gcb,'tab'). This will make the system work as if it isn't masked at all. You can put two open_system calls, one to look under mask and the other to open the mask dialog box, if you prefer.