如何获得';图';a';控制';添加了';javacomponent';常规

如何获得';图';a';控制';添加了';javacomponent';常规,java,matlab,user-interface,Java,Matlab,User Interface,背景 单击MatlabGUI中的某个按钮后显示msgbox时,对话框总是神奇地出现在保存单击按钮的图形顶部。。。这与图形的位置无关,即使未向msgbox调用传递对此图形的引用 好吧,看看msgbox的代码,这不仅仅是魔术。实际上,在代码中有一个调用,它返回回调正在执行的控件和包含该控件的图(通过调用figure类型) 问题 当使用javacomponent例程添加自定义控件时,只要使用uicontrol例程添加控件,gcbo机制工作良好, GCBO < /代码>机制找不到图形,而 MSGBOS显

背景

单击MatlabGUI中的某个按钮后显示
msgbox
时,对话框总是神奇地出现在保存单击按钮的图形顶部。。。这与图形的位置无关,即使未向
msgbox
调用传递对此图形的引用

好吧,看看
msgbox
的代码,这不仅仅是魔术。实际上,在代码中有一个调用,它返回回调正在执行的控件和包含该控件的图(通过调用figure类型)

问题

当使用
javacomponent
例程添加自定义控件时,只要使用
uicontrol
例程添加控件,
gcbo
机制工作良好,<代码> GCBO < /代码>机制找不到图形,而 MSGBOS显示在屏幕的中间,而不是在图的顶部,如下面的代码所示:

function [] = gcboDemo()
%[  
    % Create figure
    fig = figure('Name', 'Hello', 'units', 'normalized', 'Position', [1/5, 0.5, 1/5, 1/5]);

    % Add standard matlab button
    matlabBtn = uicontrol('Parent', fig, 'units', 'normalized', 'Position', [1/5, 0.5, 1/5, 1/5], 'String', 'Matlab');
    set(matlabBtn, 'Callback', @(sender, args)onBtnClicked())

    % Add java button
    [javaBtn, jContainer] = javacomponent('javax.swing.JButton', [0 0 1 1], fig); 
    set(jContainer, 'units', 'normalized', 'position', [3/5, 0.5, 1/5, 1/5]);
    javaBtn.setText('Java');
    set(javaBtn, 'ActionPerformedCallback', @(sender, args)onBtnClicked())
%]
end
function [] = onBtnClicked()
%[
    % This is what 'msgbox' is doing to find nice position for where to draw on screen
    % 1) It looks for control intiating the callback and the figure containing it
    % 2) It changes 'msgbox' position so it will appear over the figure
    % NB: If no figure is found, 'msgbox' appear in middle of the screen 
    [controlOriginatingCallback, figureContainingObjectOriginatingCallback] = gcbo(); 

    if (~isempty(figureContainingObjectOriginatingCallback))
        msg = sprintf('Control = `%s` in Figure = `%s`', class(controlOriginatingCallback), get(figureContainingObjectOriginatingCallback, 'Name'));
    else
        msg = sprintf('Control = `%s` in Figure = `???`', class(controlOriginatingCallback));
    end

    uiwait(msgbox(msg, 'modal'));
%]
end
问题

我喜欢
gcbo
的行为,并希望为我用
javacomponent
添加的控件复制它(不仅是为
msgbox
而且为我自己创建的自定义对话框)

有没有一种简单的方法可以让我返回对
图的引用,该图包含添加了
javacomponent
的控件

NB1:目前我可以通过
ctrl=get(0,'CallbackObject')
获取其回调正在执行的对象,我可以通过
ctrl.getParent()
访问该图,但返回的引用是java对象,我不知道如何在Matlab世界中获取对等引用


NB2:我知道我可以使用
[jControl,hContainer]=javacomponent(…)
语法并将
hContainer
传递给回调iin,以便跟踪对包含
图的引用
,但我更愿意保留与
gcbo
类似的机制(例如,覆盖
gcbo
的实现,并让所有例程使用它来处理
javacomponent
对象)。

经过几次尝试,我找到了一个解决方案:

  • 我使用
    thisFigure=get(control,'topLevelAgentor')
  • 我临时逐个修改maltab图形句柄的
    Name
    属性,直到
    thisfigure.getTitle()
    与我设置的临时名称匹配
注意:最好更改java端
标题
并使用
findobj
查找matlab端
名称
,但更改java端不会更新matlab端(反之亦然,所以…)

以下是覆盖的代码:

%
% PURPOSE:
%
%    Gets handle to current callback control and 
%    handle to the figure containing that control. 
%
% SYNTAX:
%
%    [control] = gcboex();
%    [control, fig] = gcboex();
%
% DESCRIPTION:
%
%    Works exactly the same way as native `gcbo` routine except
%    that it is also working for controls created with `javacomponent`.
% 

%% ---
function [control, fig] = gcboex()
%[
    % Obtain graphical element whose callback is executing
    control = get(0, 'CallbackObject');

    % Case not executing from callback on a graphical element
    if (isempty(control) || ~(ishghandle(control) || ishandle(control)))
        control = [];
        fig = [];
        return;
    end

    % Obtain the figure containing the graphical element
    if (isempty(strfind(class(control), 'javahandle_withcallbacks')))

        fig = ancestor(control, 'figure'); % Do the same as native `gcbo` routine

    else
        try

            % Obtain the containing figure as a java handle
            thisFigure = get(control, 'TopLevelAncestor');
            if (isempty(strfind(class(thisFigure), 'FigureFrameProxy'))), error('Not inside a figure'); end

            % Obtain all figures as matlab handles
            allFigures = findobj(0, 'Type', 'figure');

            % Temporarly modify figure names one by one and check
            % from the java side that this our title that has changed
            %
            % NB: Would be easier to do modify java-side title or ToolTipString
            % and use 'findobj' but when we modify java-side the changes are not
            % reported on matlab side even with forceGuiUpdate, so we do the reverse (which is working) ...
            fig = []; 
            searchedName = char(java.util.UUID.randomUUID);
            for fi = 1:length(allFigures)
                currentFig = allFigures(fi);
                oldName = get(currentFig, 'Name');
                set(currentFig, 'Name', searchedName); forceGuiUpdate();
                if (strfind(char(thisFigure.getTitle()), searchedName))
                    fig = currentFig; 
                end
                set(currentFig, 'Name', oldName); forceGuiUpdate();
                if (~isempty(fig)), break; end
            end

        catch
            fig = [];
        end        
    end
%]
end
function [] = forceGuiUpdate()
%[
    try
        drawnow nocallbacks; 
    catch
        drawnow; % Force update (not sure 'nocallbacks' option was introduced very recently ...) 
    end
%]
end
以下是带有
gcboex
补丁的完整示例代码:

function [] = gcboDemo()
%[  
    % Create figure
    fig = figure('Name', 'Hello', 'units', 'normalized', 'Position', [1/5, 0.5, 1/5, 1/5]);

    % Add check box
    cb =uicontrol('Parent', fig, 'Style', 'Checkbox', 'units', 'normalized', 'Position', [1/5, 4/5, 1/3, 1/5], 'String', 'Use modified gcbo');

    % Add standard matlab button
    matlabBtn = uicontrol('Parent', fig, 'units', 'normalized', 'Position', [1/5, 0.5, 1/5, 1/5], 'String', 'Matlab');
    set(matlabBtn, 'Callback', @(sender, args)onBtnClicked(cb))

    % Add java button
    [javaBtn, jContainer] = javacomponent('javax.swing.JButton', [0 0 1 1], fig); 
    set(jContainer, 'units', 'normalized', 'position', [3/5, 0.5, 1/5, 1/5]);
    set(jContainer, 'Tag', char(java.util.UUID.randomUUID));
    javaBtn.setText('Java');
    set(javaBtn, 'ActionPerformedCallback', @(sender, args)onBtnClicked(cb))
%]
end
function [] = onBtnClicked(cb)
%[
    % Check if using 'gcboex'
    useGcboex = (get(cb, 'Value') ~= 0);

    if (useGcboex)
        [controlOriginatingCallback, figureContainingObjectOriginatingCallback] = gcboex();
    else
        [controlOriginatingCallback, figureContainingObjectOriginatingCallback] = gcbo();
    end

    if (~isempty(figureContainingObjectOriginatingCallback))
        msg = sprintf('Control = `%s` in Figure = `%s`', class(controlOriginatingCallback), get(figureContainingObjectOriginatingCallback, 'Name'));
    else
        msg = sprintf('Control = `%s` in Figure = `???`', class(controlOriginatingCallback));
    end

    b = msgbox(msg, 'modal');
    if (useGcboex)
        moveguiex(b, 'Over', figureContainingObjectOriginatingCallback);
    end
    uiwait(b);
%]
end

%% ----
function [control, fig] = gcboex()
%[
    % Obtain graphical element whose callback is executing
    control = get(0, 'CallbackObject');

    % Case not executing from callback on a graphical element
    if (isempty(control) || ~(ishghandle(control) || ishandle(control)))
        control = [];
        fig = [];
        return;
    end

    % Obtain the figure containing the graphical element
    if (isempty(strfind(class(control), 'javahandle_withcallbacks')))

        fig = ancestor(control, 'figure'); % Do the same as native `gcbo` routine

    else
        try

            % Obtain the containing figure as a java handle
            thisFigure = get(control, 'TopLevelAncestor');
            if (isempty(strfind(class(thisFigure), 'FigureFrameProxy'))), error('Not inside a figure'); end

            % Obtain all figures as matlab handles
            allFigures = findobj(0, 'Type', 'figure');

            % Temporarly modify figure names one by one and check
            % from the java side that this our title that has changed
            %
            % NB: Would be easier to do modify java-side title or ToolTipString
            % and use 'findobj' but when we modify java-side the changes are not
            % reported on matlab side even with forceGuiUpdate, so we do the reverse (which is working) ...
            fig = []; 
            searchedName = char(java.util.UUID.randomUUID);
            for fi = 1:length(allFigures)
                currentFig = allFigures(fi);
                oldName = get(currentFig, 'Name');
                set(currentFig, 'Name', searchedName); forceGuiUpdate();
                if (strfind(char(thisFigure.getTitle()), searchedName))
                    fig = currentFig; 
                end
                set(currentFig, 'Name', oldName); forceGuiUpdate();
                if (~isempty(fig)), break; end
            end

        catch
            fig = [];
        end        
    end
%]
end
function [] = forceGuiUpdate()
%[
    try
        drawnow nocallbacks; 
    catch
        drawnow; % Force update (not sure 'nocallbacks' option was introduced very recently ...) 
    end
%]
end

%% ---
function [] = moveguiex(h, positionDescription, varargin)
%[
    % Check arguments
    if (nargin < 2), error('Not enough input arguments.'); end
    if (~ischar(positionDescription)), error('Invalid position identifier.'); end
    if (~ishandle(h)), error('Invalid graphic handle.'); end

    % 'CenterOf'
    if (strcmpi(strtrim(positionDescription), 'CenterOf') || ...
        strcmpi(strtrim(positionDescription), 'Over'))

        % Additional checks
        if (nargin < 3), error('Not enough input arguments.'); end
        if (nargin ~= 3), error('Too many input arguments.'); end
        p = varargin{1}; if (~ishandle(p)), error('Invalid graphic handle.'); end

        % Work
        if (isempty(p))
            pp = get(0,'screensize'); pl = pp(1); pb = pp(2); pw = pp(3); ph = pp(4); 
        else
            pp = getpixelposition(p); pl = pp(1); pb = pp(2); pw = pp(3); ph = pp(4); 
        end
        tp = getpixelposition(h); tw = tp(3); th = tp(4);

        switch(lower(strtrim(positionDescription)))
            case 'centerof',
                tl = pl + (1/2)*(pw - tw);
                tb = pb + (1/2)*(ph - th);
            case 'over',
                tl = pl + (1/2)*(pw - tw);
                tb = pb + (2/3)*(ph - th);
            otherwise,
                error('Out of range');
        end
        setpixelposition(h, [tl tb tw th]);

        % End
        return;

    end

    % Oops
    error('Position = `%s` is not supported', positionDescription);
%]
end
function[]=gcboDemo()
%[  
%塑造形象
图=图(‘名称’、‘你好’、‘单位’、‘标准化’、‘位置’、[1/5,0.5,1/5,1/5]);
%添加复选框
cb=uicontrol('Parent',fig',Style','Checkbox','units','normalized','Position',[1/5,4/5,1/3,1/5],'String','Use modified gcbo');
%添加标准matlab按钮
matlabBtn=uicontrol('Parent',fig','units','normalized','Position',[1/5,0.5,1/5,1/5],'String','Matlab');
在BTNClicked(cb)上设置(matlabBtn,'回调',@(发送方,参数)
%添加java按钮
[javaBtn,jContainer]=javacomponent('javax.swing.JButton',[0 0 1 1],图);
集合(jContainer,'units','normalized','position',[3/5,0.5,1/5,1/5]);
set(jContainer,'Tag',char(java.util.UUID.randomUUID));
setText('Java');
设置(javaBtn,'ActionPerformedCallback',@(发送方,参数)onBtnClicked(cb))
%]
结束
函数[]=onBtnClicked(cb)
%[
%检查是否使用“gcboex”
useGcboex=(get(cb,'Value')~=0);
如果(使用GCBOEX)
[controlOriginatingCallback,FigureContainingObjectorigingCallback]=gcboex();
其他的
[controlOriginatingCallback,FigureContainingObjectorigingCallback]=gcbo();
结束
if(~isempty(图中包含ObjectorigingCallback))
msg=sprintf('Control=`s`in Figure=`s`',class(controloriginingcallback),get(figureContainingObjectoriginingCallback,'Name');
其他的
msg=sprintf('Control=`%s`在图中=`?`',类(controloriginingcallback));
结束
b=msgbox(msg,‘模态’);
如果(使用GCBOEX)
moveguiex(b,“结束”,FigureContainingObjectorigingCallback);
结束
uiwait(b);
%]
结束
%% ----
函数[控制,图]=gcboex()
%[
%获取其回调正在执行的图形元素
control=get(0,'CallbackObject');
%不从图形元素上的回调执行大小写
如果(isempty(控制)| | ~(ishghandle(控制)| | ishandle(控制)))
控制=[];
图=[];
返回;
结束
%获取包含图形元素的图形
if(isempty(strfind(类(控件),'javahandle_with callbacks'))
fig=祖先(控制,'figure');%执行与本机'gcbo'例程相同的操作
其他的
尝试
%获取包含的图形作为java句柄
thisFigure=get(控件“TopLevelAgentor”);
if(isempty(strfind(class(thisFigure),'figureFlameProxy'))),error('notinthefigure');end
%获取所有图形作为matlab句柄
allFigures=findobj(0,'类型','图形');
%逐个临时修改地物名称并选中
%从java的角度来看,这是我们的标题已经改变了
%
%注意:修改java端标题或ToolTipString会更容易
%并使用'findobj',但当我们修改java端时,更改不会发生
%在matlab端报告,即使使用forceGuiUpdate,我们也会执行相反的操作(正在工作)。。。
图=[];
searchedName=char(java.util.UUID.randomUUID);
对于fi=1:长度(所有数字)