2017-01-02 8 views
2

Я хочу создать простую программу, которая отображает все большее число в цикле при нажатии кнопки запуска и изменения этого значения, нажимая другую кнопку, находясь в цикле , Программа, которую я придумал, используя то, что я нашел, увеличивает число и отображает ее правильно, но используемые мной переменные, по-видимому, независимы друг от друга, поэтому всякий раз, когда я возвращаю значение в 0, цикл продолжается там, где он был оставлен до сброс.Matlab - GUI - Измените переменную, изменив ее в другом обратном вызове

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 

Любая идея, как сделать эту тестовую переменную глобальной, как ее инициализировать и где я должен поместить ее в файл?

ответ

1

Да, это ожидаемое поведение! Область переменной test является локальной для каждой функции, поэтому вы не можете изменить ее в одной функции и ожидать, что измененное значение появится в другой функции.

Существует несколько вариантов этого! Например, вы можете использовать структуру handles для передачи «глобальных» переменных. В вашем коде, вы должны изменить его следующим образом:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
handles.test = 0; 
set(handles.display, 'String', num2str(handles.test)); 
guidata(hObject, handles); % Store the changed handles structure 

% --- Executes on button press in start. 
function run_Callback(hObject, eventdata, handles) 
handles.test = 1; 
while handles.test > 0 
    handles.test = handles.test + 1; 
    set(handles.display, 'String', num2str(handles.test)); 
    guidata(hObject, handles); % stores the changed handles structure 
    pause(1); 
    handles = guidata(hObject); % updates "handles" to see the change! 
end 

Это довольно стандартный подход, но у него есть несколько недостатков: Это очень легко случайно пропустить обновление или извлечение handles структуры. Кроме того, поскольку две функции работают параллельно, они подвержены условиям гонки.

Второй способ - использовать инструкцию global. Он легко вставляется:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
global test; 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
global test; 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 

Но это тоже приходит с несколькими недостаток: Теперь переменная test поистине глобальный характер. Его также можно изменить в других сценариях, функциях или графических интерфейсах, поэтому вы должны выбрать более уникальное имя, чем test, и быть осторожным в целом. Кроме того, когда (singleton) GUI перезапускается, не закрывая его сначала, визуальное состояние GUI, содержимое структуры handles и содержимое глобальных переменных могут стать «не синхронизированными». Я был укушен этим дважды, поэтому я больше не использую этот метод.

Третий способ заключается в том, что переменная test всегда должна быть связана с текстовым полем графического интерфейса. Поэтому он использует строку в поле display вместо переменной. По сути это означает, что с помощью get, set, str2double и num2str много:

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
set(handles.display, 'String', num2str(0)); 
guidata(hObject, handles); 

% --- Executes on button press in start. 
function run_Callback(hObject, eventdata, handles) 
set(handles.display, 'String', num2str(1)); 
while str2double(get(handles.display, 'String')) > 0 
    set(handles.display, 'String', ... 
     num2str(str2double(get(handles.display, 'String')) + 1)); 
    guidata(hObject, handles); 
    pause(1); 
end 

Это многословным, но это то, что я использую в этих случаях. Это наиболее надежное решение, особенно при перезапуске (singleton) GUI без его первого закрытия.

+0

Первый способ работает так, как планировалось! Я на самом деле использовал его ранее в своих тестах, но я не знал об этой строке «handles = guidata (hObject);% обновляет« ручки », чтобы увидеть изменение!» поэтому он отсутствовал, и поэтому он вел себя как код в моем запросе. Спасибо! – user3548298

+0

Что касается первого и третьего методов, что было бы наиболее эффективным? Я пытаюсь сделать программу обработки в реальном времени для звука, и мне нужно быть осторожным в этом – user3548298

+0

. Моя кишка говорит, что ни один из методов не очень эффективен - метод с оператором 'global', вероятно, является самым быстрым. Между первым и третьим методом, я предполагаю, что первый метод выполняется быстрее. Но только тест может решить наверняка. Звук в реальном времени может быть сложным, и вам, возможно, придется решать более совершенную магию. В любом случае, удачи! –

0

Вы можете просто объявить свою переменную глобальной. Это будет сделано.

% --- Executes on button press in stop. 
function stop_Callback(hObject, eventdata, handles) 
global test; 
test = 0; 
set(handles.display, 'String', num2str(test)); 
guidata(hObject, handles); 

% --- Executes on button press in run. 
function run_Callback(hObject, eventdata, handles) 
global test; 
test = 1; 
while test > 0 
    test = test + 1; 
    set(handles.display, 'String', num2str(test)); 
    guidata(hObject, handles); 
    pause(1); 
end 
0

если проект небольшой и помещается в один М-файл, вы можете решить эту проблему проще всего с помощью nested functions.

Если вы делаете свой GUI с помощью гида, то вы можете сделать это проще всего следующим образом: (убедитесь, что вы сохраните копию первого в автоматически генерируемых м-файл с редактирования GUI)

  1. открыть м-файл
  2. Если функции не закончились ключевым словом end, затем добавить его все функции, определенные, за исключением самого первой функции (чье имя находится на м-файл)
  3. поставить дополнительную end в самая нижняя часть вашего m-файла

После этого любые переменные, которые вы определяете в верхней функции, будут доступны для более низких функций (вложенных, которые также являются обратными вызовами). Стандартный редактор Matlab после этого цвета выделяет ваши переменные по-разному, если у них есть область действия во многих функциях.

 Смежные вопросы

  • Нет связанных вопросов^_^