How to truncate front of text rather than end in MATLAB uilabel - matlab

I am building a GUI using App Designer in MATLAB (2019b). One aspect of this is allowing the user to load a file, and then displaying the name of the file that was loaded. When the text to display is longer than the uilabel size, the default behavior is to truncate the end and append an ellipsis ("..."). I would like to truncate from the front and place an ellipsis there, as it's more important for the user to see the file name then the file path. Here's an example of what I want it to look like.
What is the best way to achieve this? Right now I have a hack that measures the width of the uilabel and then approximates how many characters would fit and truncates the text based on that. This doesn't seem to behave consistently though, probably do to proportional spacing rather than monospacing. Also, since the width of the uilabel is measured in pixels, I worry that it won't behave consistently on other monitor resolutions and display environments. Is there a better way than what I'm currently doing, or a way to improve my method to make it more reliable?
Sample Code:
classdef sampleApp < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
SelectaFileButton matlab.ui.control.Button
defaultFilename matlab.ui.control.Label
DefaultBehaviorLabel matlab.ui.control.Label
ModifiedBehaviorLabel matlab.ui.control.Label
modifiedFilename matlab.ui.control.Label
end
% Callbacks that handle component events
methods (Access = private)
% Button pushed function: SelectaFileButton
function SelectaFileButtonPushed(app, event)
[filename,pathname] = uigetfile('Select a filename to display');
filestr = fullfile(pathname,filename);
% This sets the text the normal way
app.defaultFilename.Text = filestr;
app.defaultFilename.Tooltip = filestr;
% This measures the width of the text field and attempts to fit
% the text to the field
pos = app.modifiedFilename.Position;
nchars = floor(0.165*pos(3))-3; % The 0.165 was found through trial and error
if(length(filestr)>nchars+3)
shortText = ['...' filestr(end-nchars+1:end)];
else
shortText = filestr;
end
app.modifiedFilename.Text = shortText;
app.modifiedFilename.Tooltip = filestr;
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 297 111];
app.UIFigure.Name = 'UI Figure';
% Create SelectaFileButton
app.SelectaFileButton = uibutton(app.UIFigure, 'push');
app.SelectaFileButton.ButtonPushedFcn = createCallbackFcn(app, #SelectaFileButtonPushed, true);
app.SelectaFileButton.Position = [13 68 160 22];
app.SelectaFileButton.Text = 'Select a File';
% Create defaultFilename
app.defaultFilename = uilabel(app.UIFigure);
app.defaultFilename.Position = [118 39 133 22];
app.defaultFilename.Text = 'Filename';
% Create modifiedFilename
app.modifiedFilename = uilabel(app.UIFigure);
app.modifiedFilename.Position = [118 19 143 22];
app.modifiedFilename.Text = 'Filename';
% Create DefaultBehaviorLabel
app.DefaultBehaviorLabel = uilabel(app.UIFigure);
app.DefaultBehaviorLabel.HorizontalAlignment = 'right';
app.DefaultBehaviorLabel.Position = [-2 40 110 22];
app.DefaultBehaviorLabel.Text = 'Default Behavior:';
% Create ModifiedBehaviorLabel
app.ModifiedBehaviorLabel = uilabel(app.UIFigure);
app.ModifiedBehaviorLabel.HorizontalAlignment = 'right';
app.ModifiedBehaviorLabel.Position = [-2 20 110 22];
app.ModifiedBehaviorLabel.Text = 'Modified Behavior:';
% 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 = sampleApp
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
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

The ellipses are probably added in the system APIs (Java), which may not necessarily be accessible to matlab. I suggest you to show the file name only in the label, and extract the path use fileparts and display it as TooltipString (supported in R2018) of the label.

Related

matlab app designer load image in new app

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”.

Set limits for values in the cells of an uitable

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.

How to display a matlab table in a Matlab App?

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).

Operating on while loop outside the loop matlab

i've got problems with my Nucleo.
Im using Matlab to cooperate with my Nucleo board.
I want to build programmatically GUI with buttons, figures etc. I'm going to put whole functionality in while loop. And now there's my question.
Is there any posibility to put whole code in while loop and operate it through callback functions outside the loop?
For example: Im my loop i want to send some data to Nucleo on btn1 press, and i want to stop it on btn2 press(Of course if statements for btns). Is there possibility to do it by changing the button values or something like that(Flags etc.)?
I don't want use global variables.
Yes it's possible...
It's not the best programming pattern, but it's very convenient approach for small software projects.
I recommend you to use MATLAB App Designer.
App Designer uses OOP programming model, that makes it simpler to pass data (without using global variables, and without complicated solutions that are used with GUIDE).
Here is a sample instructions:
Start App Designer - execute appdesigner from command line.
Add two buttons, and two labels (add anything else later).
Add callbacks: for start button set flag to true and in stop button to false.
The syntax is app.is_sending = true (when is_sending is a property of app).
Change from Design View to Code View.
Add private properties: loop_counter = 0;, sending_counter = 0;, is_sending = false;.
Add callback - select startupFcn callback function.
Put your while loop in the startupFcn callback.
Use while isvalid(app)
Place your while loop functionality inside the while loop.
Place your sending code with if (app.is_sending)...
Very important: at the end of the loop call pause function.
You must execute pause or drawnow to allow callbacks to be responsive.
When using App Designer, some code is generated automatically, and cannot be modified in Code View.
The following code sample includes both generated code, and customized code:
classdef app1 < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
StartSendingButton matlab.ui.control.Button
StopSendingButton matlab.ui.control.Button
Sending0Label matlab.ui.control.Label
LoopCounter0Label matlab.ui.control.Label
end
properties (Access = private)
loop_counter = 0 % Count while loop iteration
sending_counter = 0; %Count only while "sending data"
is_sending = false; %Flag: if value is true, assume "sending"
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
%While loop: loop until app is not valid.
while isvalid(app)
%Place your while loop functionality here:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
app.loop_counter = app.loop_counter + 1; %Increase loop counter
app.LoopCounter0Label.Text = ['Loop Counter: ', num2str(app.loop_counter)]; %Update loop coouner text lable.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Place your sending code here:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (app.is_sending)
app.sending_counter = app.sending_counter + 1; %Increase sending counter
app.Sending0Label.Text = ['Sending: ', num2str(app.sending_counter)]; %Update sending coouner text lable.
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Important %%%%
%Short pause must be used in order to allow buttons callbacks to be responsive (you can also call drawnow).
pause(0.01)
%%%% Important %%%%
end
end
% Button pushed function: StartSendingButton
function StartSendingButtonPushed(app, event)
app.is_sending = true; %Set flag to true when button is pressed.
end
% Button pushed function: StopSendingButton
function StopSendingButtonPushed(app, event)
app.is_sending = false; %Set flag to false when button is pressed.
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 440 304];
app.UIFigure.Name = 'UI Figure';
% Create StartSendingButton
app.StartSendingButton = uibutton(app.UIFigure, 'push');
app.StartSendingButton.ButtonPushedFcn = createCallbackFcn(app, #StartSendingButtonPushed, true);
app.StartSendingButton.BackgroundColor = [0.3922 0.8314 0.0745];
app.StartSendingButton.FontSize = 16;
app.StartSendingButton.Position = [33 197 130 49];
app.StartSendingButton.Text = 'Start Sending';
% Create StopSendingButton
app.StopSendingButton = uibutton(app.UIFigure, 'push');
app.StopSendingButton.ButtonPushedFcn = createCallbackFcn(app, #StopSendingButtonPushed, true);
app.StopSendingButton.BackgroundColor = [0.851 0.3255 0.098];
app.StopSendingButton.FontSize = 16;
app.StopSendingButton.Position = [33 129 130 49];
app.StopSendingButton.Text = 'Stop Sending';
% Create Sending0Label
app.Sending0Label = uilabel(app.UIFigure);
app.Sending0Label.FontSize = 16;
app.Sending0Label.Position = [229 203 151 37];
app.Sending0Label.Text = 'Sending: 0';
% Create LoopCounter0Label
app.LoopCounter0Label = uilabel(app.UIFigure);
app.LoopCounter0Label.FontSize = 16;
app.LoopCounter0Label.Position = [37 44 193 37];
app.LoopCounter0Label.Text = 'Loop Counter: 0';
% 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 and paste the entire code into an m file, to see how it works.
The code sample is not sending any data (and not related to Nucleo board), it's just advancing counters.
Here is how the sample application interface looks like:

How to customize App Designer figures in more ways than officially documented?

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