Как создать графический интерфейс внутри функции в MATLAB? - PullRequest
5 голосов
/ 07 ноября 2008

Можно ли написать 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 в глобальном рабочем пространстве.

Ответы [ 3 ]

5 голосов
/ 08 января 2009

Существует несколько способов построить графический интерфейс пользователя , например, с помощью App Designer, GUIDE или создать его программно (я проиллюстрирую эту опцию ниже). Также важно знать о различных способах определения функций обратного вызова для ваших компонентов 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. Обратите внимание, что для функции обратного вызова кнопки задан дескриптор функции - increment, и что эта функция по умолчанию должна принимать два аргумента: графический дескриптор для компонента пользовательского интерфейса, который вызвал обратный вызов, и структуру связанных данные события. В этом случае мы игнорируем их с помощью ~, поскольку мы их не используем.

Расширяя вышеуказанный подход к вашей конкретной проблеме, вы можете добавить свой цикл и изменить обратный вызов, чтобы он установил для вашей переменной-флага значение 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.

1 голос
/ 10 ноября 2008

Я нашел решение проблемы. Функция обратного вызова должна изменить структуру дескриптора 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

1 голос
/ 07 ноября 2008

Вы можете объявить переменную global в вашей функции и global в коде GUI, конечно, если обратный вызов находится в отдельной функции, а не во встроенной функции. Я сделал это в небольшом графическом интерфейсе, который я использую для создания системы быстрого меню.

В приведенном выше коде вы можете добавить глобальное ключевое слово в ваше первоначальное объявление, а также в свой обратный вызов, т. Е. 'Global myvar = false'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...