www.gusucode.com > mbcguitools 工具箱 matlab 源码程序 > mbcguitools/+mbcgui/+widget/Spinner.m

    classdef Spinner < mbcgui.widget.BasicContainer
%SPINNER Spinner editor component
%   mbcgui.widget.Spinner is a numeric scalar editor component that
%   presents the value to be altered in an edit box alongside arrow buttons
%   that increment and decrement the value.  Default rules are provided for
%   limiting the value to a given range, integer values, prime numbers or a
%   predefined list of values.
%
%   Spinner properties:
%      CData          - N-by-M-by-3 array of uint8 values that represent an
%                       image.  Each page of the array contains the red,
%                       green and blue values respectively.  When the CData
%                       property is set, the ImageFile property is cleared.
%      ImageFile      - Name of an image file to load.  When the ImageFile
%                       property is set, the CData property is cleared.
%      TooltipString  - String to display as a tooltip for the icon.
%
%   See also BasicContainer, Component.

%   Copyright 2009-2013 The MathWorks, Inc.

properties(SetObservable, AbortSet, Dependent)
    %VALUE Value to display in the spinner
    %   The Value property contains a scalar double value that the spinner
    %   is currently editing.
    %
    %   See also Rule, Min, Max, Callback.
    Value = 0;
end

properties(SetObservable, AbortSet)    
    %RULE Input validation rule to apply
    %   The Rule property controls the validation behaviour of the spinner.
    %   It may be set to one of the following strings:
    %
    %   real     - The value can be any number between the Min and Max
    %              property values.
    %   int      - The value can be any integer between the Min and Max
    %              property values.
    %   list     - The value can be any number that is contained in the
    %              vector of values in the List property
    %   prime    - The value can be any prime number between the Min and
    %              Max property values.
    %
    %   See also Value, Min, Max, List.
    Rule = 'real';
    
    %MIN Minimum value for spinner
    %   The Min property sets a lower bound on the value allowed in the
    %   spinner.  This applies when the Rule is set to real, int or prime.
    %
    %   See also Max, Value.
    Min = -inf;
    
    %MAX Maximum value for spinner
    %   The Max property sets an upper bound on the value allowed in the
    %   spinner.  This applies when the Rule is set to real, int or prime.
    %
    %   See also Min, Value.
    Max = inf;
    
    %LIST List of allowed spinner values
    %   The List property specifies the set of allowed values when the
    %   spinner Rule is set to 'list'.
    %
    %   See also Rule, Value.
    List = [];
end

properties(AbortSet)
    %CLICKINCREMENTMODE Method of incrementing and decrementing
    %   The ClickIncrementMode controls how values are increased and
    %   decreased when the Rule property is set to int or real and an arrow
    %   button is pressed.  This property must be set to one of the
    %   following strings:
    %
    %   'linear'   - (Default) The value is increased or decreased by the 
    %                value of the ClickIncrement property, i.e. Value ->
    %                Value +/- ClickIncrement.
    %                
    %   'log'      - The value is multiplied or divided but the value of
    %                the ClickIncrement property, i.e. Value -> Value *//
    %                ClickIncrement.
    %   'auto'     - The value is changed in a linear fashion but the
    %                increment size is automatically chosen.  In general,
    %                the increment will scale with the order of magnitude
    %                of the value.
    %
    %   See also: ClickIncrement, Rule, Value.
    ClickIncrementMode = 'linear';
    
    
    %CLICKINCREMENT Magnitude of increment and decrement
    %   The ClickIncrement property contains the value that is used to
    %   increase or decrease the value when an arrow button is pressed.
    %   This must be set to a scalar numeric value.   See the help for
    %   ClickIncrementMode for more details on how this value is used.
    %
    %   See also: ClickIncrementMode, Rule, Value.
    ClickIncrement = 1;
    
    %FONTWEIGHT Set font weight for the Spinner.
    %  The FontWeight property allows you to set the text in the edit box
    %  to be either 'normal' or 'bold'.
    FontWeight = 'normal';
    
    %TOOLTIPSTRING Tooltip to display over the icon
    %   Setting the TooltipString will cause the specified string to be
    %   displayed when the use hovers their mouse over the icon.
    TooltipString = '';
    
    %CALLBACK Function to execute when the value is changed
    %   The Callback property can be set to any standard callback array and
    %   will be called when the ValueEdited event is fired.
    %  
    %   See also ValueEdited.
    Callback = [];
end

properties(AbortSet, Dependent)
    %UIContextMenu Handle to a uicontextmenu object
    %   The UIContextMenu property allows you to set a context menu that
    %   will appear when a Spinner is right-clicked.
    UIContextMenu
end
    
properties(Access='private')
    % Value that backs the dependent Value property.  Having a separate
    % backing store gives us the option of value access without going
    % through get.Value.
    LocalValue = 0;
    
    % Flag that indicates whether the current value came from the user and
    % is hence not validated, or whether it came from the java peer and
    % hence has had the rules applied.
    LocalValueValidated = true;

    % Flag that signals the set.Value code not to pass on a new value to
    % the java peer.
    AllowPrivateValueSet = false;
    
    % Listener that executes the Callback property
    CallbackListener = [];
end

events
    ValueEdited
end


methods
    function obj = Spinner(varargin)
    %SPINNER Construct a new Spinner object
    %   H = mbcgui.widget.Spinner(PROP, VAL, ...) constructs a new Spinner
    %   object with its properties set to the values specified by the input
    %   list of property-value pairs.

    obj@mbcgui.widget.BasicContainer(varargin{:});

    P = com.mathworks.toolbox.mbc.gui.peer.SpinnerPeer;
    obj.ContentHandle = mbcwidgets.javacomponent(P, ...
        'Parent', obj.Parent, ...
        'Enable', obj.Enable, ...
        'Visible', obj.Visible, ...
        'Position', obj.Position);
    P.setTooltipText(obj.TooltipString);
    obj.createSpinnerModel;
    P.setStepMode(upper(obj.ClickIncrementMode));
    P.setStepSize(obj.ClickIncrement);
    obj.updateFontWeight;
    
    cb =handle(obj.ContentHandle.Peer.getValueCallback);
    L = handle.listener(cb, 'delayed', {@iValueChange, obj});
    obj.storeListeners(L);
    end



    function set.TooltipString(obj, tt)
        if obj.isConstructed
            obj.ContentHandle.Peer.setTooltipText(tt);
        end
        obj.TooltipString = tt;
    end
    
    
    function set.Value(obj, val)
        if ~isscalar(val) || ~isnumeric(val)
            error(message('mbc:widget:Spinner:InvalidPropertyValue'));  
        end
        
        if ~obj.AllowPrivateValueSet && obj.isConstructed
            % Push the value to the java peer
            switch obj.Rule
                case 'int'
                    obj.ContentHandle.Peer.setLongValue(val);
                case 'prime'
                    obj.ContentHandle.Peer.setPrimeValue(val);
                otherwise
                    obj.ContentHandle.Peer.setDblValue(val);
            end
        end
        
        % Store the value but mark it as not validated.
        obj.LocalValue = val;
        obj.LocalValueValidated = false;
    end
    
    function val = get.Value(obj)
        if obj.LocalValueValidated ...
                || ~obj.isConstructed ...
                || ~obj.ContentHandle.Peer.isComponentConstructed
            val = obj.LocalValue;
        else
            % Get value from java
            val = javaMethodEDT('getValue', obj.ContentHandle.Peer.getSpinner);
        end
    end
    
    
    function set.Rule(obj, rule)
        if ~any(strcmp(rule, {'real', 'int', 'list', 'prime'}));
            error(message('mbc:widget:Spinner:InvalidPropertyValue1'));   
        end
        obj.Rule = rule;
        obj.LocalValueValidated = false;
        obj.createSpinnerModel;
    end
    
    
    function set.Min(obj, val)
        if ~isscalar(val) || ~isnumeric(val)
            error(message('mbc:widget:Spinner:InvalidPropertyValue2'));  
        end
        obj.Min = val;
        obj.LocalValueValidated = false;
        obj.updateRange;
    end
    
    
    function set.Max(obj, val)
        if ~isscalar(val) || ~isnumeric(val)
            error(message('mbc:widget:Spinner:InvalidPropertyValue3'));  
        end
        obj.Max = val;
        obj.LocalValueValidated = false;
        obj.updateRange;
    end
    
    
    function set.List(obj, val)
        if ~isvector(val) || ~isnumeric(val)
            error(message('mbc:widget:Spinner:InvalidPropertyValue4'));  
        end
        obj.List = val;
        obj.LocalValueValidated = false;
        if obj.isConstructed
            obj.ContentHandle.Peer.setList(val);
        end
    end
    
    
    function set.ClickIncrementMode(obj, val)
        if ~any(strcmp(val, {'linear', 'log', 'auto'}));
            error(message('mbc:widget:Spinner:InvalidPropertyValue5'));   
        end
        obj.ClickIncrementMode = val;
        if obj.isConstructed
            obj.ContentHandle.Peer.setStepMode(upper(val));
        end
    end
    
    
    function set.ClickIncrement(obj, val)
        if ~isscalar(val) || ~isnumeric(val)
            error(message('mbc:widget:Spinner:InvalidPropertyValue6'));  
        end
        obj.ClickIncrement = val;
        if obj.isConstructed
            obj.ContentHandle.Peer.setStepSize(val);
        end
    end
    
    
    function set.UIContextMenu(obj, val)
        if ~isempty(val) && (~isscalar(val) || ~isgraphics(val, 'uicontextmenu'))
            error(message('mbc:widget:Spinner:InvalidPropertyValue7'));
        end
        obj.ContentHandle.UIContextMenu = val;
    end
    
    function val = get.UIContextMenu(obj)
        val =obj.ContentHandle.UIContextMenu;
    end
    
    
    function set.FontWeight(obj, val)
        if ~any(strcmp(val, {'normal', 'bold'}));
            error(message('mbc:widget:Spinner:InvalidPropertyValue8'));   
        end
        obj.FontWeight = val;
        obj.updateFontWeight;
    end
    
    
    function set.Callback(obj, val)
        if isempty(val)
            obj.CallbackListener = [];
        else
            obj.CallbackListener = event.listener(obj, 'ValueEdited', ...
                mbcutils.callback(@iCallBack, val));
        end
        obj.Callback = val;
    end 
    
    
    function increment(obj, N)
    %INCREMENT Increment the spinner by a single step
    %    INCREMENT(OBJ) sets the spinner's value to that which would be
    %    produced if the user clicked a single time on the "up" arrow
    %    button.
    %
    %    INCREMENT(OBJ, NUM) increments the spinner NUM times.
    if nargin<2
        N = 1;
    end
    obj.ContentHandle.Peer.increment(N);
    obj.LocalValueValidated = false;
    end
    
    function decrement(obj, N)
    %DECREMENT Decrement the spinner by a single step
    %    DECREMENT(OBJ) sets the spinner's value to that which would be
    %    produced if the user clicked a single time on the "down" arrow
    %    button.  
    %
    %    DECREMENT(OBJ, NUM) decrements the spinner NUM times.
    if nargin<2
        N = 1;
    end
    obj.ContentHandle.Peer.decrement(N);
    obj.LocalValueValidated = false;
    end
end

methods(Hidden)
    % Debug helper method
    function P = getPeer(obj) 
        P = obj.ContentHandle.Peer;
    end
end


methods(Access=protected) 
    function setEnable(obj, En)
        % If the enable setting is 'inactive' we interpret this as 'off'. The
        % Java peer does not support 'inactive'.
        if strcmp(En, 'inactive')
            En = 'off';
        end
        obj.setEnable@mbcgui.widget.BasicContainer(En);
    end
end

methods(Access=private)
    function createSpinnerModel(obj)
        if obj.isConstructed
            % Use the LocalValue cache - it does not matter if it is not
            % validated because the construction of a new model will do the
            % validation anyway.
            
            switch(obj.Rule)
                case 'real'
                    obj.ContentHandle.Peer.createRealModel(obj.LocalValue, obj.Min, obj.Max);
                case 'int'
                    obj.ContentHandle.Peer.createIntModel(obj.LocalValue, obj.Min, obj.Max);
                case 'list'
                    obj.ContentHandle.Peer.createListModel(obj.LocalValue, obj.List);
                case 'prime'
                    obj.ContentHandle.Peer.createPrimeModel(obj.LocalValue, obj.Min, obj.Max);
                otherwise
                    error(message('mbc:widget:Spinner:InvalidPropertyValue9'));        
            end
        end
        
    end
    
    
    function updateRange(obj)
        if obj.isConstructed
            switch(obj.Rule)
                case 'real'
                    obj.ContentHandle.Peer.setDblRange(obj.Min, obj.Max);
                case 'int'
                    obj.ContentHandle.Peer.setLongRange(obj.Min, obj.Max);
                case 'prime'
                    obj.ContentHandle.Peer.setPrimeRange(obj.Min, obj.Max);
                otherwise
                    % Range is not used by the list mode
            end
        end
    end    
    
    
    function updateFontWeight(obj)
        if obj.isConstructed
            if strcmpi(obj.FontWeight, 'bold')
                W = java.awt.Font.BOLD;
            else
                W = java.awt.Font.PLAIN;
            end
            obj.ContentHandle.Peer.setFontStyle(W);
        end
    end
    
    
    function updateValue(obj, val, isUserEdit)
        % Update the Value property with a new validated value.  This goes
        % through the public Value interface to ensure a property change
        % event is sent. 
        
        % First validate the previous value so that get.Value does not go
        % to java.
        obj.LocalValueValidated = true;
        
        % Now set the value but do not push it back to the java peer.
        obj.AllowPrivateValueSet = true;
        obj.Value = val;
        obj.AllowPrivateValueSet = false;
        
        % Now re-mark the value as validated.
        obj.LocalValueValidated = true;
        
        % Fire a value edit event if the event actually came from a user
        % input action.  Even though the value may not appear to have
        % changed, this often happens after a succession of non-input
        % events that *have* changed the value.
        if isUserEdit
            notify(obj, 'ValueEdited');
        end
    end
end

end


% Callback from the java peer
function iValueChange(~, evt, obj)
    obj.updateValue(evt.JavaEvent.getValue, ...
        evt.JavaEvent.isUserGenerated && ~evt.JavaEvent.isValueChanging)
end

function iCallBack(src, ~, callback)
    xregcallback(callback, src, []);
end