回调

时间:2018-03-29 08:24:39

标签: matlab oop

我在使用matlab句柄类时面临一个奇怪的问题,在执行某些回调时类的状态不是预期的。

为了显示问题,我过度简化了我的课程定义。这个类的基本思想是在设置之上创建一个用户界面,可以通过代码或用户交互来修改。

问题是我使用 java 组合框会激活已更改的事件,从代码或用户交互中修改选定的索引...好的...非常简单的解决方法我想,因此我决定在我的类中添加一个lockJavaEvent属性,以便知道是否从代码或用户交互中触发了更改的事件:

% Callback to listen to combo changed events
set(this.jcbFilterType, 'ActionPerformedCallback', @(s, e)this.onFilterTypeChanged(e)); 

% Code to refresh interface from code
function [] = refreshGuiFromCode(this)
%[
    this.lockJavaEvents = this.lockJavaEvents + 1;
    this.jcbFilterType.setSelectedIndex(this.filterTypeIndex - 1);            
    this.lockJavaEvents = this.lockJavaEvents - 1;
%]
end

% Code to respond to combox changed with quick exist in case it is changed from code
function [] = onFilterTypeChanged(this, e)
%[
    % Quick exit for events locked
    if (this.lockJavaEvents > 0),
        disp('Skipping combobox event because we are refreshing from code');
        return; 
    end

    ...
%]
end

不幸的是,这根本不起作用!调用refreshGuiFromCode时:

  • 按预期this.lockJavaEvent增加到1
  • 正如预期的那样,因为我正在修改组合索引,所以附加的onFilterTypeChanged被称为
  • 但patatra,在onFilterTypeChanged回调中this.lockJavaEvent的值仍然等于零????? !!!!

我显然不明白这里发生了什么?为什么this对象似乎是旧副本,而我的类被定义为句柄类?

以下是我完整的测试代码:

classdef BugLockJava <  hgsetget
%[    
    methods
        function [this] = BugLockJava()
        %[    
            this.lockJavaEvents = 0;
            this.filterTypeIndex = 2;

            this.buildGui();
            this.refreshGuiFromCode();
        %]                
        end
        function [] = delete(this)
        %[
            delete(this.parent);
        %]
        end
    end

    methods(Access = private)
        function [] = buildGui(this)
        %[    
            this.parent = figure();
            this.jcbFilterType = this.addJavaComboBox(); 

            this.jcbFilterType.setModel(javax.swing.DefaultComboBoxModel({'Sphere', 'Cylinder', 'Power', 'N&M'})); 
            this.jcbFilterType.setEditable(false);
            set(this.jcbFilterType, 'ActionPerformedCallback', @(s, e)this.onFilterTypeChanged(e)); 
        %]    
        end
        function [jComponent, hComponent, hContainer] = addJavaComboBox(this)
        %[
            % Create a matlab container to hold it 
            % NB: Required for uix, uiextras parents (GUILayout toolbox)
            hContainer = uicontainer('Parent', this.parent);
            position = getpixelposition(hContainer); position(1) = 0; position(2) = 0;

            % Link java component with visual tree in matlab
            [jComponent, hComponent] = javacomponent(javaObjectEDT('javax.swing.JComboBox'), position, hContainer);
            set(hComponent, 'Units', 'normalized');

            % Turns java naked reference into a matlab component
            % http://undocumentedmatlab.com/blog/uicontrol-callbacks
            jComponent = handle(jComponent, 'CallbackProperties');            
        %]
        end
        function [] = refreshGuiFromCode(this)
        %[
            this.lockJavaEvents = this.lockJavaEvents + 1;
            this.jcbFilterType.setSelectedIndex(this.filterTypeIndex - 1);            
            this.lockJavaEvents = this.lockJavaEvents - 1;
        %]
        end
        function [] = onFilterTypeChanged(this, e)
        %[
            % Quick exit for events locked
            if (this.lockJavaEvents > 0),
                disp('Skipping combobox event because we are refreshing from code');
                return; 
            end

            % Quick exist for action unknown
            cmd = char(e.getActionCommand());
            if (~strcmpi(cmd, 'comboBoxChanged')), 
                disp('Skipping combobox event because we don''t care');
                return; 
            end

            disp('Ok combobox changed from user interaction');
            this.filterTypeIndex = this.jcbFilterType.getSelectedIndex() + 1;                        
        %]
        end
    end


    properties %%% Keeping public for debugging values (Access = private)
        parent;
        jcbFilterType;
        lockJavaEvents;

        filterTypeIndex;
    end
%]    
end

1 个答案:

答案 0 :(得分:0)

我找到了!!!

Unsynchronized

看看在执行onFilterTypeChanged回调时放置黄色箭头有多么奇怪...就好像refreshGuiFromCode之后setSelectedIndex继续执行.... java回调只在结束,因为它是 ON TH TH TH TH / <>

要解决此问题,我只需添加一个对drawnow()的调用,强制执行消息泵中的待处理事件,然后再继续执行:

Synchronized

这确实是一个奇怪的问题......但是当记住java组件在另一个ui线程上时,无论如何都很容易修复。