Most GUI windows nowadays, ranging from web browsers to editors and data-entry windows, have a small status-bar at their bottom. Statusbars are a great way to convey non-critical information to the user, in a non-intrusive manner (without popup windows).
Matlab windows are no exception: they too have status bars which are sometimes used by internal Matlab functions. Unfortunately, there is no documented way to modify Matlab statusbars. In this post I will demonstrate the undocumented way of setting status-bar text, which is probably the most useful use-case. In next week’s post, I will expand this to include more complex customizations, such as dynamic progress-bars or a corner grip.
Note: Users interested in non-intrusive status-bar messages, may also be interested in another non-intrusive messaging mechanism which I have described some months ago: Setting system tray popup messages.
Desktop window status-bar
We start with the simplest case of setting the desktop’s statusbar text. We have no further to go than the bottom of Matlab’s own uiopen (see %matlabroot%/toolbox/matlab/uitools/uiopen.m):
dt = javaMethod('getInstance', 'com.mathworks.mde.desk.MLDesktop'); if dt.hasMainFrame dt.setStatusText(message); else disp(message); end |
Basically, we try to get the Java reference to the Matlab desktop, see if it has an open window frame and if so then we use its setStatusText() method to display a text message; if not then we display the message in the Command Window (which is probably a non-window console).
Unfortunately, if we place this code in our m-files as-is, our status message will be overridden by Matlab’s “busy” message. A solution for this is to use a one-time (discardable) timer. Another complication is meant for supporting Matlab 6, in which we get the desktop reference differently, and which did not yet have the timer function. The final code now looks like this:
%% Set the status bar text of the Matlab desktop function setDesktopStatus(statusText) % First, get the desktop reference try desktop = com.mathworks.mde.desk.MLDesktop.getInstance; % Matlab 7+ catch desktop = com.mathworks.ide.desktop.MLDesktop.getMLDesktop; % Matlab 6 end if desktop.hasMainFrame % Schedule a timer to update the status text % Note: can't update immediately (will be overridden by Matlab's 'busy' message) try timerFcn = {@setText,desktop,statusText}; t = timer('TimerFcn',timerFcn, 'StartDelay',0.05, 'ExecutionMode','singleShot'); start(t); catch % Probably an old Matlab version that still doesn't have timer desktop.setStatusText(statusText); end else disp(statusText); end %% Utility function used as setDesktopStatus's internal timer's callback function setText(varargin) if nargin == 4 % just in case... targetObj = varargin{3}; statusText = varargin{4}; targetObj.setStatusText(statusText); else % should never happen... end |
Figure window status-bar
Setting the status-bar text on figure windows is slightly more difficult: getstatus and setstatus appear to be early attempts by Matlab to enable users an access to a figure’s statusbar. In this early attempt, Matlab assumes that the user prepares a text label having a tag of ‘status’. getstatus then returns this label’s string, while setstatus modifies it:
uicontrol('Parent',gcf,'Style','text','Tag','Status'); setstatus(gcf, 'Goodbye'); string = getstatus(gcf); |
Unfortunately, nothing prevents the user from placing the label anywhere in the figure, and also from having multiple such labels at once, adding to the confusion. The result is inconsistent with normal windowing practices, and this is probably the reason that MathWorks have grandfathered these functions in Matlab 7.4 (R2007a). It would be much more logical for Matlab to have the statusbar accessible via a figure property, and perhaps this will happen in some future version.
A better, consistent and more flexible access to the figure statusbar can be achieved by using some undocumented Java functions. In a nutshell, we get the figure’s JavaFrame property (which Matlab has warned might be discontinued in some near upcoming release), which is sort of a handle reference to the Java window underlying the Matlab figure window (not exactly but close enough for today). We then travel up and down the JavaFrame window objects hierarchy (use my FindJObj utility on the File Exchange to understand this hierarchy) until we get to the status bar object. We then set its text and make it visible (it’s invisible by default). Here is a trimmed-down version (excluding the necessary sanity checks, exception handling etc.):
% Alternative #1 (hFig = requested figure's handle) jFrame = get(hFig,'JavaFrame'); jFigPanel = get(jFrame,'FigurePanelContainer'); jRootPane = jFigPanel.getComponent(0).getRootPane; jRootPane = jRootPane.getTopLevelAncestor; statusbarObj = jRootPane.getStatusBar; statusbarObj.setText(statusText); jRootPane.setStatusBarVisible(1); % Alternative #2 jFrame = get(hFig,'JavaFrame'); jRootPane = jFrame.fFigureClient.getWindow; statusbarObj = com.mathworks.mwswing.MJStatusBar; jRootPane.setStatusBar(statusbarObj); statusbarObj.setText(statusText); |
StatusBar utility
I’ve created a wrapper function, aptly called statusbar, encapsulating all the above with some additional error checking etc. I have posted statusbar on the MathWorks File Exchange. Readers are encouraged to look at this submission’s source code for examples of statusbar manipulation. Here are several usage examples:
Yair,
This is about uicomponent (e.g. JButton). How does one set button’s Border property so button’s appearance is isolated from PC desktop appearance Windows XP vs. Classic styles?
@Wei – First you need to get the underlying Java handle of the Matlab uicomponent (this is done using my FindJObj utility on the File Exchange). Then set the java handle’s Border property as explained here: http://java.sun.com/docs/books/tutorial/uiswing/components/border.html
Some useful examples: http://www.java2s.com/Code/Java/Swing-JFC/Border.htm
Yair
@Yair,
I’m using your uicomponent for such button. there is java component border which, depending on desktop’s appearance, is either com.sun.java.swing.plaf.windows.XPStyle$XPEmptyBorder or javax.swing.plaf.BorderUIResource$CompoundBorderUIResource
Not sure how to proceed to lock onto one style or the other.
My uicomponent utility (and similarly Matlab’s javacomponent function) returns the Java reference. This can be used to update the component’s Border property. The default component border is set at creation-time based on the currently-active Look-and-Feel (L&F), but can always be overridden. You can’t pre-lock a property value. But you can modify it immediately following creation, which is essentially the same thing.
Alternately, you can create your component with some specific predefined L&F, regardless of the system’s L&F, as follows:
Here are two official documentation references for the Java L&F system:
http://java.sun.com/docs/books/tutorial/uiswing/lookandfeel
http://java.sun.com/products/jlf/
@Yair, Thank you for the help. I tried and it worked with second command below:
Another (plaf?) question: after a jbutton is pressed, there is a dotted rectangular line on the button icon indicating the latest focused object. Could this line be removed or set to the same background color so it is invisible?
@wei – I believe (not sure) that the dotted line is OS-generated. I do not know of a way to control it with PLAF – you may need to hack some really internal Java/OS function for this…
If you don’t wish the control selection to become visible, perhaps you should simply set the control to be non-focusable or disabled?
First of all, congratulations for your excellent site.
I looked for a place where to post this idea, but I didn’t know where to.
I do not like Matlab uitable, and in GUI I use the java table. However, java table is difficult for me to program, specially the Callbacks when someone edits a cell value. Is there a way I could use the table in the ArrayEditor to edit data from a GUI?. The table in the ArrayEditor looks like the java table, and has many features when right-click, and also updates the value of the matrix when I edit a cell value. My idea is to have a button in my main GUI that says “Edit”. When clicked, it opens the ArrayEditor in a separate window. This window should also have buttons Accept, Cancel. In Accept, it collects the data from the ArrayEditor and closes window. When cancel, it simply closes the windows. To put it in a nutshell… is there a way to put the ArrayEditor table in a new figure window, with room left for adding buttons? (I can do all the rest). Thank you very much and congratulations again.
Thank Joan
You may find my Java-based data table utility (on the Matlab File Exchange) useful as a general-purpose sortable Java table. My PlotData utility also uses a Java table, in this case to display the raw data of figure plots. With the knowledge that you have displayed in your question, it should be fairly easy for you to modify the code in these two utilities to fit your purposes.
can the same thing (Progress bar on status bar) be done for the simulink model editor window’s status bar?
-Sunny
@Sunny – I don’t know: I haven’t played with Simulink too much…
I tried statusbar(), but I have a problem when I use it together with tabgroup. After I built my tabs, then I called:
and the tabs disappeared.
Is it some incompatibility issue?
@Sandor – the new statusbar simply pushed the figure contents upward a few pixels. Your tabs were probably right at the top of the figure contents, and so they were pushed upward beneath the toolbar and effectively became hidden.
To fix this, simply resize the tab-group’s position property so that its height decreases. For example:
Yair,
I read “Sandor Toth” says. but really I don’t know.
I tried Statusbar with tabgoup.
but tabgroup title bar was up.
and panel is normalized in tabgroup.
But It’s different between it ans with out statusbar.
I can’t say detail about this.
Can you see my script??
/////////////////////////////////////
fh = figure;
htab = uitabgroup(fh);
set(htab, ‘Units’, ‘characters’);
set(htab, ‘position’, [10 10 50 20]);
hhtab = uitab(htab, ‘title’,’Simulation ‘);
hpanel = uipanel(hhtab);
sta_h = statusbar(fh, ‘ ‘);
///////////////////////////////////
It’s result.
left side is without statusbar.
right side is within statusbar.
@Kim – did you read my reply to Sandor? try it…
Yes. I did it.
I hope you see this picture.
https://lh6.googleusercontent.com/-z606Gx5OMLw/T8VbXPZQfSI/AAAAAAAAAAk/yw3jRhHjcU8/s912/Result_Img.png
The picture is with run script.
@Kim – I don’t think you read my reply: Your script has to include
if you want the tabs to appear with the statusbar
I’m Sorry for reply again.
It worked, but it isn’t I want to.
Is it the best way for uitabgoup??
I tried 4 way show uitabgroup within Statusbar.
This picture is result.
https://lh3.googleusercontent.com/-lpouA2sLtbo/T8avFMkgQ9I/AAAAAAAAAA0/Eox1IrVovi4/s640/Result.png
And I also used findjobj() function. uitabgroup has JPanel.
I think the JPanel was pushed by statubar.
So… If I get Handle of JPanel in Matlab, I can move uitabgroup.. maybe..
Is it possible to change the position of the status bar to have it integrated in the GUI ?
@Raphael – the status bar is always placed at the bottom of the figure, it cannot be moved. This is the convention in all Windows. Have you ever seen a status bar NOT at the bottom of any window???
I guess I was more thinking about the progress bars in a window, like installation processes.
But I think I found more help regarding this in your javacomponent page
There was a recent blog post about progress bars you may find useful, here
Shalom Yair,
A while ago I wrote a little Matlab utility which uses your brilliant “statusbar” utility from the File Exchange. I was getting the handle returned by “statusbar” (which is of type ‘
com.mathworks.mwswing.MJStatusBar
‘) and then I was setting its ‘ToolTipText‘ and ‘MouseClickedCallback‘ properties. The code looks like this:This used to work just fine in the past, but in more recent versions of Matlab (e.g. R2014a) I’m getting the following error:
The name 'MouseClickedCallback' is not an accessible property for an instance of class 'com.mathworks.mwswing.MJStatusBar$1'.
I’m guessing they have changed the way one sets up a callback for a mouse click on the status bar. Could you let me know how this is done these days?
Thanks,
Andrei V
@Andrei – see my article from last week:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events-in-r2014a
Your solution works perfectly!
P.S. I always find coincidences unsettling, like you having already posted a week ago the solution to the problem which I encountered only yesterday! Makes one wonder…
Yair, How can I do that the background is transparent? Thanks.
Thank you Mr. Altman for sharing with us the result of your research.
I have an issue that I do not understand:
In my code I use the two lines that you provided above :
Unfortunately I have the following error :
The version of Matlab that I use is R2014b
@Jules – see item #2 here: http://undocumentedmatlab.com/blog/hg2-update#observations
Unfortunately Yair,
I tried the following code :
And the error that is have is now : Attempt to reference field of non-structure array.
It is because JRootPane is empty.
(I use the R2014b Matlab version)
this is probably because you have not ensured that the figure window is fully displayed when you reach that code line. Adding drawnow and pause(0.5) should solve this: http://undocumentedmatlab.com/blog/matlab-and-the-event-dispatch-thread-edt
Yair, this is the code of my function :
The jRootPane is still empty, this is why the call ”jRootPane.setStatusBar(statusbarObj);” creates the following error : Attempt to reference field of non-structure array.
If the window is not visible then this would be the expected result