Implementing an hgsetget subclass

1 view (last 30 days)
I would like to create a subclass of hgsetget that would show this kind of behavior:
>>u=unit('SI');
>>set(u) % set behavior 1
System: '[{SI} | cgs]'
>>set(u,'System') % set behavior 2
[{SI} | cgs]
>>set(u,'System','cgs') % set behavior 3
>>get(u,'System')
ans =
cgs
In other words, much like the behavior you see for a figure handle. Following the example in Implementing a Set/Get Interface for Properties, I tried this code:
classdef unit < hgsetget
properties
System = '';
end
methods
function H = unit(str)
if nargin > 0
H.System = str;
end
end
function H = set.System(H,str)
H.System = str;
end
end
end
This gets set behavior 3 right, but how do I add the other two? The closest I have come so far is to simply program all the cases into an overloaded set method, and get rid of set.System. But if I add a few more properties, this gets quite ugly. Does anyone know an elegant way of doing this?

Accepted Answer

Andrew Newell
Andrew Newell on 25 Feb 2011
O.k., this works:
classdef unit < hgsetget
% This is just a test class for using SET in an HGSETGET subclass.
properties
System = '';
end
methods
function H = unit(str)
if nargin > 0
H.System = str;
end
end
function varargout = set(H,varargin)
S = struct('System','[{SI} | cgs]');
switch nargin
case 1
if nargout < 1
disp(S)
else
varargout{1} = S;
end
case 2
if nargout < 1
disp(S.System)
else
varargout{1} = S.System;
end
case 3
H.System = varargin{2};
otherwise
error('unit:wrongNumberOfArguments', ...
'Wrong number of arguments to SET command.')
end% switch
end% set
end% methods
end% classdef
But I still wonder - is there an implementation that involves a function SET.SYSTEM?

More Answers (3)

Jiro Doke
Jiro Doke on 26 Feb 2011
This is interesting. It does seem like the documentation isn't complete. It mentions how calling the set with a particular syntax returns the possible values of a property, but it doesn't explain how to specify those possible values.
Here's something that I put together to try to achieve what you want, while making it somewhat extensible to multiple properties:
classdef MyClass < hgsetget
properties
Prop1
Prop2
end
properties (Hidden, Constant)
Prop1_values = {'SI', 'cgs'}
Prop2_values = {'C', 'F'}
end
methods
function varargout = set(obj, varargin)
% Allow only one output and no more than 3 input arguments
error(nargoutchk(0, 1, nargout, 'struct'));
error(nargchk(1, 3, nargin, 'struct'));
switch nargin
case 1 % set(h) syntax
propnames = properties(obj);
if nargout
s = cell2struct(cell(size(propnames)), ...
propnames, 1);
for id = 1:length(propnames)
s.(propnames{id}) = set(obj, propnames{id});
end
varargout{1} = s;
else
for id = 1:length(propnames)
set(obj, propnames{id});
end
end
case 2 % set(h, 'PropertyName') syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
if nargout
varargout{1} = MyClass.([varargin{1}, '_values']);
else
fprintf('%10s: %s\n', varargin{1}, ...
toString(MyClass.([varargin{1}, '_values'])));
end
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
case 3 % set(h, 'PropertyName', value) syntax
allprops = properties(obj);
if ismember(varargin{1}, allprops)
val = validatestring(varargin{2}, ...
MyClass.([varargin{1}, '_values']), ...
mfilename, varargin{1});
obj.(varargin{1}) = val;
else
error('Invalid property "%s" for class "%s".', ...
varargin{1}, class(obj));
end
if nargout
varargout{1} = [];
end
end
end
end
end
function str = toString(in)
in{1} = ['{', in{1}, '}']; % first input is the default
str = sprintf('| %s ', in{:});
str = ['[', str(2:end), ']'];
end
I have Hidden, Constant properties that specify the possible property values, and the set method queries that information. So whenever I create a new property, I create a corresponding Prop#_values property.
EDIT: I've implemented a Setter for the properties. In this example, instead of creating a separate Setter method for each property, I made it as a part of the set method (see case 3 in the switch statement). Since the Prop#_values contain the valid string values, I use that to validate the input.
Test...
>> a = MyClass;
>> set(a)
Prop1: [ {SI} | cgs ]
Prop2: [ {C} | F ]
>> set(a, 'Prop2')
Prop2: [ {C} | F ]
>> set(a, 'Prop1', 'cgs')
>> get(a, 'Prop1')
ans =
cgs
>> set(a, 'Prop2', 'CF')
??? Error using ==> MyClass
Expected Prop2 to match one of these strings:
C, F
The input, 'CF', did not match any of the valid strings.
Error in ==> MyClass>MyClass.set at 46
val = validatestring(varargin{2}, ...
>>
  7 Comments
Jiro Doke
Jiro Doke on 28 Feb 2011
@Andrew: That's great! Would you care to share that on the File Exchange? It seems like there is no simple way of doing it with HGSETGET, so your approach might be the best currently.
Andrew Newell
Andrew Newell on 28 Feb 2011
@Jiro, I intend to do just that. It was a bit of work making SET capable of taking all the different combinations of arguments! I have submitted a new question, though, about making my class abstract.

Sign in to comment.


Andrew Newell
Andrew Newell on 25 Feb 2011
Here is a simple attempt to get the full functionality:
classdef unit < hgsetget
% This is just a test class for using SET in an HGSETGET subclass.
properties
System = '';
end
methods
function H = unit(str)
if nargin > 0
H.System = str;
end
end
function varargout = set(H,varargin)
switch nargin
case 1
varargout = {struct('System',{'SI','cgs'})};
case 2
varargout{1} = '[{SI} | cgs]';
case 3
H.System = varargin{2};
otherwise
error('unit:wrongNumberOfArguments', ...
'Wrong number of arguments to SET command.')
end% switch
end% set
end% methods
end% classdef
However, the behavior is not quite the same:
>> u = unit;
>> set(u)
ans =
1x2 struct array with fields:
System
>> set(u,'System')
ans =
[{SI} | cgs]
>> set(u,'System','cgs') >> get(u,'System')
ans =
cgs

Andrew Newell
Andrew Newell on 10 Mar 2011
I have submitted an extension of hgsetget to the FEX: handleGraphicsSetGet class.

Categories

Find more on Argument Definitions in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!