我正在尝试在MATLAB(R2009a)UI中实现保存/加载功能。我的对象实现了一个为该对象生成用户界面的布局函数。我正在尝试实现保存/加载按钮的回调。保存按钮工作并将对象保存到MAT文件中,以后可以加载。
我的问题是实现加载按钮的回调。我似乎无法从MAT文件加载数据并更新新对象的属性。关于我哪里出错的任何建议以及关于我如何进行的建议都非常感谢。
重要的代码是我的类定义文件,当然我的实际对象实现了更多的属性和方法,但这里是我所拥有的骨架
classdef myObj<handle
properties
image % property holds a matlab image matrix
objCount % number of objects in image
end
properties(Transient=true)
parent
children
end
methods
function myObj
% empty constructor
end
function load_object(self)
% ask user for file
[fileName, pathToFile]=uigetfile('*.mat','Select .mat file');
tmp = load(fullfile(pathToFile,fileName);
if isfield(tmp,'obj')
self = tmp.obj;
end
end
LayoutFcn(self) % UI layout function
end
end
UI布局在单独的文件 LayoutFcn.m 中定义,基本上看起来像
function LayoutFcn(self)
% create figure window and add various UI elements
...
% create load button
self.children(end+1) = uipushtool('Parent',hToolbar, ... % set parent to current toolbar
'CData',iconRead('open-document.png'), ... % read icon image from file
'Tag','uiLoad', ...
'ClickedCallback',@(hObj,event)loadingMyObject(self,hObj,event));
% create save button
self.children(end+1) = uipushtool('Parent',hToolbar, ... % set parent to current toolbar
'CData',iconRead('save-document.png'), ... % read icon image from file
'Tag','uiSave', ...
'ClickedCallback',@(hObj,event)savingMyObject(self,hObj,event));
...
end
function loadingMyObject(self,hObj,event)
self.load_object; % call load_object method defined above in class definition
end
function savingMyObject(self,hObj,event)
[fileName,pathName]=uiputfile('.mat','Save object to MAT file');
obj = self;
save(fullfile(pahtName,fileName),'obj')
end
注意:我正在使用MATLAB R2009a。
代码不会抛出任何错误。我在编写代码时,父对象(由 self 表示)在方法 load_object 中调用 LOAD 后不会更新。所以,这有预期的效果:
>> var = myObj;
>> var.load_object;
但是,如果我以这种方式使用 LayoutFcn.m 中定义的 loadingMyObject 回调
>> var = myObjl
>> var.LayoutFcn
-> click Load button to call _loadingMyObject_
不会影响 var 属性。单击“加载”按钮后, var 仍将具有其默认属性值。
答案 0 :(得分:1)
不要为自己分配值。所做的只是在方法调用的范围内替换绑定到自变量。它不会调用魔法复制构造函数来替换调用者中的对象引用。而是将字段复制到self中。尝试类似:
if isfield(tmp,'obj')
self.image = tmp.obj.image;
self.objCount = tmp.obj.objCount;
end
答案 1 :(得分:1)
我相信Mr Fooz是对的。传递给load_object的自变量是“myObj”类型的对象,但行:
self = tmp.obj;
只是用tmp.obj中存储的结构覆盖自变量。这样做的:
self.image = tmp.obj.image;
应该为object self的image属性调用set运算符。在MATLAB文档中,有一个sample class definition,其中有一个名为“set.OfficeNumber”的方法,用于说明这一点。
此外,函数savingMyObject中的以下行可能是不必要的:
obj = self;
如果您在类代码中使用名称“obj”代替单词“self”,我认为它可能最有意义(并使代码更清晰)(正如文档所倾向的那样)。 “self”似乎不是MATLAB中的任何特殊关键字(就像它可能在其他语言中一样)。据我所知,这只是另一个变量。 =)
编辑#1:
如果必须在load_object方法中单独设置每个属性的前景听起来不是很有趣,那么解决它的方法就是如果你的对象的SET方法设计为SET method for handle graphics。该SET命令可以接受结构输入,其中每个字段名称是属性名称,每个字段值是该属性的新值。然后你会有一个电话,如:
set(self,tmp.obj);
相当短,特别是如果你要设置很多属性。当然,您必须为您的对象编写新的SET方法,但如果它在其他地方也派上用场,那么缩短的语法可能值得额外的工作。 =)
编辑#2:
您可以使用与Mr Fooz块一起使用的循环try/catch:
fn = fieldnames(tmp.obj);
for i = 1:numel(fn),
try
self.(fn{i}) = tmp.obj.(fn{i});
catch
% Throw a warning here, or potentially just do nothing.
end
end
答案 2 :(得分:1)
结合Mr Fooz's和gnovice's建议,我添加了一个具有以下定义的SET函数
function set(self,varargin)
if isa(varargin{1},'FujiCalibration')
tmp = varargin{1};
fns = fieldnames(self);
for i = 1:length(fns)
if strcmpi(fns{i}(1:2),'p_')
self.(fns{i}) = tmp.(fns{i});
end
end
self.calibImage = tmp.calibImage;
else
proplist=fields(self);
for n=1:2:length(varargin)
tmp = proplist(strcmpi(proplist,varargin{n}));
value = varargin{n+1};
switch length(tmp)
case 0
msg = char(strcat('There is no ''', varargin{n}, '''property'));
error('FujiCalibration:setPropertyChk',msg)
case 1
tmp = char(tmp);
self.(tmp) = value;
end
end
end
end
然后,我按照gnovice的建议修改了 load_object 方法,方法是更改
self = tmp.obj
到
set(self,tmp.obj).
我需要确保具有我想要保留的值的属性以“p_”为前缀。
感谢gnovice和Fooz先生的回答。