代码之家  ›  专栏  ›  技术社区  ›  Azim J

试图在Matlab用户界面中实现保存/加载对象功能时遇到了困难

  •  1
  • Azim J  · 技术社区  · 16 年前

    我尝试在Matlab(R2009A)用户界面中实现保存/加载函数。我的对象实现了一个布局函数,它为对象生成一个用户界面。我正在尝试实现保存/加载按钮的回调。“保存”按钮起作用,并将对象保存到一个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
    

    用户界面布局在单独的文件中定义。 L. 基本上看起来像

    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。

    代码不会引发任何错误。我编写代码的方式父对象(由 自己 )呼叫后不更新 负载 在该方法中 加载对象 . 因此,这具有预期的效果:

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

    但是,如果我使用 加载MyObjor对象 回调定义于 L. 以这种方式

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

    不影响 var 性质。那就是 var 单击“加载”按钮后仍将具有其默认属性值。

    1. 更改要使用的加载方法 设置 正如建议的那样 gnovice 引发以下错误

      ????使用=>集时出错 无法从FujiCalibration转换为Double。

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

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

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

    3 回复  |  直到 11 年前
        1
  •  1
  •   Community CDub    8 年前

    我相信 Mr Fooz 是正确的。传递给加载对象的自变量是“myobj”类型的对象,但行:

    self = tmp.obj;
    

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

    self.image = tmp.obj.image;
    

    应该为对象本身的图像属性调用set运算符。在matlab文档中有一个 sample class definition 使用一个名为“set.officenumber”的方法来说明这一点。

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

    obj = self;
    

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

    编辑第1页:

    如果在加载对象方法中必须单独设置每个属性的前景听起来不那么有趣,一种解决方法是如果您的对象有一个像 SET method for handle graphics . 该set命令可以接受结构输入,其中每个字段名是属性名,每个字段值是该属性的新值。然后你会接到一个电话,比如:

    set(self,tmp.obj);
    

    稍微短一点,特别是如果你有很多属性要设置的话。当然,那你就得 对象的新set方法,但是如果它在其他地方也很有用,那么缩短的语法可能值得额外的工作。=)

    编辑第2页:

    您可以使用循环 福兹先生 建议与 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    16 年前

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

    if isfield(tmp,'obj')
       self.image = tmp.obj.image;
       self.objCount = tmp.obj.objCount;
    end
    
        3
  •  1
  •   Community CDub    8 年前

    结合 Mr Fooz's gnovice's 建议,我添加了一个具有以下定义的集合函数

    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建议的方法

    self = tmp.obj
    

    set(self,tmp.obj).
    

    我需要确保具有我想要持久化的值的属性的前缀是“p”。

    感谢gnovice和fooz先生的回答。