难以尝试在MATLAB UI中实现保存/加载对象功能

时间:2009-03-18 22:46:12

标签: matlab matlab-load

我正在尝试在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 仍将具有其默认属性值。

  1. 按照gnovice的建议更改加载方法以使用 set 会引发以下错误

      

    ???使用==&gt;时出错组   无法从FujiCalibration转换为加倍。

    即使我为每个属性设置/获取方法;如在

    method set.image(self,II)
       % ... some data validation code ...
       self.image = II
    end
    
  2. 使用循环来设置Mr Fooz建议的每个字段实际上不是一个选项,因为我的完整类具有公共常量,在设置时会抛出错误。

  3. 我正在寻找一种解决方案,可以避免我必须单独设置每个字段的代码。虽然在这一点上它似乎是唯一的可能性。

3 个答案:

答案 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'sgnovice'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先生的回答。