Micard
Micard

Reputation: 389

How to create custom UI for a MATLAB application?

MATLAB possesses all features I need in my application, except for one - a 21st century look to the applications it builds. The old UI controls with the skin from the 90s just don't cut it anymore. Are there ways to customize the GUI of the compiled window itself? I know of App Designer for MATLAB (which is an alternative for GUIDE as I understood) but that's not close enough. For example, I want a complete flat design look with sprites/buttons/etc drawn in Photoshop for my built application.

Would an external C library/framework be able to build a custom GUI when compiling an application?

I've tried to google this question and it seems like nobody cares about design in the scientific community. I'm not quite sure how to phrase my question, apologies. I hope some of you have a bit of experience with this.

P.S.: Below is the look I'd like to achieve: enter image description here

Upvotes: 5

Views: 1946

Answers (1)

CitizenInsane
CitizenInsane

Reputation: 4855

As described in my previous comment, and starting from R2019b, you can use uihtml components in new web-based uifigure (introduced in R2016a) to customize style of elements appearing on screen via css + javascript

Here below is a very simple example for a css-styled button:

First the matlab code (TestUiHtml.m):

function [] = TestUiHtml()
%[
    % Create the figure and layout
    fig = uifigure('Name', 'Test uihtml', 'Color', [1 1 1]);
    grid = uigridlayout('Parent', fig, 'ColumnWidth', { '1x', '1x' }, 'RowHeight', {200, '1x' }, 'BackgroundColor', fig.Color);  
    
    % Add a uihtml element (that will act like a button using html+css+javascript)
    button = uihtml('Parent', grid, 'HTMLSource', 'myway.html', 'DataChangedFcn', @(s,e)onBtnClicked(fig)); 

    % Button layout
    button.Layout.Row = 1; button.Layout.Column = [1 2];    
%]
end
function [] = onBtnClicked(fig)
%[
    uialert(fig, 'World!', 'Clicked', 'Icon', 'info');
%]
end

NB: Above code simply adds in the figure a uihtml component whose property HTMLSource points to the html content you want to have.

Here is the html code to describe the custom uihtml component content (myway.html):

<!DOCTYPE html>
<head>    
    <link rel="stylesheet" type="text/css" href="myway.css">
    <script type="text/javascript" src="myway.js"></script>
</head>    
<html>
    <body> 
        <div class="container">
          <button class="skewBtn blue" id="btn">Hello!</button>  
        </div>
    </body>
</html>

NB: It is not mandatory to have a fully well-formed html code (i.e. just a <button style="...">Hello</button> would do).

The linked css code to style the html content (myway.css):

body { 
    background-color: transparent;
}
.container {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  flex-wrap: wrap;
  height: 97vh;
}
.container .skewBtn {
  width: 180px;
  height: 80px;
  outline: none;
  cursor: pointer;
  background: none;
  transition: 0.5s;
  font-size: 24px;
  border-radius: 5px;
  font-family: "Lato", sans-serif;
}
.container .skewBtn:hover {
  border: none;
  color: white;
  font-size: 28px;
  transform: scale(1.1);
}
.blue {
  border: 2px solid #1976D2;
  color: #1976D2;
}
.blue:hover {
  background-color: #1976D2;
  transition: all 0.3s ease-in-out;
}

And finally the javascript code for event/data marshalling between matlab and the html-based component ... or for more advanced programming logic, if any, for the html-content (myway.js):

function setup(htmlComponent) 
{
    document.getElementById("btn").addEventListener("click", function(event) 
    {
        htmlComponent.Data = 1234; // dummy value to fire event on matlab side
    });
}

Marshalling is ensure via the data property of a htmlComponent object which both sides (i.e. matlab/javascript) are listening to for changes. Matlab automatically uses jsonencode/jsondecode in the background so you can pass back and forth almost any structure/values you need directly.

And voilà ... a nice-and-responsive css-styled button in matlab's figure:

uihtml button example

It would be of course better to refactor above code as a uibuttonex class modeled on existing uibutton property name/value pairs.

Sarting from R2021a it is eventually possible to add it to app designer library of components as described here (I personally don't use the designer and prefer to code interfaces programmatically).

Some remarks

It is not possible to directly style exiting uibutton, uipanel, uitab, etc... elements => Mathwork does not allow to access uifigure's html nor to inject css/javascript in it easily (see following undocumented-matlab thread and mlapptools project to try to cheat things). For instance a uibutton does not translate to directly <button> markup in uifigure's source but a lot of imbricated <div>, so it is very difficult to style (and will probably change from one release to another).

I would not recommend to create a single uihtml element in the figure and code everything in html+css+javascript, but I would rather recommend to create small and simple custom uibuttonex, etc elements ... else you'll have to deal with a single data blob to connect you interface with the matlab code which can be tricky and difficult to reuse.

Unfortunately it is yet not possible to create custom html-containers in which you can add other child ui-elements (custom or non-custom) ... say bye-bye to create containers similar to uix.GridFlex, uix.CardPanel from the wonderful GUI Layout toolbox or to creating nicely styled uitabex, etc... This is really a missing part !

Looking at source code of uifigure pages, custom ui-elements are also embedded in <iframe></iframe> markups, so it is not possible to inject some global css/javascript code (i.e. you'll have to repeat this for each uihtml element you create). It is not possible (or difficult) then to have multiple uihtml elements to interact with each-other (unless coding everything in a single page or passing through matlab code/events only).

Addendum : Here is a solution to get css-style from parent, unfortunately this does not solve one need to inject this css in the main uifigure source (well this can be done in javascript ... something like if !exist(parent.elements where id="mycss") => parent.document.inject(lalala))

Mathworks is going the good direction with uifigure and html in the background, but it's still a bit too locked for now and missing important containers from the GUI Layout toolbox.

NB: I tried the GUI Layout toolbox elements in uifigure ... some are working (with lot of resizing bugs), other are not working at all (GridFlex). Maybe a new version of the toolbox will come.

Charting

For modern charting you can use javascript libraries like D3js, SciChart, LightningChart, or others!!.

d3jsexample

There is some example using D3 on fileexchange

Upvotes: 9

Related Questions