Scroll Bar In Matlab App Designer
Customizing web-GUI uipanel
I would like to introduce guest blogger Khris Griffis. Today, Khris will continue the series of posts on web-based uifigure customization with an article showing how to create scrollable/customizable panels in web-based uifigures. This post follows last-week's article, about placing controls/axes within a scroll-panel in non-web (Java-based) figures. Users interested in advanced aspects and insights on the development roadmap of web-based Matlab GUI should also read Loren Shure's blog post from last week.
Motivation
As a retinal physiologist, I spend a lot of time in Matlab creating GUIs to visualize and analyze electrophysiological data. The data often requires a lot of processing and quality control checks before it can be used for interpretation and publication. Consequently, I end up with many control elements taking up precious space on my GUI.
In Java-based (legacy/GUIDE) figures, this wasn't a huge problem because, depending on what GUI components I needed, I could use a pure Matlab approach (a child panel within a parent panel, with a couple of control sliders moving the child panel around), or a number of Java approaches (which are always more fun; Yair described such an approach last week).
Unfortunately, the web-based (App-Designer) figure framework doesn't support Java, and the pure/documented Matlab approach just doesn't look good or function very well:
AppDesigner uislider is not a good scrollbar, no matter what we do to it!
Fortunately, the new web framework allows us to use HTML, CSS and JavaScript (JS) to modify elements in the uifigure , i.e. its web-page DOM. It turns out that the uipanel object is essentially just a <div>
with a Matlab-designed CSS style. We can customize it with little effort.
The main goal here is to create a scrollable customizable uipanel containing many uicontrol elements, which could look something like this:
A simple command-window example
Since we are building on the series of uifigure customizations, I expect you have already read the preceding related Undocumented Matlab posts:
- Customizing uifigures part 1
- Customizing uifigures part 2
- Customizing uifigures part 3
Also, I highly recommend cloning (or at least downloading) the mlapptools toolbox repo on Github (thanks Iliya Romm et al.). We will use it to simplify life today.
Using the mlapptools
toolbox, we need just a few lines of code to set up a scrollable panel. The important thing is knowing how big the panel needs to be to hold all of our control objects. Once we know this, we simply set the panel's Position property accordingly. Then we can use simple CSS to display scrollbars and define the viewing dimensions.
For example, if we need 260px in width by 720px in height to hold our control widgets, but only have 200px height available, we can solve this problem in 3 steps:
- Set the uipanel 's Dimension property to be 260px wide by 720px tall.
- Set the viewing height using
mlapptools.setStyle(scrollPane,'height','200px')
for the panel's CSSheight
style attribute. - Display the vertical scrollbar by calling
mlapptools.setStyle(scrollPane,'overflow-y','scroll')
for the panel's CSSoverflow-y='scroll'
style attribute.
% Create the figure fig = uifigure( 'Name', 'Scroll Panel Test' ); % Place a uipanel on the figure, color it for fun scrollPane = uipanel(fig, 'BackgroundColor', [ 0.5,0.4,1 ] ); % Define the space requirements for the controls totalWidth = 260; %px totalHeight = 720; %px viewHeight = 200; %px % STEP 1: set the uipanel's Position property to the required dimensions scrollPane.Position ( 3 ) = totalWidth; % WIDTH scrollPane.Position ( 4 ) = totalHeight; % HEIGHT % STEP 2: set the viewing height mlapptools.setStyle (scrollPane, 'height', sprintf ( '%dpx', viewHeight) ); % STEP 3: display the vertical scrollbar mlapptools.setStyle (scrollPane, 'overflow-y', 'scroll' ); % Add control elements into the uipanel ...
% Create the figure fig = uifigure('Name', 'Scroll Panel Test'); % Place a uipanel on the figure, color it for fun scrollPane = uipanel(fig, 'BackgroundColor', [0.5,0.4,1]); % Define the space requirements for the controls totalWidth = 260; %px totalHeight = 720; %px viewHeight = 200; %px % STEP 1: set the uipanel's Position property to the required dimensions scrollPane.Position(3) = totalWidth; % WIDTH scrollPane.Position(4) = totalHeight; % HEIGHT % STEP 2: set the viewing height mlapptools.setStyle(scrollPane, 'height', sprintf('%dpx', viewHeight)); % STEP 3: display the vertical scrollbar mlapptools.setStyle(scrollPane, 'overflow-y', 'scroll'); % Add control elements into the uipanel ...
Example scrollable uipanel in a Matlab uifigure
Because this is a web-based GUI, notice that you can simply hover your mouse over the panel and scroll with your scroll wheel. Awesome, right?
Note that the CSS height
/width
style attributes don't affect the actual size of our panel, just how much of the panel we can see at once ("viewport").
The CSS overflow
style attribute has a number of options. For example, setStyle(scrollPane,'overflow','auto')
causes scrollbars to automatically hide when the viewing area is larger than panel's dimensions. Review the CSS overflow
attribute to learn about other related settings that affect the panel's behavior.
Styling the scrollbars
The mlapptools
toolbox utilizes dojo.js to query the DOM and set styles, which is essentially setting inline styles on the DOM element, i.e. <div ... style="color: red;background:#FEFEFE;..."> ... </div>
. This has the added benefit of overriding any CSS classes Matlab is imposing on the DOM (see CSS precedence). We can inject our own classes into the page's <head>
tag and then use dojo.setClass()
to apply our classes to specific GUI elements. For example, we can style our bland scrollbars by using CSS to define a custom scrollpane
style class:
/* CSS To stylize the scrollbar */ .scrollpane ::-webkit-scrollbar { width : 20px ; } /* Track */ .scrollpane ::-webkit-scrollbar-track { background-color : white ; box-shadow : inset 0 0 5px white ; border-radius : 10px ; } /* Handle */ .scrollpane ::-webkit-scrollbar-thumb { background : red ; border-radius : 10px ; } /* Handle on hover */ .scrollpane ::-webkit-scrollbar-thumb: hover { background : #b30000 ; }
/* CSS To stylize the scrollbar */ .scrollpane::-webkit-scrollbar { width: 20px; } /* Track */ .scrollpane::-webkit-scrollbar-track { background-color: white; box-shadow: inset 0 0 5px white; border-radius: 10px; } /* Handle */ .scrollpane::-webkit-scrollbar-thumb { background: red; border-radius: 10px; } /* Handle on hover */ .scrollpane::-webkit-scrollbar-thumb:hover { background: #b30000; }
To get the CSS into the document header, we need to first convert ("stringify") it in Matlab:
% CSS styles 'stringified' for MATLAB % note that the whole style tag is wrapped in single quotes, that is required! % i.e. '<style>...</style>' which prints to the command window as: % ''<style>...</style>'' cssText = [ ... '' '<style>\n', ... ' .scrollpane::-webkit-scrollbar {\n', ... ' width: 20px;\n', ... ' }\n', ... ' /* Track */\n', ... ' .scrollpane::-webkit-scrollbar-track {\n', ... ' background-color: white;\n', ... ' box-shadow: inset 0 0 5px white;\n', ... ' border-radius: 10px;\n', ... ' }\n', ... ' /* Handle */\n', ... ' .scrollpane::-webkit-scrollbar-thumb {\n', ... ' background: red; \n', ... ' border-radius: 10px;\n', ... ' }\n', ... ' /* Handle on hover */\n', ... ' .scrollpane::-webkit-scrollbar-thumb:hover {\n', ... ' background: #b30000; \n', ... ' }\n', ... '</style>' '' ... ];
% CSS styles 'stringified' for MATLAB % note that the whole style tag is wrapped in single quotes, that is required! % i.e. '<style>...</style>' which prints to the command window as: % ''<style>...</style>'' cssText = [... '''<style>\n', ... ' .scrollpane::-webkit-scrollbar {\n', ... ' width: 20px;\n', ... ' }\n', ... ' /* Track */\n', ... ' .scrollpane::-webkit-scrollbar-track {\n', ... ' background-color: white;\n', ... ' box-shadow: inset 0 0 5px white;\n', ... ' border-radius: 10px;\n', ... ' }\n', ... ' /* Handle */\n', ... ' .scrollpane::-webkit-scrollbar-thumb {\n', ... ' background: red; \n', ... ' border-radius: 10px;\n', ... ' }\n', ... ' /* Handle on hover */\n', ... ' .scrollpane::-webkit-scrollbar-thumb:hover {\n', ... ' background: #b30000; \n', ... ' }\n', ... '</style>''' ... ];
As explained in Customizing uifigures part 1, we can execute JavaScript (JS) commands through the webWindow
object. To simplify it, we use the method from Customizing uifigures part 2 to obtain the webWindow
object for our GUI window and and use the executeJS()
method to add our HTML into the document's <head>
tag. It is worth checking out the properties and methods of the JS document
object.
% get the webWindow object webWindow = mlapptools.getWebWindow (fig); % inject the CSS webWindow.executeJS ( [ 'document.head.innerHTML += ',cssText] );
% get the webWindow object webWindow = mlapptools.getWebWindow(fig); % inject the CSS webWindow.executeJS(['document.head.innerHTML += ',cssText]);
Now the tricky part is that we have to assign our new CSS scrollpane
class to our uipanel . We need 2 things: the webWindow
object and the data-tag
(our panel's unique ID) attribute.
% get the uipanel data-tag attr. [webWindow, panelID] = mlapptools.getWebElements (scrollPane); %make a dojo.js statement (use addClass method) setClassString = sprintf ( ... 'dojo.addClass(dojo.query("[%s = ' '%s' ']")[0], "%s")',... panelID.ID_attr, panelID.ID_val, 'scrollpane' ); % add class to DOM element webWindow.executeJS (setClassString);
% get the uipanel data-tag attr. [webWindow, panelID] = mlapptools.getWebElements(scrollPane); %make a dojo.js statement (use addClass method) setClassString = sprintf(... 'dojo.addClass(dojo.query("[%s = ''%s'']")[0], "%s")',... panelID.ID_attr, panelID.ID_val, 'scrollpane'); % add class to DOM element webWindow.executeJS(setClassString);
The results of applying our
scrollpane
CSS style on our scroll-pane's scrollbars Note: Unfortunately, because of CSS precedence rules, we may have to use the dreaded !important
CSS qualifier to get the desired effect. So if the result doesn't match your expectations, try adding !important
to the CSS class attributes.
Styling the uipanel
Each uipanel appears to be composed of 4 <div>
HTML elements: a wrapper, internal container for the panel title, a separator, and the panel's body (contents). We first use mlapptools.getWebElements()
to get the data-tag
ID for the wrapper node. We can then apply styles to the wrapper, or any child node, with CSS and JS.
For example, we can use CSS3 patterns (such as one in this CSS3 gallery) to liven up our panel. We can also use CSS to define a block element that will replace the title container with some static text. The CSS below would be appended to the cssText
string we made for styling the scrollbars above:
/* DECORATE THE BACKGROUND */ /* Stars modified from: http://lea.verou.me/css3patterns/#stars */ .scrollpane { overflow : auto ; background : linear-gradient( 324deg , #232927 4% , transparent 4% ) -70px 43px , linear-gradient( 36deg , #232927 4% , transparent 4% ) 30px 43px , linear-gradient( 72deg , #e3d7bf 8.5% , transparent 8.5% ) 30px 43px , linear-gradient( 288deg , #e3d7bf 8.5% , transparent 8.5% ) -70px 43px , linear-gradient( 216deg , #e3d7bf 7.5% , transparent 7.5% ) -70px 23px , linear-gradient( 144deg , #e3d7bf 7.5% , transparent 7.5% ) 30px 23px , linear-gradient( 324deg , #232927 4% , transparent 4% ) -20px 93px , linear-gradient( 36deg , #232927 4% , transparent 4% ) 80px 93px , linear-gradient( 72deg , #e3d7bf 8.5% , transparent 8.5% ) 80px 93px , linear-gradient( 288deg , #e3d7bf 8.5% , transparent 8.5% ) -20px 93px , linear-gradient( 216deg , #e3d7bf 7.5% , transparent 7.5% ) -20px 73px , linear-gradient( 144deg , #e3d7bf 7.5% , transparent 7.5% ) 80px 73px !important; background-color : #232977 !important; background-size : 100px 100px !important; } /* STYLES TO CENTER A TEXT BLOCK ON A WHITE SEMI-TRANSPARENT BACKGROUND BLOCK */ /* White block div */ .blockdiv { color : black ; font : 25px Arial, sans-serif !important; background : rgba ( 255 , 255 , 255 , 0.75 ) ; width : 100% ; height : 30px ; } /* Text container centered in .blockdiv */ .textdiv { position : relative ; float : left ; top : 50% ; left : 50% ; transform : translate ( -50% , -50% ) ; }
/* DECORATE THE BACKGROUND */ /* Stars modified from: http://lea.verou.me/css3patterns/#stars */ .scrollpane { overflow: auto; background: linear-gradient(324deg, #232927 4%, transparent 4%) -70px 43px, linear-gradient( 36deg, #232927 4%, transparent 4%) 30px 43px, linear-gradient( 72deg, #e3d7bf 8.5%, transparent 8.5%) 30px 43px, linear-gradient(288deg, #e3d7bf 8.5%, transparent 8.5%) -70px 43px, linear-gradient(216deg, #e3d7bf 7.5%, transparent 7.5%) -70px 23px, linear-gradient(144deg, #e3d7bf 7.5%, transparent 7.5%) 30px 23px, linear-gradient(324deg, #232927 4%, transparent 4%) -20px 93px, linear-gradient( 36deg, #232927 4%, transparent 4%) 80px 93px, linear-gradient( 72deg, #e3d7bf 8.5%, transparent 8.5%) 80px 93px, linear-gradient(288deg, #e3d7bf 8.5%, transparent 8.5%) -20px 93px, linear-gradient(216deg, #e3d7bf 7.5%, transparent 7.5%) -20px 73px, linear-gradient(144deg, #e3d7bf 7.5%, transparent 7.5%) 80px 73px !important; background-color: #232977 !important; background-size: 100px 100px !important; } /* STYLES TO CENTER A TEXT BLOCK ON A WHITE SEMI-TRANSPARENT BACKGROUND BLOCK */ /* White block div */ .blockdiv { color: black; font: 25px Arial, sans-serif !important; background: rgba(255,255,255,0.75); width: 100%; height: 30px; } /* Text container centered in .blockdiv */ .textdiv { position: relative; float: left; top: 50%; left: 50%; transform: translate(-50%, -50%); }
To insert a static text element and its container, we can create a small JS routine that creates parent and child nodes that replace the panel's title container:
% Make a nodeID string to make the JS call more generic nodeID = sprintf ( '' '[%s="%s"]' '', panelID.ID_attr, panelID.ID_val ); % JS that creates a div within a div, each with their own classes % The inner div gets the text and is centered within the outer div % These elements are added before the node MATLAB will use for any controls % added to scrollPane js = sprintf ( ... [ ... 'var d = document.createElement("div");', ... 'var t = document.createElement("div");', ... 'd.classList.add("blockdiv");',... 't.classList.add("textdiv");', ... 't.innerHTML= "Some Static Text";', ... 'd.appendChild(t);', ... 'document.querySelectorAll(%s)[0]',... '.replaceChild(d,document.querySelectorAll(%s)[0].firstChild);' ... ], ... nodeID, nodeID ... ); % execute the JS webWindow.executeJS (js);
% Make a nodeID string to make the JS call more generic nodeID = sprintf('''[%s="%s"]''', panelID.ID_attr, panelID.ID_val); % JS that creates a div within a div, each with their own classes % The inner div gets the text and is centered within the outer div % These elements are added before the node MATLAB will use for any controls % added to scrollPane js = sprintf( ... [ ... 'var d = document.createElement("div");', ... 'var t = document.createElement("div");', ... 'd.classList.add("blockdiv");',... 't.classList.add("textdiv");', ... 't.innerHTML= "Some Static Text";', ... 'd.appendChild(t);', ... 'document.querySelectorAll(%s)[0]',... '.replaceChild(d,document.querySelectorAll(%s)[0].firstChild);' ... ], ... nodeID, nodeID ... ); % execute the JS webWindow.executeJS(js);
Panel background and static elements
It seems to me that this approach might help to make lighter-weight apps, instead of having to make all those app.Label objects in Matlab's App-Designer.
Quick recap
So let's restate the process:
- Create a uipanel with the Position property set accordingly large enough for your control elements.
- Use
mlapptools.setStyle()
to set theoverflow
style attribute as desired. - Use
mlapptools.setStyle()
to set thewidth
and/orheight
style attributes to the viewing size (this is how big the viewing area of the panel needs to be in order to fit nicely in your app). - Add your control elements with the scrolling uipanel as the parent.
- If you want some special styles, create a stylesheet and inject it into the
<head>
and be sure to add the class to your panel's HTMLclassList
.
The order of items 2-4 are not really important. You just need to ensure that the panel is large enough (via its Position property) to include all your elements/controls.
I really hope that one day soon MathWorks will add CSS and JS hooks to uifigure GUI components (perhaps as settable CSS/JS properties that accept strings?), so that Matlab users could attach their own CSS and JS customizations directly within AppDesigner, without having to go through such undocumented hoops as I've shown here. In Loren Shure's latest blog post, Matlab product manager Dave Garisson indicated that this is indeed planned for a near-future Matlab release (at least for JS, but hopefully also for CSS):
"we are also investigating ways to provide a documented solution for integrating 3rd party JavaScript components in MATLAB apps."
A complete working example
I created a complete working example in Matlab's App Designer while figuring this whole thing out. The code (CWE.m) can be downloaded here, and then run directly from Matlab's command window. Alternatively, the corresponding App Designer file (CWE.mlapp) can be downloaded here. You are welcome to use/adapt the code in your own project. Just to be clear, I love wild colors and crazy themes, but I don't recommend going this overboard for a real project.
Running app demo
I can't thank Yair enough for suggesting that I turn this tip into a guest post for you readers. And I want to give a huge thank you to you, the reader, for persevering all the way to the end of this post…
Cheers!
-Khris
Addendum September 17, 2018 : Scrolling panels in uifigures are now a fully-supported documented functionality via the new scroll function and Scrollable property, starting with Matlab release R2018b. You can still use the mechanism described above, which also works for older Matlab releases.
Leave a Reply
HTML tags such as <b> or <i> are accepted.Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">I reserve the right to edit/delete comments (read the site policies).
a = magic(3);
disp(sum(a))
</pre>
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.
Scroll Bar In Matlab App Designer
Source: https://undocumentedmatlab.com/articles/customizing-web-gui-uipanel
Posted by: riveracrourt.blogspot.com
0 Response to "Scroll Bar In Matlab App Designer"
Post a Comment