Search code examples
matlabdojocustomizationundocumented-behaviormatlab-app-designer

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:

Example App Designer Figure

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?


Solution

  • 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:

    Inspecting the page in Firefox

    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:

    enter image description here

    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")']);
    

    Before and after


    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