function statusbarHandles = statusbar(varargin) %statusbar set/get the status-bar of Matlab desktop or a figure % % statusbar sets the status-bar text of the Matlab desktop or a figure. % statusbar accepts arguments in the format accepted by the sprintf % function and returns the statusbar handle(s), if available. % % Syntax: % statusbarHandle = statusbar(handle, text, sprintf_args...) % % statusbar(text, sprintf_args...) sets the status bar text for the % current figure. If no figure is selected, then one will be created. % Note that figures with 'HandleVisibility' turned off will be skipped % (compare findobj & findall). % In these cases, simply pass their figure handle as first argument. % text may be a single string argument, or anything accepted by sprintf. % % statusbar(handle, ...) sets the status bar text of the figure % handle (or the figure which contains handle). If the status bar was % not yet displayed for this figure, it will be created and displayed. % If text is not supplied, then any existing status bar is erased, % unlike statusbar(handle, '') which just clears the text. % % statusbar(0, ...) sets the Matlab desktop's status bar text. If text is % not supplied, then any existing text is erased, like statusbar(0, ''). % % statusbar([handles], ...) sets the status bar text of all the % requested handles. % % statusbarHandle = statusbar(...) returns the status bar handle % for the selected figure. The Matlab desktop does not expose its % statusbar object, so statusbar(0, ...) always returns []. % If multiple unique figure handles were requested, then % statusbarHandle is an array of all non-empty status bar handles. % % Notes: % 1) The format statusbarHandle = statusbar(handle) does NOT erase % any existing statusbar, but just returns the handles. % 2) The status bar is 20 pixels high across the entire bottom of % the figure. It hides everything between pixel heights 0-20, % even parts of uicontrols, regardless of who was created first! % 3) Three internal handles are exposed to the user (Figures only): % - CornerGrip: a small square resizing grip on bottom-right corner % - TextPanel: main panel area, containing the status text % - ProgressBar: a progress bar within TextPanel (default: invisible) % % Examples: % statusbar; % delete status bar from current figure % statusbar(0, 'Desktop status: processing...'); % statusbar([hFig1,hFig2], 'Please wait while processing...'); % statusbar('Processing %d of %d (%.1f%%)...',idx,total,100*idx/total); % statusbar('Running... [%s%s]',repmat('*',1,fix(N*idx/total)),repmat('.',1,N-fix(N*idx/total))); % existingText = get(statusbar(myHandle),'Text'); % % Examples customizing the status-bar appearance: % sb = statusbar('text'); % set(sb.CornerGrip, 'visible','off'); % set(sb.TextPanel, 'Foreground',[1,0,0], 'Background','cyan', 'ToolTipText','tool tip...') % set(sb, 'Background',java.awt.Color.cyan); % % % sb.ProgressBar is by default invisible, determinite, non-continuous fill, min=0, max=100, initial value=0 % set(sb.ProgressBar, 'Visible','on', 'Minimum',0, 'Maximum',500, 'Value',234); % set(sb.ProgressBar, 'Visible','on', 'Indeterminate','off'); % indeterminate (annimated) % set(sb.ProgressBar, 'Visible','on', 'StringPainted','on'); % continuous fill % set(sb.ProgressBar, 'Visible','on', 'StringPainted','on', 'string',''); % continuous fill, no percentage text % % % Adding a checkbox % jCheckBox = javax.swing.JCheckBox('cb label'); % sb.add(jCheckBox,'West'); % Beware: East also works but doesn't resize automatically % % Notes: % Statusbar will probably NOT work on Matlab versions earlier than 6.0 (R12) % In Matlab 6.0 (R12), figure statusbars are not supported (only desktop statusbar) % % Warning: % This code heavily relies on undocumented and unsupported Matlab % functionality. It works on Matlab 7+, but use at your own risk! % % Bugs and suggestions: % Please send to Yair Altman (altmany at gmail dot com) % % Change log: % 2007-May-04: Added partial support for Matlab 6 % 2007-Apr-29: Added internal ProgressBar; clarified main comment % 2007-Apr-25: First version posted on MathWorks file exchange: http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=14773 % % See also: % ishghandle, sprintf, findjobj (on the file exchange) % License to use and modify this code is granted freely without warranty to all, as long as the original author is % referenced and attributed as such. The original author maintains the right to be solely associated with this work. % Programmed and Copyright by Yair M. Altman: altmany(at)gmail.com % $Revision: 1.0 $ $Date: 2007/04/25 16:43:24 $ % Check for available Java/AWT (not sure if Swing is really needed so let's just check AWT) if ~usejava('awt') error('YMA:statusbar:noJava','statusbar only works on Matlab envs that run on java'); end % Args check if nargin < 1 | ischar(varargin{1}) %#ok for Matlab 6 compatibility handles = gcf; % note: this skips over figures with 'HandleVisibility'='off' else handles = varargin{1}; varargin(1) = []; end % Ensure that all supplied handles are valid HG GUI handles (Note: 0 is a valid HG handle) if isempty(handles) | ~all(ishandle(handles)) %#ok for Matlab 6 compatibility error('YMA:statusbar:invalidHandle','invalid GUI handle passed to statusbar'); end % Retrieve the requested text string (only process once, for all handles) if isempty(varargin) deleteFlag = (nargout==0); updateFlag = 0; statusText = ''; else deleteFlag = 0; updateFlag = 1; statusText = sprintf(varargin{:}); end % Loop over all unique root handles (figures/desktop) of the supplied handles rootHandles = []; if any(handles) % non-0, i.e. non-desktop try rootHandles = ancestor(handles,'figure'); if iscell(rootHandles), rootHandles = cell2mat(rootHandles); end catch errMsg = 'Matlab version is too old to support figure statusbars'; % Note: old Matlab version didn't have the ID optional arg in warning/error, so I can't use it here if any(handles==0) warning([errMsg, '. Updating the desktop statusbar only.']); %#ok for Matlab 6 compatibility else error(errMsg); end end end rootHandles = unique(rootHandles); if any(handles==0), rootHandles(end+1)=0; end statusbarObjs = handle([]); for rootIdx = 1 : length(rootHandles) if rootHandles(rootIdx) == 0 setDesktopStatus(statusText); else thisStatusbarObj = setFigureStatus(rootHandles(rootIdx), deleteFlag, updateFlag, statusText); if ~isempty(thisStatusbarObj) statusbarObjs(end+1) = thisStatusbarObj; end end end % If statusbarHandles requested if nargout % Return the list of all valid (non-empty) statusbarHandles statusbarHandles = statusbarObjs; end %end % statusbar %#ok for Matlab 6 compatibility %% Set the status bar text of the Matlab desktop function setDesktopStatus(statusText) try % 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 % Schedule a timer to update the status text % Note: can't update immediately, since it will be overridden by Matlab's 'busy' message... try t = timer('Name','statusbarTimer', 'TimerFcn',{@setText,desktop,statusText}, 'StartDelay',0.05, 'ExecutionMode','singleShot'); start(t); catch % Probably an old Matlab version that still doesn't have timer desktop.setStatusText(statusText); end catch %if any(ishandle(hFig)), delete(hFig); end error('YMA:statusbar:desktopError',['error updating desktop status text: ' lasterr]); end %end %#ok for Matlab 6 compatibility %% 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 %end %#ok for Matlab 6 compatibility %% Set the status bar text for a figure function statusbarObj = setFigureStatus(hFig, deleteFlag, updateFlag, statusText) try jFrame = get(hFig,'JavaFrame'); jFigPanel = get(jFrame,'FigurePanelContainer'); jRootPane = jFigPanel.getComponent(0).getRootPane; % If invalid RootPane, retry up to N times tries = 10; while isempty(jRootPane) & tries>0 %#ok for Matlab 6 compatibility - might happen if figure is still undergoing rendering... drawnow; pause(0.001); tries = tries - 1; jRootPane = jFigPanel.getComponent(0).getRootPane; end jRootPane = jRootPane.getTopLevelAncestor; % Get the existing statusbarObj statusbarObj = jRootPane.getStatusBar; % If status-bar deletion was requested if deleteFlag % Non-empty statusbarObj - delete it if ~isempty(statusbarObj) jRootPane.setStatusBarVisible(0); end elseif updateFlag % status-bar update was requested % If no statusbarObj yet, create it if isempty(statusbarObj) statusbarObj = com.mathworks.mwswing.MJStatusBar; jProgressBar = javax.swing.JProgressBar; jProgressBar.setVisible(false); statusbarObj.add(jProgressBar,'West'); % Beware: East also works but doesn't resize automatically jRootPane.setStatusBar(statusbarObj); end statusbarObj.setText(statusText); jRootPane.setStatusBarVisible(1); end statusbarObj = handle(statusbarObj); % Add quick references to the corner grip and status-bar panel area if ~isempty(statusbarObj) addOrUpdateProp(statusbarObj,'CornerGrip', statusbarObj.getParent.getComponent(0)); addOrUpdateProp(statusbarObj,'TextPanel', statusbarObj.getComponent(0)); addOrUpdateProp(statusbarObj,'ProgressBar', statusbarObj.getComponent(1).getComponent(0)); end catch try title = jFrame.fFigureClient.getWindow.getTitle; catch title = get(hFig,'Name'); end error('YMA:statusbar:figureError',['error updating status text for figure ' title ': ' lasterr]); end %end %#ok for Matlab 6 compatibility %% Utility function: add a new property to a handle and update its value function addOrUpdateProp(handle,propName,propValue) try if ~isprop(handle,propName) schema.prop(handle,propName,'mxArray'); end set(handle,propName,propValue); catch exception % never mind... end %end %#ok for Matlab 6 compatibility