【问题标题】:How to create a GUI inside a function in MATLAB?如何在 MATLAB 中的函数内创建 GUI?
【发布时间】:2010-09-21 07:30:14
【问题描述】:

是否可以从函数内部编写 GUI?

问题是所有 GUI 函数的回调都是在全局工作区中评估的。但是函数有自己的工作空间,不能访问全局工作空间中的变量。是否可以让 GUI 函数使用该函数的工作区?例如:

function myvar = myfunc()
    myvar = true;
    h_fig = figure;

    % create a useless button
    uicontrol( h_fig, 'style', 'pushbutton', ...
                      'string', 'clickme', ...
                      'callback', 'myvar = false' );

    % wait for the button to be pressed
    while myvar
        pause( 0.2 );
    end

    close( h_fig );

    disp( 'this will never be displayed' );
end

此事件循环将无限期运行,因为回调不会修改函数中的myvar。相反,它将在全局工作区中创建一个新的myvar

【问题讨论】:

    标签: matlab function user-interface


    【解决方案1】:

    build a GUI 有多种方法,例如使用 App Designer、GUIDE 或以编程方式创建它(我将在下面说明此选项)。了解 GUI 组件的 different ways to define callback functionsoptions available for sharing data between components 也很重要。

    我偏爱的方法是使用nested functions 作为回调。下面以一个简单的 GUI 为例:

    function make_useless_button()
    
      % Initialize variables and graphics:
      iCounter = 0;
      hFigure = figure;
      hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
                          'String', 'Blah', 'Callback', @increment);
    
      % Nested callback function:
      function increment(~, ~)
        iCounter = iCounter+1;
        disp(iCounter);
      end
    
    end
    

    当您运行此代码时,每按一次按钮,显示的计数器应递增一,因为嵌套函数increment 可以访问make_useless_button 的工作区,因此可以修改iCounter。请注意,按钮回调设置为function handleincrement,默认情况下,此函数必须接受两个参数:触发回调的 UI 组件的图形句柄和关联事件数据的结构。在这种情况下,我们ignore them with the ~,因为我们没有使用它们。

    将上述方法扩展到您的特定问题,您可以添加循环并更改回调,以便将您的标志变量设置为 false:

    function make_stop_button()
    
      % Initialize variables and graphics:
      keepLooping = true;
      hFigure = figure;
      hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
                          'String', 'Stop', 'Callback', @stop_fcn);
    
      % Keep looping until the button is pressed:
      while keepLooping,
        drawnow;
      end
    
      % Delete the figure:
      delete(hFigure);
    
      % Nested callback function:
      function stop_fcn(~, ~)
        keepLooping = false;
      end
    
    end
    

    这里需要drawnow,让按钮回调有机会中断循环内的程序流程并修改keepLooping的值。

    【讨论】:

      【解决方案2】:

      你可以在你的函数中声明一个全局变量,在 GUI 代码中声明一个全局变量,当然如果回调是在一个单独的函数中而不是内联函数中。我在一个用来制作快速菜单系统的小骨架 GUI 中完成了这项工作。

      在上面的代码中,您可以将 global 关键字添加到初始声明以及内联回调中,即“global myvar = false”

      【讨论】:

      • OP 需要将输出变量更改为其他变量,并在基础工作区中创建“全局 myvar”以使其正常工作。
      • 这真的是唯一的方法吗?使用全局变量来完成这项工作似乎有点生硬。
      • 这是我想出的最好的方法——我同意它有点难看,我认为 Matlab GUI 模型不是很好。您可能想检查 Mathworks 上 uitable(?) 贡献中的代码。网站即将关闭。
      【解决方案3】:

      我找到了解决问题的方法。回调函数必须修改 GUI 的句柄结构。这个结构既可以在回调内部也可以从函数中访问,而无需向全局工作区引入新变量:

      function myfunc()
          h_fig = figure;
      
          % add continue_loop to the GUI-handles structure
          fig_handles = guihandles( h_fig );
          fig_handles.continue_loop = true;
          guidata( h_fig, fig_handles );
      
          % create a useless button
          uicontrol( h_fig, 'style', 'pushbutton', ...
                            'string', 'clickme', ...
                            'callback', @gui_callback );
      
          % wait for the button to be pressed
          while fig_handles.continue_loop
              fig_handles = guidata( h_fig ); % update handles
              pause( 0.2 );
          end
      
          close( h_fig );
          disp( 'callback ran successfully' );
      end
      
      % The arguments are the Matlab-defaults for GUI-callbacks.
      function gui_callback( hObject, eventdata, handles )
          % modify and save handles-Structure
          handles.continue_loop = false;
          guidata( hObject, handles );
      end
      

      请注意,由于 while 循环只会在运行时更新 fig_handles,因此在循环捕获 fig_handles.continue_loop 的修改之前,您将始终有至少 0.2 秒的延迟

      【讨论】:

      • 你在这里给出的答案看起来确实是正确的,这就是有多少人可能处理过这类问题。这完全取决于个人喜好:有些人喜欢使用 GUIDE,而我一直觉得我可以使用嵌套函数让事情看起来更干净(不过这需要更多的工作)。
      • 我同意这一点。事实上,我从 GUIDE 生成的代码中受了很多苦,以至于我编写了 fig2cmd - 从 .fig 文件中提取在 m 文件中重现它所必需的命令。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-20
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多