call_back函数内值的实时更新[值来自外部函数(另一个.m文件)]

时间:2016-02-24 15:05:30

标签: matlab matlab-guide

我有一个外部函数说“external_func”(单独的.m文件)

在此函数内部调用while循环,此while循环更新名为“update_prog”的变量

现在我将使用

将此值传递给GUIDE
assignin('base', 'update_prog', update_prog); % passing to workspace

我正在制作

“update_prog”作为全局变量并将其调用到GUIDE .m文件

function pb1_Callback(hObject, eventdata, handles)
global update_prog

% hObject    handle to pb1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% else
%      set(handles.pb1,'enable','on');
% end
% update_prog first value prints, but it wont updates as the loop in external_func goes on.
drawnow;
set(handles.slider1,'Value',update_prog)
 external_func;

所以在GUIDE .m文件中我可以得到值

“update_prog”但它不会跟上while循环。我使用“drawow”但它没用。

如何在“external_func”中的while循环经历多次迭代时,如何优化此值“update_prog”。 [注意:更新的值存在于GUIDE的回调函数中,但除非有回调函数,否则回调函数不会更新“update_prog”],那么如何在call_back函数内实现这种实时更新。

[注意:在我的情况下,通过函数输入传递变量是不可能的,所以我正在寻找替代方案]

Edit1:请考虑此链接,其中有一个示例Which may clarify you what I am trying to acheive

我在这里做的是

  1. 将变量(在外部函数的while循环中更新)传递到GUI。
  2. 我将使用此变量显示进度条上的进度(滑块)。
  3. 有什么问题?  1. GUI回调中的变量(Consdier I将按下按钮,然后它将使用while循环调用该函数)将更新的值放入set(handles.slider,'Value',variable)

    通过这样做,我无法移动滑块。

    为什么?

    1. 只有当我按下按钮时,回调才会更新变量,接下来不会更新变量的所有更新,因此进度条/滑块不会移动。

2 个答案:

答案 0 :(得分:1)

我不建议使用中间工作区(外部 - >基础工作区 - > GUI)以3个步骤传递变量。我宁愿建议直接传递你的变量(external-> GUI)。

每个Matlab图提供了一个存储任何类型变量(应用程序数据)的空间。我建议阅读文章Share Data Among Callbacks并阅读3个函数的文档:

通过这种方式,您可以更好地控制变量的范围,并且您不需要任何global声明。

下面是一个简单gui的例子。 gui在其用户空间(使用setappdata)中声明变量,然后使用计时器定期读取此变量(使用getappdata)。
外部函数执行您想要的任何操作(在示例中只是一个随机数),然后更新您使用相同setappdata的变量。你唯一需要的是主GUI图形的句柄,所以在这个例子中我把它作为外部函数的输入。

GUI还有两个按钮来启动和停止更新。

enter image description here

主要示例GUI的代码' theGui.m'是:

function h = theGui

%// basic GUI with 2 buttons and 1 slider
h.fig = figure('Position',[433 434 500 100],'Menubar','none','CloseRequestFcn',@my_closefcn) ;
h.sld = uicontrol('Style','Slider','Position',[20 20 460 20]) ;
h.btnStart = uicontrol('Style','pushbutton','String','Start updating','Callback',@btnStart_callback,'Position',[20 50 200 30]);
h.btnStop  = uicontrol('Style','pushbutton','String','Stop updating','Callback',@btnStop_callback,'Position',[280 50 200 30],'Max',1,'Min',0);

%// Define the timer
h.t = timer ;
h.t.Period = 0.1 ; %// 0.1s refresh interval
h.t.TimerFcn = {@timer_callback,h.fig} ;
h.t.ExecutionMode = 'fixedSpacing' ;

%// initialise the variable to update in the GUI appdata
update_prog = 0 ;
setappdata( h.fig , 'update_prog' , update_prog ) ;

%// save handles
guidata( h.fig , h );


function btnStart_callback(hobj,~)
    h = guidata( hobj ) ;           %// retrieve handles
    if strcmp('off',h.t.Running)    %// Start timer (only if not already running)
        start(h.t)
    end

function btnStop_callback(hobj,~)
    h = guidata( hobj ) ;   %// retrieve handles
    stop(h.t)               %// Stop timer

function timer_callback(~,~,hfig)
    update_prog = getappdata( hfig , 'update_prog' ) ;  %// retrieve the 'update_prog' variable value
    h = guidata( hfig ) ;                               %// retrieve handles
    set(h.sld , 'Value' , update_prog) ;                %// update the slider object with the retrieved value

function my_closefcn(hobj,~)
%// this function is only to clean up when the GUI will be closed.
%// It is recommended to delete the timer manually
    h = guidata( hobj ) ;   %// retrieve handles
    stop(h.t)               %// Stop timer (in case it is still running)
    delete(h.t) ;           %// delete the timer
    delete(h.fig) ;         %// destroy the figure

external_func.m

的代码
function external_func( guiMainFigureHandle )
%// This function will only generate random numbers and push them into the
%// variable 'update_prog' contained in the GUI appdata.
%// This is why this function NEEDS the handle of the gui to be able to
%// access the Application Data space of the gui.

for k = 1:100
    randomValue = rand(1) ;                              %// generate a random value
    hfig = ancestor( guiMainFigureHandle , 'figure' ) ;  %// make sure the handle provided is the top level figure
    setappdata( hfig , 'update_prog' , randomValue) ;    %// update the variable value
    pause(0.1) ;
end

编辑: 我将其置于编辑中而不是更改上面的代码,因为如果您不需要,我建议您不要使用root对象。但在你的情况下,它可以解决你的问题。

如果您的外部功能无法访问GUI,它可以随时更新可用于所有在给定Matlab会话中运行的程序的内存部分,即{ {1}}对象。它的句柄是保留的,对于任何程序都是相同的:root(虽然从v2014b开始有另一种方法可以调用它:groot,它仍然是所有Matlab的相同句柄。)< / p>

因此,在上面的示例中,在0中,请改为使用:

theGui.m

在主程序中,然后在子功能setappdata( 0 , 'update_prog' , update_prog ) ; 中,使用:

function timer_callback(~,~,hfig)

你的函数update_prog = getappdata( 0 , 'update_prog' ) ; %// retrieve the 'update_prog' variable 不需要任何额外的参数,更新只需要一行:

external_func()

答案 1 :(得分:0)

我“怀疑”基础工作区中的update_prog变量不是全局变量(您必须在要使用它的每个工作空间中将其定义为全局变量)。

由于您使用全局变量(有很多更好的方法可以做到这一点 - 但这不是您的问题) - 为什么不简单地将update_prog变量定义为external_func函数中的全局变量(替换分配呼叫。)

编辑在您的external_func功能中添加一个drawow。这样当你点击按钮时它会更新。

编辑3

我想我知道你想做什么,尝试这个例子,看看它是否符合你的要求 - 更新以显示如何在代码中找到滑块对象并在循环内更新:

function  mygui
  % create a figure
  f = figure;
  % create a uicontrol slider - note that I give it a tag.
  uicontrol ( 'style', 'slider', 'Position', [0 200 200 40], 'tag', 'MYSLIDER', 'backgroundcolor', 'white', 'parent', f );
  % create a push button which we can press to update
  uicontrol ( 'string', 'Press 2 start', 'callback', @(a,b)myLoop(), 'Position', [0 0 200 50] )
end

% This replicates your "external_func" function.
function myLoop()
  % since you cant pass in any var -> you need to find the slider object
  % you can do this by using findobj and search for the tag of the item
  uic = findobj ( 0, 'tag', 'MYSLIDER' );
  % find the figure handle (only needed for this demo)
  f = ancestor ( uic, 'figure' ); 
  % initialise the value which will be used to update the slider
  count = 0;
  % create your loop
  while ishandle(f)
    % incrememt the count variable -> this will end up on the slider value
    count = count + 1e-5;
    % reset count if > 1 -> so the slider cant go out of range.
    if count >= 1
      count = 0;
    end
    set ( uic, 'Value', count );
    % initiate a drawnow -> this allows matlab to process GUI events
    drawnow();
  end
end

这样做的缺点是你在循环中插入一个drawow - &gt;这可能会减慢它的速度。

如果这不能解决您的问题,您需要更好地解释您想要做的事情......(在我看来)