1

我正在尝试在 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。

该代码不会引发任何错误。在方法load_object中调用LOAD之后,我编写父对象(由self表示)的代码的方式不会得到更新。所以,这有预期的效果:

>> var = myObj;
>> var.load_object;

但是,如果我 以这种方式使用LayoutFcn.m中定义的loadingMyObject回调

>> var = myObjl
>> var.LayoutFcn
-> click Load button to call _loadingMyObject_

不影响var属性。也就是说var在单击 Load 按钮后仍将具有其默认属性值。

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

    ???使用 ==> 从 FujiCalibration 将转换设置为 double 时出错是不可能的。

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

    method set.image(self,II)
       % ... some data validation code ...
       self.image = II
    end
    
  2. 使用循环来设置Fooz 先生建议的每个字段并不是一个真正的选择,因为我的全班有公共常量,当它们被设置时会抛出错误。

我正在寻找一种解决方案,以避免我不得不单独手动设置每个字段的代码。尽管在这一点上,这似乎是唯一的可能性。

4

3 回答 3

1

不要给自己赋值。所做的只是在方法调用的范围内替换对 self 变量的绑定。它不会调用神奇的复制构造函数来替换调用者中的对象引用。相反,将字段复制到 self. 尝试类似:

if isfield(tmp,'obj')
   self.image = tmp.obj.image;
   self.objCount = tmp.obj.objCount;
end
于 2009-03-19T00:35:46.663 回答
1

我相信福兹先生是对的。传递给 load_object 的 self 变量是“myObj”类型的对象,但行:

self = tmp.obj;

只是用存储在 tmp.obj 中的结构覆盖 self 变量。正在做:

self.image = tmp.obj.image;

应该改为为对象 self 的图像属性调用集合运算符。在 MATLAB 文档中有一个示例类定义,其中包含一个名为“set.OfficeNumber”的方法来说明这一点。

此外,您的函数 SavingMyObject 中的以下行可能是不必要的:

obj = self;

我认为如果您在类代码中使用名称“obj”代替单词“self”(文档倾向于这样做),这可能最有意义(并使代码更清晰)。“self”在 MATLAB 中似乎不是任何类型的特殊关键字(就像在其他语言中一样)。据我所知,这只是另一个变量。=)

编辑#1:

如果必须在您的 load_object 方法中单独设置每个属性的前景听起来并不有趣,那么一种解决方法是,如果您的对象有一个 SET 方法,其设计类似于用于处理图形的 SET 方法。该 SET 命令可以接受结构输入,其中每个字段名称是属性名称,每个字段值是该属性的新值。然后你会接到一个电话,比如:

set(self,tmp.obj);

相当短一些,特别是如果你有很多属性要设置。当然,您随后必须为您的对象编写新的 SET 方法,但如果在其他地方也能派上用场,缩短的语法可能值得额外的工作。=)

编辑#2:

您可以将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
于 2009-03-19T01:47:50.360 回答
1

结合Fooz 先生gnovice 的建议,我添加了一个具有以下定义的 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 先生的回答。

于 2009-03-19T19:22:15.730 回答