As I have repeatedly posted in recent years, Matlab is advancing towards web-based GUI. The basic underlying technology is more-or-less stable: an HTML/Javascript webpage that is created-on-the-fly and rendered in a stripped-down browser window (based on Chromium-based jxBrowser in recent years). However, the exact mechanism by which the controls (“widgets”) are actually converted into visible components (currently based on the Dojo toolkit and its Dijit UI library) and interact with Matlab (i.e., the internal Matlab class structures that interact with the browser and Dojo) is still undergoing changes and is not quite as stable.
Customization hacks reported on this blog last year (part 1, part 2) may fail in some cases due to the changing nature of the undocumented internals. Some examples are the way by which we can extract the uifigure’s URL (which changed in R2017a), the ability to display and debug uifigures in a standard webbrowser with associated dev tools (which seems to have stopped working in R2017b), and the way by which we can extract the Dijit reference of displayed uicontrols.
Greatly assisting in this respect is Iliya Romm, who was the guest blogger for part 2 of this series last year. Iliya co-authored the open-source (GitHub) mlapptools toolbox, which enables accessing and customizing uifigure components using standard CSS, without users having to bother about the ugly hacks discussed in the previous parts of the series. This toolbox is really just a single Matlab class (mlapptools
), contained within a single m-file (mlapptools.m). In addition to this class, the toolbox includes a README.md mark-down usage documentation, and two demo functions, DOMdemoGUI.m and TableDemo.m.
Here is the effect of using TableDemo, that shows how we can customize individual uitable cells (each uitable cell is a separate Dijit widget that can be customized individually):
The mlapptools class contains several static methods that can be used individually:
- textAlign(uielement, alignment) – Modify text horizontal alignment (
'left'
,'center'
,'right'
,'justify'
or'initial'
) - fontWeight(uielement, weight) – Modify font weight (
'normal'
,'bold'
,'bolder'
,'lighter'
or'initial'
), depending on availability in the font-face used - fontColor(uielement, color) – Modify font color (e.g.
'red'
,'#ff0000'
,'rgb(255,0,0)'
or other variants) - setStyle(uielement, styleAttr, styleValue) – Modify a specified CSS style attribute
- aboutDojo() – Return version information about the Dojo toolkit
- getHTML(hFig) – Return the full HTML code of a uifigure
- getWebWindow(hFig) – Return a webwindow handle from a uifigure handle
- getWebElements (hControl) – Return a webwindow handle and a widget ID for the specified uicontrol handle
- getWidgetList(hFig, verboseFlag) – Return a cell-array of structs containing information about all widgets in the uifigure
- getWidgetInfo(hWebwindow, widgetId, verboseFlag) – Return information about a specific dijit widget
- setTimeout(hFig, seconds) – Override the default timeout (=5 secs) for dojo commands, for a specific uifigure
A few simple usage examples:
mlapptools.fontColor(hButton,'red') % set red text color mlapptools.fontWeight(hButton,'bold') % set bold text font mlapptools.setStyle(hButton,'border','2px solid blue') % add a 2-pixel solid blue border mlapptools.setStyle(hButton,'background-image','url(https://www.mathworks.com/etc/designs/mathworks/img/pic-header-mathworks-logo.svg)') % add background image |
Once you download mlapptools and add its location to the Matlab path, you can use it in any web-based GUI that you create, either programmatically or with Add-Designer.
The mlapptools is quite well written and documented, so if you are interested in the inner workings I urge you to take a look at this class’s private methods. For example, to understand how a Matlab uicontrol handle is converted into a Dojo widget-id, which is then used with the built-in dojo.style() Javascript function to modify the CSS attributes of the HTML <div>
or <span>
that are the control’s visual representation on the webpage. An explanation of the underlying mechanism can be found in part 2 of this series of articles on uifigure customizations. Note that the mlapptools code is newer than the article and contains some new concepts that were not covered in that article, for example searching through Dijit’s registry of displayed widgets.
Note: web-based GUI is often referred to as “App-Designed” (AD) GUI, because using the Matlab App Designer is the typical way to create and customize such GUIs. However, just as great-looking GUIs could be created programmatically rather than with GUIDE, so too can web-based GUIS be created programmatically, using regular built-in Matlab commands such as uifigure, uibutton and uitable (an example of such programmatic GUI creation can be found in Iliya’s TableDemo.m, discussed above). For this reason, I believe that the new GUIs should be referred to as “uifigures” or “web GUIs”, and not as “AD GUIs”.
If you have any feature requests or bugs related to mlapptools, please report them on its GitHub issues page. For anything else, please add a comment below.
Very useful resource. Once again the user community is way ahead of MathWorks developers. It’s about time they sorted out the ability to customise the appearance of individual cells in a table.
Thanks for the great head-start on breaking down the new UIFigure/WebWindow class and the interface with CEF. I am wondering if you have had any success with returning values from the CEF rendering to Matlab using JS calls. I can see that WebWindow.Channel has a JavaScriptReturnValue property – I am curious if we can return data from the CEF window to Matlab using this property and the underlying Channel.execute(‘executeJS’, options) method. Would be good as an interim solution for handling UIFigure interaction methods by allowing you to set callbacks to a component in CEF using JS (e.g. mouse events etc)and then returning results from the JS function to Matlab via JavaScriptReturnValue. So far all I can get JS to set for JavaScriptReturnValue is a result of a throw in the JS. But I cannot get JS console.error or console.log to return to this property. Perhaps the underlying function in cefclientmlconverter.dll only handles the JS throw return. Interested to hear your thoughts. Keep up the good work.
Hi,
Is there a way to import and use other JS UI libraries in MATLAB App Designer?
@Royi – yes, but this is definitely not easy. Hopefully custom JS integration will be better in future Matlab versions. Perhaps I’ll post something similar to this sometime.
Hi,
Much thanks for this very interesting and useful topic. I read the TableDemo and I was wondering if there was a way to control over one specific cell. For instance, let’s say we have a 3*3 uitable and we want the element located at the 2nd row and 3rd column to have a red background. Is there any way to have access to the widegetId of this specific cell (hopefully without using getWidgetList function)?
Thank you
H