5

関数内から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代わりに、グローバル ワークスペースに新しい を作成します。

4

3 に答える 3

5

GUI を作成するには、App Designer や GUIDE を使用したり、プログラムで作成したりする方法がいくつかあります(このオプションについては以下で説明します)。GUI コンポーネントのコールバック関数を定義するさまざまな方法と、コンポーネント間でデータを共有するために使用できるオプションを認識することも重要です。

私が好きなアプローチは、ネストされた関数をコールバックとして使用することです。例として簡単な 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

このコードを実行すると、表示されるカウンターは、ボタンを押すたびに 1 ずつ増加します。これは、ネストされた関数incrementが のワークスペースにアクセスできるため、make_useless_buttonを変更できるためiCounterです。ボタン コールバックは への関数ハンドルに設定されてincrementおり、この関数はデフォルトで 2 つの引数を受け入れる必要があることに注意してください。コールバックをトリガーした UI コンポーネントのグラフィックス ハンドルと、関連付けられたイベント データの構造です。この場合、それらを使用していないため、 でそれらを無視します。~

上記のアプローチを特定の問題に拡張すると、ループを追加してコールバックを変更し、フラグ変数を 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

于 2009-01-08T18:39:03.643 に答える
1

コールバックがインラインではなく別の関数にある場合は、関数内でグローバル変数を宣言し、GUI コード内でグローバル変数を宣言できます。これは、クイック メニュー システムを作成するために使用する小さなスケルトン GUI で行いました。

上記のコードでは、global キーワードを最初の宣言とインライン コールバック、つまり 'global myvar = false' に追加できる場合があります。

于 2008-11-07T16:12:38.513 に答える
1

問題の解決策を見つけました。コールバック関数は、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 のみを更新するため、ループが変更をキャッチするまで常に少なくとも 0.2 秒の遅延があることに注意してください。fig_handles.continue_loop

于 2008-11-10T13:07:57.620 に答える