Set limits for values in the cells of an uitable - matlab

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.

Related

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

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.

How to print text message in UI App in Matlab

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.

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