Setting status-bar text

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);


simple figure status-bar text message

simple figure status-bar text message


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:


statusbar usage examples (click to see details)

statusbar usage examples (click to see details)


Categories: Desktop, Figure window, GUI, Java, Medium risk of breaking in future versions

Tags: , , , , ,

Bookmark and SharePrint Print

32 Responses to Setting status-bar text

  1. wei says:

    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

    • wei says:

      @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.

    • Yair Altman says:

      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:

      import javax.swing.UIManager;
      originalLnF = UIManager.getLookAndFeel;
      UIManager.setLookAndFeel('javax.swing.plaf.metal.MetalLookAndFeel');
         % Create your GUI here...
      UIManager.setLookAndFeel(originalLnF);

      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/

    • wei says:

      @Yair, Thank you for the help. I tried and it worked with second command below:

      jButton.setBorder('empty'); %no visible effect
      jButton.setBorder([]);

      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?

    • Yair Altman says:

      @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?

  2. Joan says:

    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.

    • Yair Altman says:

      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.

  3. Sunny R Billava says:

    can the same thing (Progress bar on status bar) be done for the simulink model editor window’s status bar?

    -Sunny

  4. Sandor Toth says:

    I tried statusbar(), but I have a problem when I use it together with tabgroup. After I built my tabs, then I called:

    statusbar('My text');

    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:

      >> set(hTabGroup,'pos',[0,0,1,.95])
  5. Red Kim says:

    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, ‘ ‘);
    ///////////////////////////////////

  6. Raphael says:

    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???

    • Raphael says:

      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

  7. Andrei Veldman says:

    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:

    set(sb.TextPanel, 'ToolTipText', sToolTip, 'MouseClickedCallback', @TestStatusBarCallback)

    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

  8. Luis Camilo says:

    Yair, How can I do that the background is transparent? Thanks.

  9. Jules-Florent EYA says:

    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 :

    jFrame = get(hFig,'JavaFrame');
    jRootPane = jFrame.fFigureClient.getWindow;

    Unfortunately I have the following error :

    No appropriate method, property, or field fFigureClient for class com.mathworks.hg.peer.HG2FigurePeer.

    The version of Matlab that I use is R2014b

    • Jules-Florent EYA says:

      Unfortunately Yair,

      I tried the following code :

      try
         % This works up to R2011a
         jRootPane = jFrame.fFigureClient.getWindow;
      catch
         try
            % This works from R2008b and up, up to HG2
            jRootPane = jFrame.fHG1Client.getWindow;
         catch
            % This works in HG2
            jRootPane = jFrame.fHG2Client.getWindow;
         end
      end

      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: https://undocumentedmatlab.com/blog/matlab-and-the-event-dispatch-thread-edt

    • Jules-Florent EYA says:

      Yair, this is the code of my function :

      % buildStatusBarObject
      function this = buildStatusBarObject(this)
          jFrame = get(this.mainWindow,'JavaFrame');
          if(isempty(jFrame))
              Logger.logError('Retrieved an EMPTY jFrame Object');
          end
          drawnow;
          pause(0.5);
          try
              % This works up to R2011a
              jRootPane = jFrame.fFigureClient.getWindow;
          catch
              try
                  % This works from R2008b and up, up to HG2
                  jRootPane = jFrame.fHG1Client.getWindow;
              catch
                  % This works in HG2
                  jRootPane = jFrame.fHG2Client.getWindow;
              end
          end
          statusbarObj = com.mathworks.mwswing.MJStatusBar;
          jRootPane.setStatusBar(statusbarObj);
          statusbarObj.setText('please wait - processing...')
          jRootPane.setStatusBarVisible(true);
      end

      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

Leave a Reply

Your email address will not be published. Required fields are marked *