【问题标题】:Obtaining a handle object's base workspace name in the constructor在构造函数中获取句柄对象的基本工作区名称
【发布时间】:2013-08-02 18:47:15
【问题描述】:

所以我有一个继承自 handle 超类的类,如下所示:

classdef testClass < handle
    properties(Access = private)
        handles_gui;
    end

    methods(Access = public)
        function obj = testClass
            % Preferably like to get inputname here
            obj.handles_gui = obj.init_gui();
        end

        function callback_test(obj,hObject,eventdata)
            disp(inputname(1));
        end
    end

    methods(Access = private)
        function handles_gui = init_gui(obj)            
            handles_gui.figure = figure( ...
                'Tag', 'figure', ...
                'Units', 'characters', ...
                'Position', [50 35 167 25]);    

            handles_gui.button_left = uicontrol( ...
                'Parent', handles_gui.figure, ...
                'Units', 'characters', ...
                'Position', [41 1.2 8 1.8], ...
                'String', 'Test', ...
                'Callback', @(hObject,eventdata) callback_test(obj,hObject,eventdata)); 
        end
    end
end

我希望最好在构造函数中获取对象的工作区名称。不确定这是否可行,因为在创建对象之前我不确定是否分配了名称。如果是这样的话,那么我想通过回调来获取它。我有一个 gui,但为了正确传递 obj 句柄,我必须通过在 init_gui 函数中传递 obj 来定义回调。这意味着当按下按钮时为callback_test 调用inputname 时,它返回'obj',因为它是在回调定义中定义的。但是,如果我通过终端调用callback_test,它会返回正确的变量名(结果是有意义的,但这不是我想要的)。示例如下:

EDU>> test = testClass;
obj (this was called by clicking on the button)
EDU>> test.callback_test
test 
EDU>> 

所以我的问题是:如何获取变量名,最好在构造函数中,如果没有,那么如何通过回调获取它,而不必使用终端。

【问题讨论】:

  • 刚想出一个主意:你可以使用whos,然后找到你感兴趣的类类型的所有变量名。然后你可以assignin进入调用者工作区并比较每个带有obj 的变量使用eq 来查找正确的名称。稍后我会看看这是否有效。
  • 好吧,我的评论是错误的,因为您不能在嵌套函数中使用assignin,所以现在我回到第一条。
  • 我在这里展示如何检索赋值变量名称:stackoverflow.com/questions/17554012/…。
  • @OlegKomarov,今晚晚些时候我会检查一下。谢谢。
  • 这是一个有趣的 Matlab 编程难题。但是,如果您需要对象本身内的对象的工作区名称,那么您可能有一个损坏的体系结构。这不应该是必需的,并且可能会阻止用户(即将来的您)以灵活的方式使用此类。

标签: matlab


【解决方案1】:

如果您需要知道对象的指定名称,那么最好将其作为构造函数调用约定的显式部分。例如:

        function obj = testClass(assignedName_input)
            obj.assignedName = assignedName_input;
            obj.handles_gui = obj.init_gui();
        end

然后,类的使用变为:

anyVariableName = testClass('test');  %Replaces "test = testClass();".  This separates the assigned name from the named used to keep track of it in the calling function.

或者,如果您稍后决定要一次将其中的 5 个放在一个数组中

for ix = 1:5
    arrayOfObjects{ix} = testClass(['test_' num2str(ix)]);  %This is not possible if you only look at the assigned variable name.
end

如果出于某种原因(我能想到几个),您想确保每个 assignedName 仅存在一个实例,您可以在类中使用静态 containers.Map 来维护现有列表对象,以及创建它们的静态工厂方法。 (我很确定这是“工厂方法设计模式”。)

例如,添加:

properties(Access = private, Static = true)
    existingInstancesMap = containers.Map('keyType','char','valueType','any');
end

methods(Access = public, Static = true) 
    function mappedInstance = getInstance(assignedName);
    if ~existingInstancesMap.isKey(assignedName)                      %If no mapped instance exists
        existingInstancesMap(assignedName) = testClass(assignedName); %Then make one and map it.
    end
    mappedInstance = existingInstancesMap(assignedName);               %Return the mapped instance
end

然后将你的构造函数设为私有。

【讨论】:

    【解决方案2】:

    好吧,这只是以防其他人偶然发现了这个问题。我解决了它:

    classdef testClass < handle
        properties(Access = private)
            handles_gui;
        end
    
        methods(Access = public)
            function obj = testClass
                % Preferably like to get inputname here
                obj.handles_gui = obj.init_gui();
            end
        end
    
        methods(Access = private)
            function handles_gui = init_gui(obj)            
                handles_gui.figure = figure( ...
                    'Tag', 'figure', ...
                    'Units', 'characters', ...
                    'Position', [50 35 167 25]);    
    
                handles_gui.button_left = uicontrol( ...
                    'Parent', handles_gui.figure, ...
                    'Units', 'characters', ...
                    'Position', [41 1.2 8 1.8], ...
                    'String', 'Test', ...
                    'Callback', @(hObject,eventdata) callback_test(obj,hObject,eventdata)); 
            end
    
            function callback_test(obj,hObject,eventdata)
                basevars = evalin('base','whos');
                testClassvars = basevars(strcmp({basevars.class},class(obj)));
    
                found = false;
                for i = 1:length(testClassvars)
                    if(eq(evalin('base',testClassvars(i).name),obj))
                        found = true;
                        disp(['Name is: ' testClassvars(i).name]);
                    end
                end
                if(~found)
                    disp('Handle has been deleted'); 
                end
            end
        end
    end
    

    这是我想要的功能;诀窍是使用evalin 来访问基础工作区中同一类的对象。我以为我需要使用assignin 来执行此操作,但我错了。实现这样的事情是否好是一个不同的问题,但这最终是我想做的,所以它是为其他想做类似事情的人准备的。

    输出:

    EDU>> a = testClass
    
    a = 
    
      testClass handle with no properties.
      Methods, Events, Superclasses
    
    EDU>> b = testClass
    
    b = 
    
      testClass handle with no properties.
      Methods, Events, Superclasses
    
    Name is: b (after clicking on the button)
    Name is: a (after clicking on the button)
    

    【讨论】:

      猜你喜欢
      • 2018-02-23
      • 1970-01-01
      • 2019-05-17
      • 1970-01-01
      • 2013-01-12
      • 2015-03-07
      • 1970-01-01
      • 2011-02-13
      • 1970-01-01
      相关资源
      最近更新 更多