www.gusucode.com > mbcguitools 工具箱 matlab 源码程序 > mbcguitools/+mbcgui/+container/Dialog.m
classdef Dialog < matlab.mixin.SetGet & matlab.mixin.Copyable %mbcgui.container.Dialog class % mbcgui.container.Dialog properties: % Figure - Property is of type 'MATLAB array' (read only) % Buttons - Property is of type 'string' (read only) % DefaultAction - Property is of type 'string' % HelpCode - Property is of type 'string' (read only) % Owner - Property is of type 'MATLAB array' (read only) % ContentBorder - Property is of type 'MATLAB array' % Content - Property is of type 'MATLAB array' % Enabled - Property is of type 'bool' % PersistPosition - Property is of type 'bool' % Name - Property is of type 'string' % Size - Property is of type 'MATLAB array' % Visible - Property is of type 'on/off' (read only) % Resize - Property is of type 'on/off' % Tag - Property is of type 'string' % InfoTitle - Property is of type 'string' % InfoString - Property is of type 'string' % InfoHeight - Property is of type 'double' % % mbcgui.container.Dialog methods: % addListeners - Convenience method to add listeners to dialog's store. % closeDialog - Close the dialog. % disableButtons - Disables a dialog's buttons. % enableButtons - Enables a dialog's buttons. % resetPointer - Reset the pointer to previous setting. % setPointer - Set the dialog's pointer % showDialog - Show the dialog % Copyright 2007-2015 The MathWorks, Inc. properties (Hidden,Constant) %Tester tester object Tester = mbcgui.container.Tester; end properties (AbortSet, SetObservable) %DEFAULTACTION Property is of type 'string' DefaultAction = ''; %CONTENTBORDER Property is of type 'MATLAB array' ContentBorder = [ 7, 0, 7, 7 ]; %CONTENT Property is of type 'MATLAB array' Content = []; %ENABLED Property is of type 'bool' Enabled = true; %PERSISTPOSITION Property is of type 'bool' PersistPosition = false; %NAME Property is of type 'string' Name = ''; %SIZE Property is of type 'MATLAB array' Size = [ 400, 200 ]; %RESIZE Property is of type 'on/off' Resize %TAG Property is of type 'string' Tag = ''; %INFOTITLE Property is of type 'string' InfoTitle = ''; %INFOSTRING Property is of type 'string' InfoString = ''; %INFOHEIGHT Property is of type 'double' InfoHeight = 30; %ValidationFcn callback to validate dialog before accepting OK ValidationFcn end properties (Access=protected, AbortSet) %BUTTONLAYOUT Property is of type 'MATLAB array' ButtonLayout = []; %CONTENTLAYOUT Property is of type 'MATLAB array' ContentLayout = []; %INFOPANE Property is of type 'MATLAB array' InfoPane = []; %LISTENERS Property is of type 'MATLAB array' Listeners = []; %POINTERID Property is of type 'MATLAB array' PointerID = []; %ACTIONS Property is of type 'MATLAB array' Actions = struct(); %BUTTONHANDLES Property is of type 'MATLAB array' ButtonHandles = []; %CLOSEACTION Property is of type 'string' CloseAction = 'CANCEL'; end properties (SetAccess=protected, AbortSet, SetObservable) %FIGURE Property is of type 'MATLAB array' (read only) Figure = []; %BUTTONS Property is of type 'string' (read only) Buttons = 'OK_CANCEL_HELP'; %HELPCODE Property is of type 'string' (read only) HelpCode = ''; %OWNER Property is of type 'MATLAB array' (read only) Owner = []; %VISIBLE Property is of type 'on/off' (read only) Visible end events DialogShowing end % events methods % constructor block function obj = Dialog( varargin ) %mbcgui.container.Dialog Create a dialog with buttons and space for content. % % Example: % d = mbcgui.container.Dialog( 'Owner', pFig,... % 'Name', dialogTitle,... % 'Size', [200, 300],... % 'Buttons', 'OK_CANCEL_HELP',... % 'DefaultAction', 'OK',... % 'CloseAction', 'CANCEL' ); % % d.Content = iCreateLayout( d.Figure ); % % % Does the waitfor % closeMode = d.showDialog(); % % % The tag is set to either 'OK' or 'CANCEL' % switch closeMode % case 'OK' % ... % case 'CANCEL' % ... % end % % See also mbcgui.container.Dialog.showDialog. % Create the Actions obj.Actions.OK = iMakeAction( obj, @(s,e)obj.closeDialog('OK'), 'OK' ); obj.Actions.CANCEL = iMakeAction( obj, @(s,e)obj.closeDialog('CANCEL'), 'Cancel' ); obj.Actions.CLOSE = iMakeAction( obj, @(s,e)obj.closeDialog('CLOSE'), 'Close' ); obj.Actions.HELP = iMakeAction( obj, @(s,e)iShowHelp( obj ), 'Help' ); obj.Figure = xregdialog(); obj.addListeners( event.listener( obj, 'ObjectBeingDestroyed', @(s,e)iDeleteFigure(obj) ) ); if nargin set( obj, varargin{:} ); end % add a close dialog property mbcgui.hgclassesutil.addprop(obj.Figure, 'CloseMode'); InfoProps = [obj.findprop('InfoTitle'), obj.findprop('InfoString'), obj.findprop('InfoHeight')]; obj.addListeners( event.proplistener(obj, InfoProps, 'PostSet', @iUpdateInfo)); % Initialise dialog location here, before any contents are created. This % prevents a bug - ActiveX controls not appearing obj.pSetDialogLocation; end % dialog end % constructor block methods function set.CloseAction(obj,value) obj.CloseAction = iCheckActionName(value,'CloseAction'); end function set.Buttons(obj,value) validOptions = {'OK_CANCEL_HELP', 'OK_CANCEL', 'OK_HELP', 'CANCEL_HELP', 'CLOSE', 'CANCEL', 'OK'}; if ~any( ismember( validOptions, value ) ) error(message('mbc:xregGui:dialog:InvalidProperty1', 'Buttons', iMakeList( validOptions ))); end obj.Buttons = value; end function set.DefaultAction(obj,value) obj.DefaultAction = iCheckActionName(value,'DefaultAction'); end function value = get.Name(obj) fGet = @(obj,value)getFigureProperty(obj,value,'Name'); value = fGet(obj,obj.Name); end function set.Name(obj,value) fSet = @(obj,value)setFigureProperty(obj,value,'Name'); obj.Name = fSet(obj,value); end function value = get.Visible(obj) fGet = @(obj,value)getFigureProperty(obj,value,'Visible'); value = fGet(obj,obj.Visible); end function value = get.Resize(obj) fGet = @(obj,value)getFigureProperty(obj,value,'Resize'); value = fGet(obj,obj.Resize); end function set.Resize(obj,value) fSet = @(obj,value)setFigureProperty(obj,value,'Resize'); obj.Resize = fSet(obj,value); end function value = get.Tag(obj) fGet = @(obj,value)getFigureProperty(obj,value,'Tag'); value = fGet(obj,obj.Tag); end function set.Tag(obj,value) fSet = @(obj,value)setFigureProperty(obj,value,'Tag'); obj.Tag = fSet(obj,value); end end % set and get functions methods % public methods %---------------------------------------- function addListeners(obj, L) %ADDLISTENERS Convenience method to add listeners to dialog's store. % ADDLISTENERS(OBJ, L) adds the listener vector L to the list of listeners % being held in the component. obj.Listeners = [obj.Listeners; L(:)]; end % addListeners %---------------------------------------- function closeDialog(obj, mode) %CLOSEDIALOG Close the dialog. % CLOSEDIALOG(OBJ, MODE) closes the dialog. The dialog's CloseMode is set % to MODE. % % MODE is 'OK', 'CANCEL' or 'CLOSE' depending on how the dialog is % closed. % % See also mbcgui.container.Dialog.showDialog. if strcmp(mode,'OK') && ~isempty(obj.ValidationFcn) % use validation function to check if dialog is OK before % clicking OK ptr = obj.Figure.Pointer; obj.Figure.Pointer = 'watch'; drawnow update OK = obj.ValidationFcn(); obj.Figure.Pointer = ptr; if ~OK return end end set(obj.Figure,'CloseMode', mode ); obj.Figure.Visible = 'off'; end % closeDialog %---------------------------------------- function disableButtons(obj, varargin) %DISABLEBUTTONS Disables a dialog's buttons. % DISABLEBUTTONS(OBJ) disables all the dialog's buttons. % DISABLEBUTTONS(OBJ, Name1,Name2) disables the buttons called NAMES. NAMES is % a string, or a cell string. % % See also mbcgui.container.Dialog.enableButtons. actionsToDisable = obj.pGetActions( varargin ); set( actionsToDisable, 'Enabled', false ); end % disableButtons %---------------------------------------- function enableButtons(obj, varargin) %ENABLEBUTTONS Enables a dialog's buttons. % ENABLEBUTTONS(OBJ) enables all the dialog's buttons. % ENABLEBUTTONS(OBJ, Name1,Name2 ) enables the buttons called NAMES. NAMES is % a string, % % See also mbcgui.container.Dialog.disableButtons. actionsToDisable = obj.pGetActions( varargin ); set( actionsToDisable, 'Enabled', true ); end % enableButtons %---------------------------------------- function resetPointer(obj) %RESETPOINTER Reset the pointer to previous setting. % RESETPOINTER(OBJ) % % See also mbcgui.container.Dialog.setPointer. PR = xregGui.PointerRepository; PR.stackRemovePointer( obj.Figure, obj.PointerID(end) ); obj.PointerID(end) = []; drawnow('expose'); end % resetPointer %---------------------------------------- function setPointer(obj, pointer) %SETPOINTER Set the dialog's pointer % % SETPOINTER(OBJ, POINTER). % % See also mbcgui.container.Dialog.resetPointer. PR = xregGui.PointerRepository; obj.PointerID(end+1) = PR.stackSetPointer( obj.Figure, pointer ); drawnow('expose'); end % setPointer %---------------------------------------- function status = showDialog(obj) %SHOWDIALOG Show the dialog % % STATUS = SHOWDIALOG(OBJ) opens the dialog and blocks execution until it % is closed or until OK or Cancel is pressed. % % Immediately after the dialog is made visible but before it code % execution is blocked, the 'DialogShowing' event is sent. If you want % to execute code after the dialog is visible then you can use a listener % on this event. % % See also mbcgui.container.Dialog.closeDialog. % Make sure the figure is in the correct position. % Do this first so the everything else gets the final figure size. obj.pSetDialogLocation(); % We actually make everything here. obj.pLayout(); % Add a figure key action to implement Esc capturing. obj.Figure.WindowKeyReleaseFcn = @i_catchEsc; % Add a highlighter for the default action. This also takes care of % handling Enter presses DefaultActionButton = obj.ButtonHandles.(obj.DefaultAction); obj.Figure.setDefaultButton(DefaultActionButton); % Set the CloseRequestFcn. obj.Figure.CloseRequestFcn = {@iFigureCloseRequest, obj.Actions.(obj.CloseAction) }; % And make it visible. obj.Figure.CloseMode = ''; obj.Figure.Visible = 'on'; % Send an event to allow dialog creators to execute custom code after the % dialog is made visible obj.notify('DialogShowing'); TESTMODE = obj.Tester.Mode; if ~TESTMODE waitfor(obj.Figure, 'Visible'); elseif TESTMODE callback = obj.Tester.ShowDialogCallback; if ~isempty(callback) xregcallback( callback, obj.Figure, DefaultActionButton ); else obj.Figure.CloseMode = obj.CloseAction; end end % Return the CloseMode status = obj.Figure.CloseMode; % And hide the figure. obj.Figure.Visible = 'off'; end % showDialog end % public methods methods (Hidden) % possibly private or hidden %---------------------------------------- function buttons = pCreateButtons(obj) %PCREATEBUTTONS Private method to create the Buttons. % % BUTTONS = PCREATEBUTTONS(OBJ) Creates the buttons specified but the % Buttons property and returns a cell array of button handles in the % order they should be laid out (left to right). Also sets the dialog % CloseAction, again based on the Buttons property. % Here we translate the 'enumerated' Buttons [property to the names of the % actions we need buttons for. The order of the names is the order the % buttons will be in. switch obj.Buttons case 'OK_CANCEL_HELP' actionNames = {'OK', 'CANCEL', 'HELP'}; obj.CloseAction = 'CANCEL'; defaultAction = 'OK'; case 'OK_CANCEL' actionNames = {'OK', 'CANCEL'}; obj.CloseAction = 'CANCEL'; defaultAction = 'OK'; case 'OK_HELP' actionNames = {'OK', 'HELP'}; obj.CloseAction = 'OK'; defaultAction = 'OK'; case 'CANCEL_HELP' actionNames = {'CANCEL', 'HELP'}; obj.CloseAction = 'CANCEL'; defaultAction = 'CANCEL'; case 'CANCEL' actionNames = {'CANCEL'}; obj.CloseAction = 'CANCEL'; defaultAction = 'CANCEL'; case 'CLOSE' actionNames = {'CLOSE'}; obj.CloseAction = 'CLOSE'; defaultAction = 'CLOSE'; case 'OK' actionNames = {'OK'}; obj.CloseAction = 'OK'; defaultAction = 'OK'; otherwise % We should never get here - the check on the property set should % have errored if the value is invalid. error(message('mbc:xregGui:dialog:InvalidOption', obj.Buttons)); end % If no DefaultAction has been specified use the calculated default. if isempty( obj.DefaultAction ) obj.DefaultAction = defaultAction; else % check the user provided DefaultAction is one of the actions we have a % button for. if ~ismember( obj.DefaultAction, actionNames ) error(message('mbc:xregGui:dialog:InvalidProperty', obj.DefaultAction, obj.Buttons)); end end numButtons = length(actionNames); buttons = cell(1, numButtons); for i=1:numButtons name = actionNames{i}; buttons{i} = obj.Actions.(name).createButton( obj.Figure ); % set tag buttons{i}.Tag = name; obj.ButtonHandles.(name) = buttons{i}; end end % pCreateButtons %---------------------------------------- function actions = pGetActions(obj, names) %PGETACTIONS Private method to get the actions from the dialog. % % ACTIONS = PGETACTIONS(OBJ, NAMES) if nargin==1 actions = struct2cell( obj.Actions ); else if ischar( names ) names = {names}; end actions = cellfun( @(n)obj.Actions.(n), names, 'UniformOutput', false ); end actions = [actions{:}]; end % pGetActions %---------------------------------------- function pLayout(obj) %PLAYOUT Private method to layout the dialog. % % PLAYOUT(OBJ) if isempty(obj.ContentLayout) % Create a layout that applies the content border obj.ContentLayout = xreglayerlayout( obj.Figure,... 'PackStatus', 'off'); end set(obj.ContentLayout,... 'Elements', {obj.Content},... 'Border', obj.ContentBorder ); % Create the appropriate buttons buttons = obj.pCreateButtons(); numBtns = length( buttons ); % Delete any existing buttons and the layout they are in if ~isempty(obj.ButtonLayout) % Detach the content layout from the existing grid. old_elements = get(obj.ButtonLayout, 'Elements'); old_elements{1} = []; set(obj.ButtonLayout, 'Elements', old_elements); delete(obj.ButtonLayout); end % Create a layout that adds the buttons elements = [{obj.ContentLayout}, repmat( {[]}, 1, numBtns+2 );... {[]}, {[]} buttons(:)', {[]} ]; obj.ButtonLayout = xreggridbaglayout( obj.Figure,... 'PackStatus', 'off',... 'Dimension', [2 numBtns+3],... 'RowSizes', [-1 25],... 'ColSizes',[0 -1 repmat( 65, 1, numBtns ), 0],... 'Gapx',7,... 'Gapy', 7,... 'Border',[0 7 0 0],... 'mergeblock', {[1 1],[1 numBtns+3]},... 'Elements', elements); TopLayout = obj.ButtonLayout; % Create a layout for the dialog information only if it is required HasInfo = ~isempty(obj.InfoTitle) || ~isempty(obj.InfoString); if HasInfo && isempty(obj.InfoPane) obj.InfoPane = mbcgui.container.InfoPane(... 'Parent', obj.Figure, ... 'Visible', 'off'); end if ~isempty(obj.InfoPane) set(obj.InfoPane, 'Title', obj.InfoTitle, ... 'InfoString', obj.InfoString, ... 'InfoHeight', obj.InfoHeight); end % In order to make sure the info pane repacks at the right time we need to % make the figure's packstatus is on here. set( obj.ButtonLayout, 'PackStatus', 'on'); if HasInfo % Use the InfoPane as the figure's main layout set(obj.InfoPane, 'Center', TopLayout, 'Visible', 'on'); TopLayout = obj.InfoPane; else set(obj.InfoPane, 'Center', [], 'Visible', 'off'); end obj.Figure.LayoutManager = []; obj.Figure.LayoutManager = TopLayout; set(obj.ButtonLayout, 'Visible', 'on' ); end % pLayout %---------------------------------------- function pSetDialogLocation(obj) %PSETDIALOGLOCATION Private method to set the dialog's location. % % PSETDIALOGLOCATION(OBJ) if ~isempty( obj.Figure ) % Work out the default position we want to use scr=get(0,'ScreenSize'); if ~isempty( obj.Owner ) figpos=get(obj.Owner,'Position'); defpos=[figpos(1:2)+(figpos(3:4)-obj.Size)./2 obj.Size]; else defpos=[(scr(3:4)-obj.Size)./2 obj.Size]; end % Set position if obj.PersistPosition xregpersistfigpos( obj.Figure, 'DefaultPos', defpos ); else set(obj.Figure, 'Position', defpos); end % Move figure to be entirely on screen xregmoveonscreen( obj.Figure ); end end % pSetDialogLocation %---------------------------------------- function pUpdateInfo(obj, InfoProp) %PUPDATEINFO Private method to update the dialog information. % % PUPDATEINFO(OBJ, PROP) is called when dialog information properties are % altered. % New information is only set if the infopane has been created. If no % information was set when the dialog is shown, setting information will % not cause it to appear. This is deliberate behaviour and prevents % dialogs that rearrange their contents in disconcerting ways. if ~isempty(obj.InfoPane) InfoPaneProp = InfoProp; % Convert this object's InfoTitle property to Title for the infopane InfoPaneProp = regexprep(InfoPaneProp, '^InfoTitle$', 'Title'); obj.InfoPane.(InfoPaneProp) = obj.(InfoProp); end end % pUpdateInfo end % possibly private or hidden end % classdef function value = setFigureProperty( obj, value, property ) if ~isempty( obj.Figure ) obj.Figure.(property) = value; end end % setFigureProperty function value = getFigureProperty( obj, value, property ) if ~isempty( obj.Figure ) value = obj.Figure.(property); end end % getFigureProperty function value = iCheckActionName( value, propertyName ) validOptions = {'OK', 'CANCEL', 'CLOSE', 'HELP'}; if ~any( ismember( validOptions, value ) ) error(message('mbc:xregGui:dialog:InvalidProperty2', propertyName, iMakeList( validOptions ))); end end % iCheckActionName function validList = iMakeList( validOptions ) validList = sprintf( '%s, ', validOptions{1:end-1} ); validList = sprintf( '%s or %s', validList(1:end-2), validOptions{end} ); end % iMakeList function action = iMakeAction( dialog, callback, name ) action = mbcgui.container.DialogAction( callback, name ); action.Dialog = dialog; end % iMakeAction function iDeleteFigure( obj ) if isgraphics( obj.Figure ) delete(obj.Figure) end end % iDeleteFigure function iShowHelp( obj ) mv_helptool( obj.HelpCode, obj.Figure ); end % iShowHelp function iUpdateInfo(src, evt) obj = evt.AffectedObject; PropName = src.Name; pUpdateInfo(obj, PropName); end % iUpdateInfo function i_catchEsc(src, ~) if get(src, 'CurrentCharacter')==27 close(src); end end % i_catchEsc function iFigureCloseRequest( ~, ~, closeAction ) closeAction.execute(); end % iFigureCloseRequest