Good afternoon!
I'm currently trying to build an app with MATLAB using App Designer. The goal is to be able to plot data using multiple GPX files, which I have successfully done. I'm curious as to how I should go about populating my Listbox.
Is there a way for Listbox to get populated with filenames depending on the folder you select?
You can use dir to list folder's content, convert names list to cell array, and populate the ListBox Items with the cell array.
Assume you have a Button with ButtonButtonPushed callback, and you wish to let the user select a folder, and then populate the list box with all *.gpx files.
You can do it as follows:
% Button button pushed function
function ButtonButtonPushed(app)
selpath = uigetdir(); %Open dialog box for selecting folder.
gpx_files = dir(fullfile(selpath, '*.gpx')); %Dir all *.gpx in selected folder.
%Populate listbox with file names:
app.ListBox.Items = {gpx_files(:).name};
end
The statement app.ListBox.Items = {gpx_files(:).name}; populates the ListBox.
gpx_files(:).name is a list of file names.
{gpx_files(:).name} creates a cell array out of the list.
app.ListBox.Items = {gpx_files(:).name}; Sets the Items property of the ListBox with the created cell array.
Getting the full path of the selected file:
Keep the selected folder:
Add a private property named selpath (use the red P+ in the designer [code view] to add new property, and edit the name of the property):
properties (Access = private)
selpath % Store selected path
end
Store the selected path in selpath property when button is pressed:
% Button pushed function: Button
function ButtonButtonPushed(app, event)
app.selpath = uigetdir(); %Open dialog box for selecting folder.
gpx_files = dir(fullfile(app.selpath, '*.gpx')); %Dir all *.gpx in selected folder.
%Populate listbox with file names:
app.ListBox.Items = {gpx_files(:).name};
end
Now selected path is stored in app.selpath.
Add "ListBoxChangeValue" Callback (right click the list box in design view).
Edit the code of ListBoxValueChanged function:
The value returned value = app.ListBox.Value; is the name of the selected file
(you don't need to use strcmpi).
Use fullfile function to concatenate the path with the file name.
% Value changed function: ListBox
function ListBoxValueChanged(app, event)
value = app.ListBox.Value;
selected_file = fullfile(app.selpath, value); %Get the full path of selected file.
disp(selected_file) %Change the code to load selected_file
end
The above code displays selected_file string in the Command Window.
Replace the disp(selected_file) with you own code (loading and plotting the gpx file).
Here is the complete code of App1 (most of the code was generated automatically):
classdef App1 < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
Button matlab.ui.control.Button
LabelListBox matlab.ui.control.Label
ListBox matlab.ui.control.ListBox
end
properties (Access = private)
selpath % Store selected path
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
end
% Button pushed function: Button
function ButtonButtonPushed(app, event)
app.selpath = uigetdir(); %Open dialog box for selecting folder.
gpx_files = dir(fullfile(app.selpath, '*.gpx')); %Dir all *.gpx in selected folder.
%Populate listbox with file names:
app.ListBox.Items = {gpx_files(:).name};
end
% Value changed function: ListBox
function ListBoxValueChanged(app, event)
value = app.ListBox.Value;
selected_file = fullfile(app.selpath, value); %Get the full path of selected file.
disp(selected_file) %Change the code to load selected_file
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [101 101 640 480];
app.UIFigure.Name = 'UI Figure';
% Create Button
app.Button = uibutton(app.UIFigure, 'push');
app.Button.ButtonPushedFcn = createCallbackFcn(app, #ButtonButtonPushed, true);
app.Button.Position = [43 380 114 49];
app.Button.Text = 'Select Folder';
% Create LabelListBox
app.LabelListBox = uilabel(app.UIFigure);
app.LabelListBox.HorizontalAlignment = 'right';
app.LabelListBox.VerticalAlignment = 'top';
app.LabelListBox.Position = [300 412 44 15];
app.LabelListBox.Text = 'List Box';
% Create ListBox
app.ListBox = uilistbox(app.UIFigure);
app.ListBox.ValueChangedFcn = createCallbackFcn(app, #ListBoxValueChanged, true);
app.ListBox.Position = [359 355 100 74];
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = App1
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
Related
I am using App Designer and trying to load an image (after clicking on it) from MainApp to App2 and show it directly (see screenshot) using a global variable in MainApp called imagePath, where I store the string ('metro-station.png') and a Startup function within App2, where I set the ImageSource to that path.
But it doesn't seem to work.
function startupFcn(app)
app.Image.ImageSource = fullfile(imagePath);
end
Is there any other method to do this?
You don’t need global variable to share data between two Apps.
One of the possible way to exchange data between Apps is:
In the MainApp:
Define a public property (the variable that you want to share with the second App)
Initialize it in a function or callback of the MainApp
When calling the second App, just pass the “App” handle as input parameter, this allows sharing all the public properties of the MainApp to the second App
In the second App:
Define a private property to hold the input parameter coming from the MainApp
In the startupFcn assign the input parameter to such property
From this moment on, you can access to all the public properties of the ManApp, including the specific one you want to pass from the MainApp to the second App
One of the pros (but, at the same time, one of the cons) of this method is that you can modify any of the MainApp public properties in the second App, especially the input parameter
If you don’t want (don’t need) to give to the second App the possibility to modify the MainApp properties:
In the MainApp:
if you want to change the input parameter for the Second App inside other functions besides the one where you call Second App, you can define it as private property in the MainApp so that you can access to it in any MainApp function / callback
Otherwise you can define a local variable in the function / callback of the MainApp calling the second App and use it as input parameter
Then, when calling the Second App you can pass only this property or the local variable to the second App
In the second App:
Define a private property in which to store the input parameter
In the startupFcn assigns the input parameter to that property
From this moment on, all the second App function / callback have access to the ManApp input parameter
The pros (but, at the same time, the cons) of this method is that:
Since the input parameter is passed by value, any modification to the input parameter is lost when you close the second App
The second App does not have access to the public properties of the MainApp
Other sharing methods are available.
In the solution proposed in the below code, I’ve used (for simplicity) the first approach.
The MainApp presents 6 Images and the Import pushbutton that, when pressed, opens the second App and displays the image selected in the MainApp:
The image is selected by clicking on it, when selected, the Selected (click again to unselect) label appears above it
Clicking again on the image, deselect the image
Clicking another image, selects the image and deselects the image selected before (if any)
The pushbutton is enabled only if an image has been selected, when pressed, the second App opens.
The second App simply displays the image selected in the MainApp, a Close pushbutton allows to close it.
The MainApp consists of: (see below picture):
6 Image objects: app.Image1, …
6 Labels: app.img_1_selected, …
1 pushbutton: app.ImportButton
The app2 consists of (see below picture):
1 Image object: app.Image
1 Label: app.Label
1 pushbutton: CloseButton
MainApp code
For simplicity the path and the filename of the images in the MainApp are hardcoded, but you can easily implement a function to dynamically load them.
In the set of public properties you can find, among the others:
PathSelectedImage: the property used to store the path and the filename of the selected image to be passed to the second App
ImgSelectionStr: an array to store the handles of the labels of the images
ImageSet: an array to store the handles of the image object
These two arrays allows using for loops when working with the images and the string and to avoid code duplications.
The arrays are initialized in the startupFcn function.
To access to the properties of the objects stored in the arrays you have to use the set / get functions instead of the dot notation.
The ImageClickedFcn callback is defined for each image; it simply sets the ID of the image and calls the SetUnset_Selection function.
The SetUnset_Selection function manages the selection of the images, the label above them and enables / disables the Import pushbutton
classdef MainApp_exported < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
MainAppUIFigure matlab.ui.Figure
img_1_selected matlab.ui.control.Label
img_2_selected matlab.ui.control.Label
img_3_selected matlab.ui.control.Label
img_4_selected matlab.ui.control.Label
img_5_selected matlab.ui.control.Label
img_6_selected matlab.ui.control.Label
ImportButton matlab.ui.control.Button
Image_6 matlab.ui.control.Image
Image_5 matlab.ui.control.Image
Image_4 matlab.ui.control.Image
Image_3 matlab.ui.control.Image
Image_2 matlab.ui.control.Image
Image_1 matlab.ui.control.Image
end
properties (Access = public)
PathSelectedImage; % Path and filename of the selected image
SelectedImageId; % Id of the selected image
SelectedImagePrevId; % Id of the previously selected image
ImgSelectionStr; % Array of Label objects
ImageSet; % Array of Image objects
app2_h; % handle to access app2
end
methods (Access = private)
% SetUnset_Selection: functin that manages the activaton of:
% - selection labels over the images
% - path and filename of the selected image
function SetUnset_Selection(app,SelectedImg)
% Selet the image object from the ImageSet array
tmp = app.ImageSet(SelectedImg);
% Get the path and filename of the selected imae
app.PathSelectedImage = get(tmp,'ImageSource');
% Save the ID of the previouusly selected image
if(app.SelectedImagePrevId ~= app.SelectedImageId)
app.SelectedImagePrevId = app.SelectedImageId;
else
app.SelectedImagePrevId = -1;
end
% Set the ID of the selected image
app.SelectedImageId = SelectedImg;
% Selet the image label object from the ImgSelectionStr array
tmp = app.ImgSelectionStr(SelectedImg);
% Visualize the label of the selected image and hide the label of
% the previously selected image and turns on the Import pushbutton
if(strcmp(get(tmp,'Visible'),"off"))
set(tmp,'Visible',"on",'Text','Selected (click again to unselect)');
app.ImportButton.Enable = "on";
else
set(tmp,'Visible',"off")
app.ImportButton.Enable = "off";
end
if(app.SelectedImagePrevId > 0)
set(app.ImgSelectionStr(app.SelectedImagePrevId),'Visible','off');
end
end
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
% Initialize the handle to access app2
app.app2_h = [];
% Initialize the ID of the previously selected image
app.SelectedImagePrevId = -1;
% Initialize the ID of the selected image
app.SelectedImageId = -1;
% Store the image label objects in the ImgSelectionStr array
% The array is used to easily access the label objects and avoid
% duplication in the code
app.ImgSelectionStr(1) = app.img_1_selected;
app.ImgSelectionStr(2) = app.img_2_selected;
app.ImgSelectionStr(3) = app.img_3_selected;
app.ImgSelectionStr(4) = app.img_4_selected;
app.ImgSelectionStr(5) = app.img_5_selected;
app.ImgSelectionStr(6) = app.img_6_selected;
% Store the image objects in the ImageSet array
% The array is used to easily access the label objects and avoid
% duplication in the code
app.ImageSet(1) = app.Image_1;
app.ImageSet(2) = app.Image_2;
app.ImageSet(3) = app.Image_3;
app.ImageSet(4) = app.Image_4;
app.ImageSet(5) = app.Image_5;
app.ImageSet(6) = app.Image_6;
end
% Button pushed function: ImportButton
function ImportButtonPushed(app, event)
% Turn off the Import pushbutton (will be turned on in the
% SetUnset_Selection function
app.ImportButton.Enable = "off";
% Open the app2 that shows the selected image
app.app2_h=app2(app);
end
% Image clicked function: Image_1
function Image_1Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 1;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
% Image clicked function: Image_2
function Image_2Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 2;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
% Image clicked function: Image_3
function Image_3Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 3;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
% Image clicked function: Image_4
function Image_4Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 4;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
% Image clicked function: Image_5
function Image_5Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 5;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
% Image clicked function: Image_6
function Image_6Clicked(app, event)
% Set the ID of the selected image
Sel_Img_Id = 6;
% Call SetUnset_Selection to manage the image labels and get the
% path and filename of the selected image
SetUnset_Selection(app,Sel_Img_Id);
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Get the file path for locating images
pathToMLAPP = fileparts(mfilename('fullpath'));
% Create MainAppUIFigure and hide until all components are created
app.MainAppUIFigure = uifigure('Visible', 'off');
app.MainAppUIFigure.IntegerHandle = 'on';
app.MainAppUIFigure.Position = [100 100 580 431];
app.MainAppUIFigure.Name = 'MainApp';
app.MainAppUIFigure.Tag = 'App1_FIGURE';
% Create Image_1
app.Image_1 = uiimage(app.MainAppUIFigure);
app.Image_1.ImageClickedFcn = createCallbackFcn(app, #Image_1Clicked, true);
app.Image_1.Position = [34 301 118 92];
app.Image_1.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_1.jpg');
% Create Image_2
app.Image_2 = uiimage(app.MainAppUIFigure);
app.Image_2.ImageClickedFcn = createCallbackFcn(app, #Image_2Clicked, true);
app.Image_2.Position = [34 176 118 92];
app.Image_2.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_2.jpg');
% Create Image_3
app.Image_3 = uiimage(app.MainAppUIFigure);
app.Image_3.ImageClickedFcn = createCallbackFcn(app, #Image_3Clicked, true);
app.Image_3.Position = [34 53 118 92];
app.Image_3.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_3.jpg');
% Create Image_4
app.Image_4 = uiimage(app.MainAppUIFigure);
app.Image_4.ImageClickedFcn = createCallbackFcn(app, #Image_4Clicked, true);
app.Image_4.Position = [413 301 118 92];
app.Image_4.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_4.jpg');
% Create Image_5
app.Image_5 = uiimage(app.MainAppUIFigure);
app.Image_5.ImageClickedFcn = createCallbackFcn(app, #Image_5Clicked, true);
app.Image_5.Position = [413 176 118 92];
app.Image_5.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_5.jpg');
% Create Image_6
app.Image_6 = uiimage(app.MainAppUIFigure);
app.Image_6.ImageClickedFcn = createCallbackFcn(app, #Image_6Clicked, true);
app.Image_6.Position = [413 53 118 92];
app.Image_6.ImageSource = fullfile(pathToMLAPP, 'IMG', 'img_6.jpg');
% Create ImportButton
app.ImportButton = uibutton(app.MainAppUIFigure, 'push');
app.ImportButton.ButtonPushedFcn = createCallbackFcn(app, #ImportButtonPushed, true);
app.ImportButton.BackgroundColor = [0.9294 0.6941 0.1255];
app.ImportButton.FontSize = 14;
app.ImportButton.FontWeight = 'bold';
app.ImportButton.Enable = 'off';
app.ImportButton.Position = [211 203 158 39];
app.ImportButton.Text = 'Import';
% Create img_6_selected
app.img_6_selected = uilabel(app.MainAppUIFigure);
app.img_6_selected.FontWeight = 'bold';
app.img_6_selected.FontColor = [1 0 0];
app.img_6_selected.Visible = 'off';
app.img_6_selected.Position = [350 144 195 22];
app.img_6_selected.Text = 'Selected (click again to unselect)';
% Create img_5_selected
app.img_5_selected = uilabel(app.MainAppUIFigure);
app.img_5_selected.FontWeight = 'bold';
app.img_5_selected.FontColor = [1 0 0];
app.img_5_selected.Visible = 'off';
app.img_5_selected.Position = [350 267 195 22];
app.img_5_selected.Text = 'Selected (click again to unselect)';
% Create img_4_selected
app.img_4_selected = uilabel(app.MainAppUIFigure);
app.img_4_selected.FontWeight = 'bold';
app.img_4_selected.FontColor = [1 0 0];
app.img_4_selected.Visible = 'off';
app.img_4_selected.Position = [350 393 195 22];
app.img_4_selected.Text = 'Selected (click again to unselect)';
% Create img_3_selected
app.img_3_selected = uilabel(app.MainAppUIFigure);
app.img_3_selected.FontWeight = 'bold';
app.img_3_selected.FontColor = [1 0 0];
app.img_3_selected.Visible = 'off';
app.img_3_selected.Position = [48 144 195 22];
app.img_3_selected.Text = 'Selected (click again to unselect)';
% Create img_2_selected
app.img_2_selected = uilabel(app.MainAppUIFigure);
app.img_2_selected.FontWeight = 'bold';
app.img_2_selected.FontColor = [1 0 0];
app.img_2_selected.Visible = 'off';
app.img_2_selected.Position = [48 267 195 22];
app.img_2_selected.Text = 'Selected (click again to unselect)';
% Create img_1_selected
app.img_1_selected = uilabel(app.MainAppUIFigure);
app.img_1_selected.FontWeight = 'bold';
app.img_1_selected.FontColor = [1 0 0];
app.img_1_selected.Visible = 'off';
app.img_1_selected.Position = [48 393 195 22];
app.img_1_selected.Text = 'Selected (click again to unselect)';
% Show the figure after all components are created
app.MainAppUIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = MainApp_exported
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.MainAppUIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.MainAppUIFigure)
end
end
end
Second App code
The private property MainApp is used to store the input parameter of the MainApp (whch is the MainApp handle)
The startupFcn simply retrieves the path and the name of the image to be displayed form the input parameter and sets the label above the image.
classdef app2_exported < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
App2ImageDisplayUIFigure matlab.ui.Figure
Label matlab.ui.control.Label
CloseButton matlab.ui.control.Button
Image matlab.ui.control.Image
end
properties (Access = private)
MainApp; % Handle of the calling app (app1)
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app, CallingApp)
% Set the handle of the calling app
app.MainApp = CallingApp;
% Load the select image
app.Image.ImageSource = CallingApp.PathSelectedImage;
% Print the name and the ID of the diplayed image
[~,name,~] = fileparts(app.Image.ImageSource);
img_id=CallingApp.SelectedImageId;
str=sprintf('Name: %s\nPosition: %d',name,img_id);
app.Label.Text = str;
% Set the Label of the selected image in app1 as "Imported"
tmp=CallingApp.ImgSelectionStr(img_id);
set(tmp,'text','Imported');
end
% Button pushed function: CloseButton
function CloseButtonPushed(app, event)
% Get the handle of the label of the selected image in app1
tmp=app.MainApp.ImgSelectionStr(app.MainApp.SelectedImageId);
% Update the label of displayed image in the calling app before
% closing the app2
set(tmp,'text','App2 closed, select a in image');
app.MainApp.app2_h = [];
delete(app);
end
% Close request function: App2ImageDisplayUIFigure
function App2ImageDisplayUIFigureCloseRequest(app, event)
tmp=app.MainApp.ImgSelectionStr(app.MainApp.SelectedImageId);
% Update the label of displayed image in the calling app before
% closing the app2
set(tmp,'text','App2 closed, select a in image');
app.MainApp.app2_h = [];
delete(app);
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create App2ImageDisplayUIFigure and hide until all components are created
app.App2ImageDisplayUIFigure = uifigure('Visible', 'off');
app.App2ImageDisplayUIFigure.IntegerHandle = 'on';
app.App2ImageDisplayUIFigure.Position = [100 100 655 536];
app.App2ImageDisplayUIFigure.Name = 'App2 - Image Display';
app.App2ImageDisplayUIFigure.CloseRequestFcn = createCallbackFcn(app, #App2ImageDisplayUIFigureCloseRequest, true);
app.App2ImageDisplayUIFigure.HandleVisibility = 'on';
app.App2ImageDisplayUIFigure.Tag = 'app2_FIGURE';
% Create Image
app.Image = uiimage(app.App2ImageDisplayUIFigure);
app.Image.Position = [33 122 390 295];
% Create CloseButton
app.CloseButton = uibutton(app.App2ImageDisplayUIFigure, 'push');
app.CloseButton.ButtonPushedFcn = createCallbackFcn(app, #CloseButtonPushed, true);
app.CloseButton.Position = [445 273 98 34];
app.CloseButton.Text = 'Close';
% Create Label
app.Label = uilabel(app.App2ImageDisplayUIFigure);
app.Label.WordWrap = 'on';
app.Label.Position = [59 448 524 73];
app.Label.Text = '';
% Show the figure after all components are created
app.App2ImageDisplayUIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = app2_exported(varargin)
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.App2ImageDisplayUIFigure)
% Execute the startup function
runStartupFcn(app, #(app)startupFcn(app, varargin{:}))
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.App2ImageDisplayUIFigure)
end
end
end
The picture below shows the two Apps “at working”.
I am creating a GUI using Matlab's App Designer (2019b). One of the nice features for NumericEditField is that you can define value limits so that users can't enter a value outside the desired range. For example, the following would limit the edit field values between -100 and 100.
app.numericEditField1.Limits = [-100 100];
I also have a uitable object in my GUI - is it possible to set value limits for cells in the data table, like with the edit fields? I didn't see a property that was obviously equivalent. My best thought for a workaround is to edit the CellEditCallback to manually check the values every time one is changed.
Below is a sample app that has a value edit field with limits, and a regular uitable. I would like the to put value limits on certain columns of the table as well.
Sample code
classdef sampleLimitedValApp < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
LimitedEditValueEditFieldLabel matlab.ui.control.Label
LimitedEditValueEditField matlab.ui.control.NumericEditField
UITable matlab.ui.control.Table
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
app.UITable.Data = zeros(3,4);
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 383 331];
app.UIFigure.Name = 'UI Figure';
% Create LimitedEditValueEditFieldLabel
app.LimitedEditValueEditFieldLabel = uilabel(app.UIFigure);
app.LimitedEditValueEditFieldLabel.HorizontalAlignment = 'right';
app.LimitedEditValueEditFieldLabel.Position = [31 280 101 22];
app.LimitedEditValueEditFieldLabel.Text = 'Limited Edit Value';
% Create LimitedEditValueEditField
app.LimitedEditValueEditField = uieditfield(app.UIFigure, 'numeric');
app.LimitedEditValueEditField.Limits = [-100 100];
app.LimitedEditValueEditField.Position = [147 280 100 22];
% Create UITable
app.UITable = uitable(app.UIFigure);
app.UITable.ColumnName = {'Column 1'; 'Column 2'; 'Column 3'; 'Column 4'};
app.UITable.RowName = {''};
app.UITable.ColumnEditable = true;
app.UITable.Position = [31 67 302 185];
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = sampleLimitedValApp
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
Your idea of using the CellEditCallback was the right one. I have to admit, that I am not really an expert in creating and using classes in Matlab and always create my GUIs from scratch without using the AppDesigner, thats why I don't know if there is maybe a better organization of functions and methods possible.
However, the following does what you want:
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% original code
% added code
app.UITable.CellEditCallback = #limitCellVal;
function limitCellVal(src,evt)
CellLimits = [-100 100];
idx = evt.Indices; % indices of selected cell
belowLowerLimit = src.Data(idx(1),idx(2)) < CellLimits(1);
aboveUpperLimit = src.Data(idx(1),idx(2)) > CellLimits(2);
if belowLowerLimit, src.Data(idx(1),idx(2)) = CellLimits(1); end
if aboveUpperLimit, src.Data(idx(1),idx(2)) = CellLimits(2); end
end
end
end
If you want to edit multiple cells at once, than a little tweaking of the callback function is necessary, but I think you can manage that.
I am working on a App in MATLAB and I use the app design to build it. I have added a text area element in which I display messages to the user (similar use as the command window). In the the app the user can press buttons, which trigger functions to be executed and within those functions, I would like to be able to display some messages in this text area element.
This is an example of the code I use to display the text in this text area. I use a counter to add text in the list and simulate display without overwriting the previous messages.
% display execution message
app.nb_Text_stock = app.nb_Text_stock + 1;
app.OutputStatusTextArea.Value(app.nb_Text_stock) = {'My test here'};
As you can see, I need the app element. I could then pass it to the function all the way to the level where I need to display the text but my real question is, can I access the app element from within the function without passing it as an argument? The reason I want to do that is I have also a non-GUI version of the script where I would not be able to pass app as argument. So to make things simpler, I would like to have a parameters GUI = 1 or 0, and then based on that display either in the command window if GUI = 0 or in the text area in the GUI if GUI = 1. But for that I need to access the app element from inside my function. Is there a proper way to do that? Or do you have any suggestion for another approach for this problem?
You can store app object using setappdata, and get the object using getappdata:
Store app in startupFcn function (Code that executes after component creation):
Add startupFcn by adding callback in "Code View".
% Code that executes after component creation
function startupFcn(app)
% Store app in the root object (setappdata(groot, 'my_app', app) also works).
setappdata(0, 'my_app', app)
end
Read app object from any function:
app = getappdata(0, 'my_app');
Note:
This is not a good coding practice.
What you supposed to do:
function NonGuiFun()
app = app1();
app.func();
What you are asking to do:
function NonGuiFun()
% Get app object (assuming `app` GUI is already open)
app = getappdata(0, 'my_app');
if ~isempty(app)
app.func();
end
Here is the entire code of app1 class, that I used for testing (most of it is automatically generated):
classdef app1 < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
Button matlab.ui.control.StateButton
TextAreaLabel matlab.ui.control.Label
OutputStatusTextArea matlab.ui.control.TextArea
end
properties (Access = private)
nb_Text_stock = 0; % Description
end
methods (Access = public)
function results = func(app)
app.nb_Text_stock = app.nb_Text_stock + 1;
app.OutputStatusTextArea.Value(app.nb_Text_stock) = {num2str(app.nb_Text_stock)};
end
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
setappdata(0, 'my_app', app)
end
% Value changed function: Button
function ButtonValueChanged(app, event)
value = app.Button.Value;
func(app);
end
% Close request function: UIFigure
function UIFigureCloseRequest(app, event)
setappdata(0, 'my_app', [])
delete(app)
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 640 480];
app.UIFigure.Name = 'UI Figure';
app.UIFigure.CloseRequestFcn = createCallbackFcn(app, #UIFigureCloseRequest, true);
% Create Button
app.Button = uibutton(app.UIFigure, 'state');
app.Button.ValueChangedFcn = createCallbackFcn(app, #ButtonValueChanged, true);
app.Button.Text = 'Button';
app.Button.Position = [214 295 214 85];
% Create TextAreaLabel
app.TextAreaLabel = uilabel(app.UIFigure);
app.TextAreaLabel.HorizontalAlignment = 'right';
app.TextAreaLabel.Position = [210 211 56 22];
app.TextAreaLabel.Text = 'Text Area';
% Create OutputStatusTextArea
app.OutputStatusTextArea = uitextarea(app.UIFigure);
app.OutputStatusTextArea.Position = [281 175 150 60];
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = app1
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
Note that UIFigureCloseRequest executes: setappdata(0, 'my_app', []).
If you have the handle of any graphical object, you can find pretty much any other object in the same figure using the .Parent and .Children fields (e.g. hObject.Parent.Parent.Children(3).String = 'foo'), optionally using ancestor. If you don't have any object handles, you can use findall, but this would require some means of identifying the correct figures/controls. This can be done using their Tag field, but it would require specifying it beforehand.
I am building an app where the user can select some parameters and press a button "update", which trigger a table to be create. Let's say a table named A.
Now I would like to display this table in a excel like window on my app so the user can see the results of the data update. I can not find which element and how to set it up so that my table A is display in my app in a excel like window where the user could scroll up and down, left and right.
Is that something possible to do and if yes how?
I actually have found a satisfactory answer, which builds on the answer of Rotem above:
In the button pushed callback, simply add:
% Button pushed function: UpdateButton
function UpdateButtonPushed(app, event)
app.UITable.Data = app.T;
app.UITable.ColumnName = app.T.Properties.VariableNames;
end
This works fine for multiple data type. (i actually did not display the rowName property as I do not have any in this case).
You can use the table component.
My example is based on the following example, which displays MATLAB table in a uitable (user interface table component).
You can start by adding a table to the application main figure in App Designer design view.
You can also add the update button in design view.
Add a private property to the app class for storing the table data (I named it T):
properties (Access = private)
T % Table
end
You may initialize table T in the startupFcn like in the following example:
% Code that executes after component creation
function startupFcn(app)
LastName = {'Smith'; 'Johnson'; 'Williams'; 'Jones'; 'Brown'};
Age = [38; 43; 38; 40; 49];
Height = [71; 69; 64; 67; 64];
Weight = [176; 163; 131; 133; 119];
app.T = table(Age, Height, Weight, 'RowNames', LastName);
end
In the button pushed callback, you can update the table like in the following example:
% Button pushed function: UpdateButton
function UpdateButtonPushed(app, event)
app.UITable.Data = app.T{:,:};
app.UITable.ColumnName = app.T.Properties.VariableNames;
app.UITable.RowName = app.T.Properties.RowNames;
end
Here is how the user interface looks like (after pressing update button):
Here is the complete code (include automatically generated code):
classdef app1 < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
UITable matlab.ui.control.Table
UpdateButton matlab.ui.control.Button
end
properties (Access = public)
children = app1.empty % Description
end
properties (Access = private)
T % Table
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
LastName = {'Smith'; 'Johnson'; 'Williams'; 'Jones'; 'Brown'};
Age = [38; 43; 38; 40; 49];
Height = [71; 69; 64; 67; 64];
Weight = [176; 163; 131; 133; 119];
app.T = table(Age, Height, Weight, 'RowNames', LastName);
end
% Button pushed function: UpdateButton
function UpdateButtonPushed(app, event)
app.UITable.Data = app.T{:,:};
app.UITable.ColumnName = app.T.Properties.VariableNames;
app.UITable.RowName = app.T.Properties.RowNames;
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 322 233];
app.UIFigure.Name = 'UI Figure';
% Create UITable
app.UITable = uitable(app.UIFigure);
app.UITable.ColumnName = {'Column 1'; 'Column 2'; 'Column 3'; 'Column 4'};
app.UITable.RowName = {};
app.UITable.Position = [36 57 251 163];
% Create UpdateButton
app.UpdateButton = uibutton(app.UIFigure, 'push');
app.UpdateButton.ButtonPushedFcn = createCallbackFcn(app, #UpdateButtonPushed, true);
app.UpdateButton.Position = [36 14 100 22];
app.UpdateButton.Text = 'Update';
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = app1
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
You can copy an paste the code to app1.m file, just to see how it works (without using App Designer).
A recently published article in UndocumentedMatlab, mentions that App Designer figures are actually web pages using the Dojo Toolkit. This means we could theoretically manipulate the HTML DOM directly to achieve certain UI customizations that are otherwise unavailable.
Below is an example of an App Designer figure definition, as appears in the .m file generated by the App Designer (on MATLAB R2016a):
classdef domDemo < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure % UI Figure
LabelListBox matlab.ui.control.Label % List Box
ListBox matlab.ui.control.ListBox % Item 1, Item 2, Item 3, It...
end
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
end
end
% App initialization and construction
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure
app.UIFigure = uifigure;
app.UIFigure.Position = [100 100 260 147];
app.UIFigure.Name = 'UI Figure';
setAutoResize(app, app.UIFigure, true)
% Create LabelListBox
app.LabelListBox = uilabel(app.UIFigure);
app.LabelListBox.HorizontalAlignment = 'right';
app.LabelListBox.Position = [50 93 44 15];
app.LabelListBox.Text = 'List Box';
% Create ListBox
app.ListBox = uilistbox(app.UIFigure);
app.ListBox.Position = [109 36 100 74];
end
end
methods (Access = public)
% Construct app
function app = domDemo()
% Create and configure components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
...which looks like this:
According to the documentation of uilistbox (which redirects us to the page on Check Box Properties for the full property list), there exists no way to manipulate e.g. the text alignment of list items. If so,
Question: How do we manipulate the ListBox in the example app such that its contents become center-aligned, even though such a setting is not available to us?
In order to succeed in this task, we need several things:
Find where the HTML/CSS are located (so we can manipulate them).
Find which element of the DOM we want to edit.
Find what is the change we need to make.
Find a way to manipulate the element using MATLAB.
Working step by step:
1. Find where the figure's HTML/CSS are stored/located
win = struct(struct(struct(app).UIFigure).Controller).Container.CEF;
URL = win.URL; % Needed only for testing in browser
2. Find which element of the DOM we need to edit
data_tag = char(struct(app.ListBox).Controller.ProxyView.PeerNode.getId);
Validation using a browser:
3. Find what is the change we need to make
Since we want to manipulate text alignment, we google some relevant keywords and find the CSS text-align property. Then we try it manually to see if it really works:
4. Find a way to manipulate the element using MATLAB
Using dojo.style and dojo.query:
win.executeJS(['dojo.style(dojo.query("[data-tag^=''' data_tag ''']")[0],"textAlign","center")']);
Complete code for this answer:
classdef domDemo < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure % UI Figure
LabelListBox matlab.ui.control.Label % List Box
ListBox matlab.ui.control.ListBox % Item 1, Item 2, Item 3, It...
end
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
% Customizations (aka "MAGIC GOES HERE"):
drawnow; rez = [];
warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame
warning off MATLAB:structOnObject
while ~strcmp(rez,'"center"')
try
% 1. Get a handle to the webwindow:
win = struct(struct(struct(app).UIFigure).Controller).Container.CEF;
% 2. Find which element of the DOM we want to edit (as before):
data_tag = char(struct(app.ListBox).Controller.ProxyView.PeerNode.getId);
% 3. Manipulate the DOM via a JS command
rez = win.executeJS(['dojo.style(dojo.query("[data-tag^=''' ...
data_tag ''']")[0],"textAlign","center")']);
catch
pause(1); % Give the figure (webpage) some more time to load
end
end
end
end
% App initialization and construction
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure
app.UIFigure = uifigure;
app.UIFigure.Position = [100 100 260 147];
app.UIFigure.Name = 'UI Figure';
setAutoResize(app, app.UIFigure, true)
% Create LabelListBox
app.LabelListBox = uilabel(app.UIFigure);
app.LabelListBox.HorizontalAlignment = 'right';
app.LabelListBox.Position = [50 93 44 15];
app.LabelListBox.Text = 'List Box';
% Create ListBox
app.ListBox = uilistbox(app.UIFigure);
app.ListBox.Position = [109 36 100 74];
end
end
methods (Access = public)
% Construct app
function app = domDemo()
% Create and configure components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, #startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end