MATLAB.Exponenta
–Û·Ë͇ Matlab&Toolboxes

Приложения с GUI и дескрипторная графика

Новшества для создания приложений с графическим интерфейсом пользователя в 7-ой версии MATLAB

В 7-ой версии MATLAB появилось несколько новшеств для создания приложений с графическим интерфейсом пользователя. В демонстрациях (на вкладке Demo справочной системы MATLAB) в разделе Greating Craphical User Interfaces содержится десятиминутная видеодемонстрация новых возможностей по созданию приложений с графическим интерфейсом. Новые возможности описаны в справочной системе в разделе Release Notes: Summary of Product Updates: MATLAB Products (после выбора этого раздела в правом окне спарвочной системы надо щелкнуть по ссылке MATLAB, затем в появившемся окне по New Features и далее по ссылке Creating Graphical User Interfaces (GUIDE) Features).

Появилась возможность использовать в приложениях MATLAB различные Active X компоненты. Удобнее стало обеспечивать согласованную работу группы переключателей. Окно приложения может содержать одну или несколько панелей инструментов с кнопками или кнопками-переключателями. Усовершенствован редактор меню среды GUIDE, который позволяет теперь более эффективно создавать и настраивать меню, а так же он лучше согласован с другими компонентами среды GUIDE. Cобытие KeyPressFcn объектов uicontrol (кнопки, переключатели и т. д.) позволяет задать действие, которое надо выполнить при нажатии пользователем клавиши (или сочетания клавиш), если данный объект находится в фокусе. Для передачи фокуса ввода объекту uicontrol теперь можно использовать функцию uicontrol. Небольшие изменения коснулись стандартного диалогового окна запроса, в котором можно при его создании указать кнопку, находящуюся в фокусе. Область ввода многострочного текста снабжается полосой прокрутки, которая, так же, как и обычная полоса прокрутки может быть настроена на различное перемещение области просматриваемого в окне текста. Стандартное диалоговое окно открытия файла допускает выбор нескольких файлов. Обработка событий элементов управления может быть осуществлена при помощи вложенных функций (Nested Function), что позволяет просто программировать диалоговые окна как функции, возвращающие параметры.

Иерархическая схема элементов управления приведена ниже.

Панели и группы переключателей

В 7-ой версии MATLAB появилась панель, которая может содержать другие элементы управления (кнопки, переключатели, строки ввода и т.д.), области ввода текста, графические оси, а так же другие панели и группы переключателей. В среде GUIDE панель создается при помощи соответствующей кнопки . После создания панели на нее можно добавлять остальные элементы, причем при перемещении панели по заготовке окна приложения все размещенные на ней элементы управления перемещаются вместе с ней. Объекты, размещаемые на панели, являются потомками панели, их положение определяется внутри панели.

Для создания панели может быть применена функция uipanel, которая вызывается следующим образом

h=uipanel('НазваниеСвойства', значение, 'НазваниеСвойства', значение, ...)

Свойства, отвечающие за вид панели и их возможные значения таковы.

BorderType - тип границы вокруг панели, значения:

  • 'none' - отсутствие границы
  • 'etchedin' (по умолчанию), 'etchedout', 'beveledin','beveledout' - различные варианты объемных видов панели
  • 'line' - линия

BorderWidth - толщина границы, значением является целое число, задающее толщину границы вокруг панели в пикселях. По умолчанию, толщина границы составляет 1 пиксель.

Title - название панели, значением является строка или строковая переменная, если задан массив строк или массив ячеек, каждая ячейка которого содержит строку, то используется только первая строка, остальные игнорируются.

TitlePosition - положение названия панели, значения

  • lefttop - слева сверху (по умолчанию)
  • centertop - сверху по центру
  • righttop - справа сверху
  • leftbottom - слева внизу
  • centerbottom - внизу по центру
  • rightbottom - справа внизу

FontAngle - наклон шрифта в названии панели, значения

  • 'normal' - обычный (по умолчанию)
  • 'italic' - курсив

FontName - имя шрифта в названии панели, значением является строка с именем одного из шрифтов, установленных в системе.

FontSize - размер шрифта в названии панели, задаваемый числом в единицах измерения, определяемых значением свойства FontUnits.

FontUnits - единицы измерения размера шрифта, значения

  • 'inches' - дюймы
  • 'centimeters' -сантиметры
  • 'normalized' - нормализованные (в долях высоты панели)
  • 'points' - пункты (по умолчанию)
  • 'pixels' - пиксели

FontWeight - жирность шрифта, значения:

  • 'normal' - обычный (по умолчанию)
  • 'bold' - жирный

ForegroundColor - цвет рамки вокруг панели и шрифта в названии панели, значения: один из цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w' или цвет в формате RGB (вектор из трех компонент).

BackgroundColor - цвет панели, значения: один из цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w' или цвет в формате RGB (вектор из трех компонент). По умолчанию совпадает с цветом объектов uicontrol и зависит от настроек операционной системы.

ShadowColor - цвет тени от объемной рамки вокруг панели , значения: один из цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w' или цвет в формате RGB (вектор из трех компонент).

HighlightColor - цвет рамки вокруг панели , значения: один из цветов 'r', 'g', 'b', 'c', 'm', 'y', 'k', 'w' или цвет в формате RGB (вектор из трех компонент).

Visible - видимость панели, значения

  • 'on' - видна (по умолчанию)
  • 'off' - не видна

Если свойство Visible установлено в off, то не видны также оси, панели и группы переключателей, которые являются потомками данной панели. Элементы управления (кнопки, переключатели и т.д.), размещенные на панели (являющиеся ее потомками), остаются видимыми.

Назначение остальных свойств и событий: Children, Parent, Selected, Tag, UserData, Position, Units, HandleVisibility, HitTest, BusyAction, ButtonDownFcn, CreateFcn, DeleteFcn, Interruptible, ResizeFcn, UIContextMenu такое же, как и у других элементов управления.

Для обеспечения согласованной работы группы переключателей (может быть включен только один из них) появилась панель переключателей (Button group). Она создается в среде GUIDE при помощи кнопки . Переключатели и кнопки-переключатели (Toggle Button), размещенные на этой панели автоматически ведут себя согласованно. При перемещении группы переключателей по заготовке окна приложения все размещенные на ней элементы управления перемещаются вместе с ней. Объекты, размещаемые в группе переключателей, являются ее потомками, и их положение определяется внутри панели.

Для создания панели может быть применена функция uipanel, которая вызывается следующим образом

h= uibuttongroup ('НазваниеСвойства', значение, 'НазваниеСвойства', значение, ...)

Свойства, отвечающие за вид панели и их возможные значения такие же, как и у панели, описанной выше.

При программировании событий от кнопок и кнопок-переключателей, размещенных в группе, следует использовать событие SelectionChangeFcn, которое возникает при установке одного из переключателей или кнопок-переключателей. Значением SelectionChangeFcn должен быть указатель на функцию обработки события, у которой есть два входных аргумента. В первом входном аргументе передается указатель на группу переключателей, а во втором - структура со следующими полями:

  • EventName, содержащим строку 'SelectionChanged'
  • OldValue, содержащим указатель на тот переключатель, или кнопку-переключатель, который были включены до возникновения события SelectionChangeFcn группы переключателей. Если ни один из них не был включен, то возвращается пустой массив [].
  • NewValue, содержащем указатель на тот переключатель, или кнопку-переключатель, который стал включенным после возникновения события SelectionChangeFcn группы переключателей.

Если одновременно запрограммированы события SelectionChangeFcn группы переключателей и события Callback каждого переключателя или кнопки-переключателя, то будет выполняться функция обработки события SelectionChangeFcn.

Следующее приложение btngroupdemo демонстрирует программирование группы переключателей. При выборе одного из них в текстовой области выводится сделанный выбор и прежнее состояние группы переключателей.

function btngroupdemo
% Создание окна приложения
h=figure('MenuBar','none');
% Создание группы переключателей и переключателей Red, Green, Blue. Для обработки события 
% SelectionChangeFcn группы будет использоваться функция SelectionChangeFcn_Callback
handles.btngroup=uibuttongroup('Position',[0.1 0.5 0.4 0.4],...
    'SelectionChangeFcn', @SelectionChangeFcn_Callback);
handles.rbRed=uicontrol('Style','Radio','String','Red',...
    'Units','normalized','position',[0.1 0.7 0.8 0.2],...
    'parent',handles.btngroup);
handles.rbGreen=uicontrol('Style','Radio','String','Green',...
    'Units','normalized','position',[0.1 0.4 0.8 0.2],...
    'parent',handles.btngroup);
handles.rbBlue=uicontrol('Style','Radio','String','Blue',...
    'Units','normalized','position',[0.1 0.1 0.8 0.2],...
    'parent',handles.btngroup);
% Создание текстовой области
handles.txtInfo=uicontrol('Style','Text',...
    'Units','normalized','position',[0.52 0.5 0.4 0.4]);
% Сохранение указателей на объекты приложения в структуре handles
guidata(h,handles)

% Функция обработки события SelectionChangeFcn группы переключателей
function SelectionChangeFcn_Callback(src, evt)
% получаем указатель на переключатель, который был включен после возникновения 
% события SelectionChangeFcn группы переключателей
hOld=evt.OldValue;
% получаем указатель на переключатель, который стал включен после возникновения 
% события SelectionChangeFcn группы переключателей
hNew=evt.NewValue;
% Записываем в переменные OldColor и NewColor названия этих переключателей
OldColor=get(hOld,'String');
NewColor=get(hNew,'String');
% формируем массив строк с информацией о том, какой переключатель был включен 
% и какой стал включен
txt=char(strcat('Old Color: ', OldColor),strcat('New Color: ', NewColor));
% получаем структуру указателей на объекты приложения
handles=guidata(src);
% Выводим информацию о переключателях в текстовую область
set(handles.txtInfo,'String',txt)

Панель инструментов

В 7-ой версии MATLAB появилась возможность создавать панель инструментов, которая размещается вверху окна приложения. На панели инструментов могут находиться кнопки, кнопки-переключатели, причем группы кнопок и кнопок-переключателей можно отделять вертикальными линиями. На кнопке или кнопке-переключателе можно разместить любую цветную пиктограмму, размером не более чем 20 на 20 пикселей.

Панель инструментов создается при помощи функции uitoolbar, которая возвращает указатель на созданную панель. Кнопки создаются при помощи функции uipushtool, а кнопки переключатели с использованием функции uitoggletool. Первым аргументом этих функций может быть указатель на нужную панель инструментов, на которой следует разместить кнопки, а дальше входные аргументы указываются парами: 'НазваниеСвойства', значение.

Панели инструментов присутствуют в окне приложения только если его свойство WindowStyle имеет значение 'normal' или 'docked', т.е. для обычных окон, или встроенных окон. Если окно становится модальным, т.е. его свойство WindowStyle получает значение 'modal', то панели инструментов не отображаются в окне приложения, хотя по-прежнему являются его потомками и после изменения значения свойства WindowStyle на 'normal' или 'docked' становятся видимыми.

У панели инструментов есть свойство Children, значением которого является вектор-указателей на кнопки или кнопки-переключатели, размещенные на панели. Упорядочивая вектор указателей на кнопки или кнопки-переключатели, можно расположить их в нужном порядке (см. пример ниже). Свойство Parent панели инструментов содержит указатель на окно приложения. Свойство Type панели инструментов доступно только для чтения и всегда принимает значение 'uitoolbar'. Назначение остальных свойств панели инструментов: Visible, BeingDeleted, Tag, UserData, BusyAction, CreateFcn, DeleteFcn, Interruptible, HandleVisibility такое же, как и у остальных объектов.

Основные общие свойства кнопок и кнопок-переключателей, размещаемых на панелях инструментов, таковы:

CData - пиктограмма кнопки или кнопки-переключателя. Значением является трехмерный массив размеров n на m на 3, элементы этого массива задают цвет каждого пикселя пиктограммы в формате RGB. Каждое значение массива должно быть от 0 до 1. Всего размер пиктограммы допускается не более чем 20 на 20 пикселей, если он больше, то на кнопке или кнопке-переключателе размещается только его середина размеров 20 на 20 пикселей.

Separator - отделение кнопки или кнопки-переключателя от других кнопок при помощи вертикальной линии, которая помещается слева от кнопки или кнопки-переключателя. Значения

  • 'on' - рисовать линию
  • 'off' - не рисовать (по умолчанию)

Visible - видна или нет кнопка, или кнопка-переключатель. Значения

  • 'on' - видна (по умолчанию)
  • 'off' - не видна

Enable - доступна или нет кнопка или кнопка-переключатель. Значения

  • 'on' - доступна (по умолчанию)
  • 'off' - не доступна
  • 'inactive' - не активна

TooltipString - всплывающая подсказка. Значение - строка или строковая переменная с текстом подсказки.

Parent - указатель на панель инструментов, которой принадлежит кнопка или кнопка-переключатель. Изменяя значение этого свойства можно перемещать кнопку кнопку-переключатель с одной панели инструментов на другую (см. пример ниже).

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

Для кнопок-переключателей есть следующие свойства, которые служат для определения состояния кнопки-переключателя и задания выполняемых функций.

State - состояние кнопки-переключателя, которое принимает значения

  • 'on' - кнопка-переключатель включена
  • 'off' - кнопка-переключатель выключена (по умолчанию)

OnCallback - указатель на функцию или команда, которая должна выполняться после того, как кнопка-переключатель стала включена.

OffCallback - указатель на функцию или команда, которая должна выполняться после того, как кнопка-переключатель стала выключена.

ClickedCallback - указатель на функцию или команда, которая должна выполняться после того, как закончила выполнение функция, указанная в OnCallback или OffCallback. Функция, заданная в ClickedCallback всегда выполняется вне зависимости от того включена или нет кнопка-переключатель.

Назначение остальных свойств BeingDeleted, Tag, Type, UserData, BusyAction, CreateFcn, DeleteFcn, Interruptible и HandleVisibility такое же, как и для остальных объектов. Свойство Type для кнопок и кнопок-переключателей доступно только для чтения. Для кнопок оно принимает значение 'uipushtool', а для кнопок-переключателей - 'uitoggletool'.

Следующий пример демонстрирует создание окна с двумя панелями инструментов и тремя кнопками с красной, зеленой и синей пиктограммами, а так же упорядочение кнопок на панели инструментов и перемещение кнопки с одной панели инструментов на другую.

% создание графического окна без стандартного меню и панели инструментов
h=figure('MenuBar','none');
% создание двух панелей инструментов с указателями tbar1 и tbar2
tbar1=uitoolbar;
tbar2=uitoolbar;
% Заполнение трехмерных массивов R, G и B для красной, зеленой и синей пиктограмм
R(1:20,1:20,1) = ones(20); R(1:20,1:20,2) = zeros(20); R(1:20,1:20,3) = zeros(20);
G(1:20,1:20,1) = zeros(20); G(1:20,1:20,2) = ones(20); G(1:20,1:20,3) = zeros(20);
B(1:20,1:20,1) = zeros(20); B(1:20,1:20,2) = ones(20); B(1:20,1:20,3) = ones(20);
% Создание трех кнопок на первой панели инструменов
% кнопки имеют указатели btnR, btnG, btnB
btnR = uipushtool(tbar1,'CData',R)
btnG = uipushtool(tbar1,'CData',G)
btnB = uipushtool(tbar1,'CData',B)

После выполнения этих команд в графическом окне появляется две панели инструментов, верхняя панель инструментов содержит три кнопки.

Для изменения порядка следования кнопок на панели инструментов достаточно изменить порядок указателей на них в свойстве Children панели инструментов. Сделаем так, чтобы на первой панели инструментов сначала была синяя кнопка, затем зеленая и потом красная.

set(tbar1,'Children',[btnR btnG btnB])

Для переноса кнопки с одной панели инструментов на другую следует изменить значение ее свойства Parent на указатель на нужную панель инструментов. Перенесем, например, красную кнопку с верхней панели инструментов на нижнюю.

set(btnR,'Parent',tbar2) 

Для изменения порядка самих панелей инструментов следует изменить позиции указателей на них в векторе, который является значением свойства Children самого окна приложения. У окна приложения может быть достаточно много потомков, поэтому этот поиск и замену следует автоматизировать. Например, можно воспользоваться такой последовательностью операторов

% получаем вектор указателей на потомков графического окна
hc=get(h,'Children');
% ищем позиции указателей на панели инструментов и записываем их в k1 и k2
k1=find(hc==tbar1);
k2=find(hc==tbar2);
% изменяем положение указателей на панели инструментов в векторе hc
hc(k1)=tbar2;
hc(k2)=tbar1;
% устанавливаем обновленный вектор hc в качестве значения свойства Children окна 
set(h,'Children',hc)

Для размещения более содержательных пиктограмм на кнопках и кнопках-переключателях следует предварительно создать соответствующие графические файлы, а затем считать их в массив при помощи функции imread, которая возвращает трехмерный массив, указываемый затем как значение свойства CData кнопки или кнопки-переключателя.

Улучшения редактора меню (Menu Editor) среды GUIDE

Редактор меню среды GUIDE (который запускается из меню Tools, пункт Menu Editor) позволяет задать сочетание клавиш (с Ctrl) для быстрого доступа к меню и его пунктам. Для меню и пунктов меню можно задавать доступны они или нет (эквивалентно установки свойства Enable в 'on' или 'off''). Для задания всех свойств меню и его пунктов служит кнопка More options >>, которая открывает инспектор свойств. Для автоматической генерации функции обработки события пунктов меню предназначена кнопка View рядом со строкой ввода Callback редактора меню.

Улучшилась синхронизация редактора меню и инспектора свойств, изменения, сделанные в редакторе меню сразу же отображаются в инспекторе свойств и наоборот. Объекты, созданные в редакторе меню, автоматически отображаются в браузере объектов (Object Browser). Выбор объекта, входящего в меню, в редакторе меню приводит к тому, что в браузере объектов данный объект становится текущим и наоборот.

Если элементы управления размещены на панели или в группе переключателей, то их положение определяется по отношению к левому нижнему углу панели или группы переключателей (см. Панели и группы переключателей). Однако при изменении высоты панели или группы переключателей на заготовке окна приложения в среде GUIDE привязка их положения сделана к верхнему левому углу панели или группы переключателей.

Обработка нажатия клавиш для элементов управления

У объектов uicontrol появилось событие KeyPressFcn, которое позволяет задать функцию обработки нажатия клавиши, если объект находится в фокусе. Входными аргументами функции обработки события KeyPressFcn являются: указатель на кнопку и структура, поля которой имеют следующий смысл

  • Character - символ, соответствующий нажатому сочетанию клавиш
  • Modifier - была ли нажаты клавиши Ctrl, Shift или Alt. Значение - массив ячеек с именами нажатых клавиш
  • Key - нажатая клавиша

Например, при нажатии клавиш Shift и a значения полей будут следующими:

Character: 'A'
Modifier: {'shift'}
Key: 'a'

Таким образом можно сделать так, чтобы событие Callback кнопки, находящейся в фокусе, обрабатывалось не только при нажатии на пробел, но и на другую клавишу, скажем на Enter. Это и демонстрирует следующий пример простого приложения с графическим интерфейсом btnkey, в окне которого есть оси и кнопка Plot. После запуска приложения кнопка Plot находится в фокусе. Нажатие на нее мышью, пробелом или Enter приводит к одинаковому результату - построению столбцевой диаграммы вектора на осях. Для этого в функции btnOK_KeyPress обработки события KeyPressFcn проверяется, была ли нажата клавиша Enter и затем вызывается функция btnOK_Callback обработки события Callback кнопки Plot. Эта функция автоматически вызывается при нажатии пробела (когда кнопка в фокусе) или при нажатии на кнопку мышью. Построение столбцевой диаграммы вектора [1 2 3 2 1] происходит как раз в функции Callback.

function btnkey
% создание окна приложения без стандартного меню и панели инструментов
h=figure('MenuBar','none')
% создание кнопки Plot и задание функций обработки 
% ее событий Callback и KeyPressFcn
hb=uicontrol('Style','pushbutton','String','Plot',...
    'KeyPressFcn',@btnOK_KeyPress, 'Callback',@btnOK_Callback)
% создание осей
axes
% помещение кнопки Plot в фокус
uicontrol(hb)

% функция обработки события KeyPressFcn кнопки Plot
function btnOK_KeyPress(src,evt)
% evt является структурой с информацией о нажатой клавише или сочетании клавиш
if isequal(evt.Key,'return')
    % если нажат Enter, то вызываем функцию обработки события Callback кнопки Plot
    btnOK_Callback(src,[])
end

% функция обработки события Callback кнопки Plot
function btnOK_Callback(src,evt)
% строим столбцевую диаграмму вектора
bar([1 2 3 2 1])

Изменение в стандартном диалоговом окне questdlg

В стандартном диалоговом окне questdlg с кнопками, которое создается функцией questdlg, можно назначить фокус любой кнопке. Для этого следует повторить в последнем входном аргументе функции questdlg надпись на кнопке, которой следует передать фокус при создании стандартного диалогового окна запроса. Например, такое обращение к функции questdlg

choice = questdlg('Are you sure?', 'Warning', 'Yes', 'No', 'May be', 'May be')

приводит к появлению диалогового окнас заголовком Warning и текстом Are you sure, в котором в фокусе находится кнопка May be.

Нажатие клавиши пробел или Enter приведет к закрытию окна и возвращению надписи May be в строковом выходном аргументе choice функции questdlg:

choice =
May be

Если не указывать в последнем входном аргументе функции questdlg кнопку, которая должна получить фокус после создания стандартного диалогового окна запроса

choice=questdlg('Are you sure?', 'Warning', 'Yes', 'No', 'May be')

то выводится предупреждение о том, что последний входной аргумент не соответствует ни одной кнопке

Warning: Default string does not match any button string name.

и окно запроса создается без последней кнопки

Если же требуется создать стандартное диалоговое окно запроса, в котором ни одна кнопка не находится в фокусе, то лучше перед вызовом функции questdlg убрать вывод предупреждений при помощи команды warning, а после вызова questdlg снова включить вывод предупреждений в командное окно MATLAB:

warning off
choice=questdlg('Are you sure?', 'Warning', 'Yes', 'No', 'May be','')
warning on

Многострочная область ввода текста с полосой прокрутки

В 7-ой версии MATLAB многострочная область ввода текста снабжается полосой прокрутки (область становится многострочной, если разность между значениями свойств Max и Min области ввода текста больше единицы). У области ввода есть свойство SliderStep, значением которого является вектор из двух чисел, их значения определяют передвижение по области просмотра:

  • первое число отвечает за перемещение при щелчке по кнопкам со стрелками на полосе прокрутки, по умолчанию оно равно 0.01, т.е. происходит перемещение на один процент от всей области;
  • второе число отвечает за перемещение при щелчке по полосе прокрутки вне бегунка, по умолчанию оно равно 0.1, т.е. происходит перемещение на десять процентов от всей многострочной текстовой области.

Как и раньше, многострочная область ввода создается при помощи функции uicontrol при установке свойству Style создаваемого элемента управления значения edit.

Передача фокуса ввода объектам

Предположим, что в окне приложения с графическим интерфейсом пользователя размещено несколько областей ввода текста. После того, как пользователь ввел данные в одну область ввода и нажал клавишу Enter, требуется, чтобы курсор переместился в другую область ввода. Для этого нужно в обработке события Callback первой области ввода передать фокус ввода второй области ввода. В 7-ой версии усовершенствован интерфейс функции uicontrol, которую теперь можно вызывать с одним входным аргументом - указателем на объект, которому передается фокус ввода. В следующем примере приведено приложение focus с графическим интерфейсом пользователя, окно которого содержит три области ввода и кнопку OK. Сначала фокус ввода находится в первой области ввода текста, после ввода первого числа и нажатия Enter, фокус ввода передается второй области ввода, затем третьей, и после ввода данных в третью область и нажатия Enter фокус ввода получает кнопка OK. После нажатия на кнопку OK строится столбцевая диаграмма введенных данных.

function focus
h=figure('MenuBar','none'); % создание окна приложения
% создание первой области ввода и задание функции обработки ее события Callback
handles.edit1=uicontrol('Style','edit','Units','normalized',...
    'Position',[0.1 0.8 0.8 0.1],'BackgroundColor','w',...
    'Callback',@edit1_Callback);
% создание второй области ввода и задание функции обработки ее события Callback
handles.edit2=uicontrol('Style','edit','Units','normalized',...
    'Position',[0.1 0.6 0.8 0.1],'BackgroundColor','w',...
    'Callback',@edit2_Callback);
% создание третьей области ввода и задание функции обработки ее события Callback
handles.edit3=uicontrol('Style','edit','Units','normalized',...
    'Position',[0.1 0.4 0.8 0.1],'BackgroundColor','w',...
    'Callback',@edit3_Callback);
% создание кнопки OK и задание функции обработки ее события Callback
handles.btnOK=uicontrol('Style','pushbutton','Units','normalized',...
    'Position',[0.7 0.2 0.2 0.1],'String','OK',...
    'Callback',@btnOK_Callback);
% сохранение структуры с указателями на объекты приложения 
guidata(h,handles)
% установка фокуса ввода первой области ввода
uicontrol(handles.edit1)
% функция обработки события Callback первой области ввода
function edit1_Callback(src,evt)
% получаем структуру с указателями на объекты приложения
handles=guidata(src);
% передаем фокус ввода второй области ввода
uicontrol(handles.edit2);
% функция обработки события Callback второй области ввода
function edit2_Callback(src,evt)
% получаем структуру с указателями на объекты приложения
handles=guidata(src);
% передаем фокус ввода третьей области ввода
uicontrol(handles.edit3);
% функция обработки события Callback третьей области ввода
function edit3_Callback(src,evt)
% получаем структуру с указателями на объекты приложения
handles=guidata(src);
% передаем фокус ввода кнопке OK
uicontrol(handles.btnOK);
% функция обработки события Callback кнопки OK
function btnOK_Callback(src,evt)
% получаем структуру с указателями на объекты приложения
handles=guidata(src);
% записываем в a1, a2, a3 числа, введенные в области ввода
a1=str2num(get(handles.edit1,'String'));
a2=str2num(get(handles.edit2,'String'));
a3=str2num(get(handles.edit3,'String'));
% строим столбцевую диаграмму в отдельном окне
figure
bar([a1 a2 a3])

Выбор нескольких файлов в стандартном диалоговом окне открытия файлов, функция uigetfile

Функция uigetfile, создающая стандартное диалоговое окно открытия файла, теперь поддерживает опцию выбора нескольких файлов. Для этого ее следует вызвать таким образом

[FileName, PathName] = uigetfile(...,'MultiSelect', 'on')

Если в диалоговом окне открытия файла пользователь выбрал несколько файлов, то первый выходной аргумент FileName функции uigetfile является массивом ячеек, каждая ячейка которого содержит строку с именем выбранного файла. Второй выходной аргумент PathName функции uigetfile всегда является строкой, содержащей полный путь к каталогу с выбранными файлами, поскольку выбор нескольких файлов допускается только в одном каталоге.

В следующем примере демонстрируется использование опции 'MultiSelect' на примере открытия нескольких графических окон. Графические окна содержатся в файлах MATLAB с расширением fig, поэтому при создании диалогового окна открытия файла устанавливается соответствующий фильтр '*.fig' просмотра содержимого каталога. В заголовок диалогового окна открытия файла помещается строка 'Open Graph Files'. После того, как пользователь закрыл диалоговое окно, проверяется был ли сделан выбор файла или файлов (для этого значение FileName сравнивается с нулем. Если FileName не равно нулю, то возможно, что был выбран один файл (тогда переменная FileName содержит строку с именем выбранного файла) или несколько файлов (тогда FileName является массивом ячеек, каждая ячейка которого содержит строку с именем выбранного файла). В зависимости от этого либо открывается выбранный файл, либо в цикле в цикле формируется полное имя каждого файла при помощи функции strcat, которая сцепляет две строки:

  1. строку с путем к файлу, который содержится в переменной PathName
  2. строку с именем каждого файла, который содержится в k-ой ячейке массива FileName, для доступа к содержимому ячейки следует применять фигурные скобки при указании индекса.
[FileName, PathName] = uigetfile('*.fig','Open Graph Files','Multiselect','on')
if ~isequal(FileName,0)
    if iscell(FileName)
         for k=1:length(FileName)
             open(strcat(PathName,FileName{k}))
         end
    else
        open(strcat(PathName,FileName))
    end
end

Приостановка выполнения приложения на заданное время

В предыдущих версиях MATLAB функция uiwait служила для приостановления работы приложения. Если выполнялся оператор

uiwait(h)

то выполнение приостанавливалось до тех пор, пока не вызывалась

uiresume(h)

или окно, указатель на которое h не было удалено. Теперь в функции uiwait появился второй дополнительный входной аргумент, который задает время приостановки выполнения приложения в секундах. Например, после uiwait(h, 10) приложение продолжит работу через 10 секунд, или раньше, если будет выполнено uiresume(h), или окно с указателем h будет удалено.

Использование вложенных функций в приложениях GUI. Файл-функция для окна, возвращающая введенные в него параметры.

В 7-ой версии MATLAB появились вложенные функции (nested functions), которые удобно использовать, в частности, при написании приложений с графическим интерфейсом пользователя. Разберем сначала правила написания вложенных функций и несколько небольших примеров, демонстрирующих программирование вложенных функций.

Правила написания вложенных функций несложны:

  1. Вложенная функция находится внутри основной, ее заголовок начинается со слова function, а заканчивается она словом end.
  2. Вложенных функций может быть несколько внутри основной функции.
  3. Если в основной функции есть вложенные, то основная функция так же должна заканчиваться словом end.
  4. Вложенная функция может содержать одну или несколько вложенных функций.
  5. Внутри одной вложенной функции можно вызывать другую вложенную функцию.

Основная функция mainfun, содержащая вложенные функции nestfun1, nestfun2, имеет структуру, приведенную ниже:

function y=mainfun(x)
операторы основной функции
    
       function a=nestfun1(b)
       операторы вложенной функции
       end
    
       function c=nestfun2(d)
       операторы вложенной функции
       end
end

Вот простой пример, демонстрирующий использование вложенной функции, и альтернативный вариант с использованием подфункции

использование вложенной функции использование подфункций
function y=mainfun1(x)
% основная функция
y = nestfun(x^2);
    
    function b=nestfun(a)
    % вложенная функция
    b=a+2;
    end

end

>> y=mainfun1(3)
y =
    11
function y=mainfun2(x)
% основная функция
y=subfun(x^2);

function b=subfun(a)
% подфункция
b=a+2;

>> y=mainfun2(3)
y =
    11

В этом примере не чувствуется особой выгоды вложенных функций по сравнению с подфункциями и существенного различия между ними. Основное отличие вложенных функций от подфункций заключается в том, то переменные, определенные внутри основной функции, доступны во вложенных функциях и наоборот, переменные, определенные во вложенных функциях, доступны в основной.

Следующий пример показывает, что переменные основной функции видны во вложенной, а в подфункции они недоступны (в данном примере это переменная H).

использование вложенной функции использование подфункций
function y=mainfun1(x)
H=2;
y=nestfun(x^2);
    
    function b=nestfun(a)
    b=a+H;
    end

end

>> y=mainfun1(3)
y =
    11
function y=mainfun2(x)
H=2;
y=subfun(x^2);

function b=subfun(a)
b=a+H;

>> y=mainfun2(3)
??? Undefined function or variable 'H'.

Error in ==> mainfun2>subfun at 6
b=a+H;

Error in ==> mainfun2 at 3
y=subfun(x^2);

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

function y=mainfun3(x)
H=2; A=-10; B=-29;
y=nestfun(x^2);
A
B
    function B=nestfun(A)
    B=A+H;
    end
end

В основной функции mainfun3 значения переменных A и B не изменятся после вызова вложенной функции nestfun, поскольку для вложенной функции nestfun A является входным аргументом, а B - выходным аргументом. При вызове вложенной функции nestfun внутри основной функции на место входного аргумента A подставится x^2, во вложенной функции найдется значение выражения B=A+H и возвращаемый вложенной функцией nestfun результат запишется в переменную y основной функции mainfun3. В основной функции специально выводятся значения переменных A и B в командное окно для демонстрации вышесказанного:

>> y=mainfun3(3)
A =
   -10
B =
   -29
y =
    11

В справочной системе MATLAB информация о вложенных функциях находится в разделе MATLAB: Programming: Types of Functions: Nested Functions, где приводятся примеры использования вложенных функций, говорится об области видимости переменных основной функции и вложенных функций, а так же обсуждается использование указателей на вложенные функции.

То, что вложенным функциям доступны переменные, определенные в основной функции, позволяет достаточно просто программировать диалоговые окна, в которых пользователь должен вводить данные, устанавливать флаги, переключатели и т.д. После закрытия окна основная функция вернет введенные пользователем данные, состояние флагов, переключателей и т. д. Основная функция в данном случае, как правило, содержит операторы, создающие само окно и элементы управления, а вложенные функции обрабатывают события элементов управления диалогового окна.

Создадим основную функцию mydlg с несколькими вложенными функциями, обращение к которой

>> [x1,x2,flag]=mydlg(0.111,0.333,1)

приводит к появлению следующего диалогового окна Parameters, содержащего две области ввода, флаг и две кнопки:

Функция mydlg имеет три входных числовых аргумента: x1 и x2, значения которых сразу же отображаются в областях ввода X1= и X2= диалогового окна, и последний третий входной аргумент, который может принимать значения 0 или 1 и отвечает за то, должен ли при появлении диалогового окна быть установлен флаг optimize (если третий входной аргумент функции mydlg равен 1, то флаг optimize должен быть установлен, соответственно, если он равен 0, то флаг должен быть сброшен). В диалоговом окне пользователь вместо текущих значений X1= и X2= вводит новые, меняет состояние флага и по закрытии окна нажатием на кнопку OK новые установки возвращаются в выходных аргументах функции mydlg.

В основной функции mydlg создается:

  1. Диалоговое окно с заголовком Parameters, указатель на которое записывается в переменную hF.
  2. Области ввода текста с указателями hInputX1 и hInputX2, в которые заносятся значения x1 и x2 (от которых была вызвана функция mydlg). Числовые значения x1 и x2 преобразуются в строковые при помощи функции num2str.
  3. Две области статического текста, содержащие пояснения к областям ввода с надписями X1= и X2=.
  4. Флаг с именем optimize, состояние которого сразу же выбирается в зависимости от значения входного аргумента flag функции mydlg.
  5. Кнопка с надписью OK, для обработки события Callback которой служит вложенная функция OK_Callback.
  6. Кнопка с надписью Cancel, для обработки события Callback которой служит вложенная функция Cancel_Callback.

После создания диалогового окна Parameters со всеми элементами управления в основной функции mydlg вызывается функция uiwait, в ее входном аргументе задается указатель на окно hF. Это необходимо для приостановки работы функции mydlg, иначе функция закончит работу сразу после создания диалогового окна и возникнет ошибка, т.к. ее выходным аргументам не было присвоено никаких значений. Функция uiwait продолжает работу приложения когда окно будет закрыто, т.е. объект с указателем hF перестанет существовать. Но в нашем примере после вызова функции uiwait нет операторов в основной функции mydlg, поэтому она закончит работу, вернув соответствующие значения в выходных аргументах X1, X2 и FLAG.

Вложенная функция OK_Callback обработки события Callback кнопки OK считывает значения, введенные в области ввода (преобразуя строку, содержащую число, в число), записывает их в выходные аргументы X1 и X2 функции mydlg, узнает состояние флага и записывает в выходной аргумент FLAG функции mydlg либо 0 (если флаг сброшен), либо 1 (если флаг установлен). Как говорилось выше, так можно делать, поскольку во вложенной функции доступны переменные основной функции. После этого вложенная функция OK_Callback удаляет диалоговое окно Parameters.

Вложенная функция Cancel_Callback обработки события Callback кнопки Cancel присваивает выходным аргументам значения соответствующих входных аргументов, поскольку нажимая на кнопку Cancel пользователь решил отказаться от сделанных изменений. После этого вложенная функция Cancel_Callback удаляет диалоговое окно Parameters.

Текст основной функции mydlg с вложенными функциями OK_Callback и Cancel_Callback приведен ниже

function [X1,X2,FLAG]=mydlg(x1,x2,flag)
% основная функция, в которой создается окно и элементы управления

% создание окна, запись указателя на него в переменную hF
hF=figure('MenuBar','none', 'Position',[150 150 150 100],'NumberTitle','off',...
   	 'Name','Parameters')
              % создание статического текста 'X1=' 
uicontrol('Style','text','Position',[5 70 30 15],'String','X1=')
% создание области ввода для x1, запись в нее значения входного аргумента x1
% и  запись указателя на нее в переменную hInputX1
hInputX1=uicontrol('Style','edit','Position',[40 70 60 15],...
   	 'String',num2str(x1));
              % создание статического текста 'X2='              
uicontrol('Style','text','Position',[5 50 30 15],'String','X2=')
% создание области ввода для x2, запись в нее значения входного аргумента x2
% и  запись указателя на нее в переменную hInputX2
hInputX2=uicontrol('Style','edit','Position',[40 50 60 15],...
    'String',num2str(x2));
% создание флага, запись указателя на него в переменную hFlag
hFlag=uicontrol('Style','checkbox','Position',[5 30 80 15],...
    'String','optimize');
% установка или сброс флага в соответствии со значением входного аргумента flag
set(hFlag,'Value',flag)
% создание кнопки OK, запись указателя на нее в переменную hOK и связь 
% ее события Callback со вложенной функцией OK_Callback
hOK=uicontrol('Style','pushbutton','Position',[5 5 50 15],...
    'String','OK','Callback',@OK_Callback);
% создание кнопки Cancel, запись указателя на нее в переменную hCancel и связь 
% ее события Callback со вложенной функцией Cancel_Callback
hCancel=uicontrol('Style','pushbutton','Position',[65 5 50 15],...
    'String','Cancel','Callback',@Cancel_Callback);
% приостановка работы основной функции, пока существует диалоговое окно
uiwait(hF)
    
    function OK_Callback(src,evt)
    % вложенная функция для обработки нажатия на кнопку OK

    % считывание значений из областей ввода, преобразование их в числа 
    % и запись числовых значений  в выходные аргументы X1 и X2 функции mydlg
    X1=str2num(get(hInputX1,'String'));
    X2=str2num(get(hInputX2,'String'));
    % считывание состояния флага и запись его в выходной аргумент FLAG функции mydlg
    FLAG=get(hFlag,'Value');
    % удаление диалогового окна
    delete(hF)
    end

    function Cancel_Callback(src,evt)
    % вложенная функция для обработки нажатия на кнопку Cancel

   % отказ от всех изменений, записываем в выходные аргументы функции mydlg то, 
   % что было в ее входных аргументах
    X1=x1; X2=x2; FLAG=flag;
    % удаление диалогового окна
    delete(hF)
    end
end

У функции mydlg есть один недостаток - при закрытии диалогового окна Parameters при помощи кнопки с крестиком в правом верхнем углу (или Alt + F4) выводится сообщение о том, что одному или нескольким выходным аргументам не было присвоено значений.

??? One or more output arguments not assigned during call to 'C:\MATLAB7\work\mydlg.m (mydlg)'.

Исправление этой ошибки потребует программирования обработки события CloseRequestFcn окна, которое возникает при упомянутых выше способах закрытия диалогового окна Parameters. Для этого нужно немного модифицировать вызов функции figure в основной функции mydlg, установив свойству окна Parameters CloseRequestFcn значение указателя на вложенную функцию (назовем ее Figure_Close), которая должна выполниться перед закрытием окна.

% создание окна, запись указателя на него в переменную hF и связывание события 
% CloseRequestFcn с вложенной функцией Figure_Close.
hF=figure('MenuBar','none','WindowStyle','modal',...
    'Position',[150 150 150 100],'NumberTitle','off',...
    'Name','Parameters','CloseRequestFcn',@Figure_Close);

Кроме того, надо запрограммировать вложенную функцию Figure_Close. При закрытии диалогового окна Parameters кнопкой с крестиком в правом верхнем углу (или Alt + F4) функция mydlg должна возвращать старые значения параметров, т.е. должно выполняться то же самое, что и при нажатии пользователем на кнопку Cancel. Поэтому достаточно во вложенной функции Figure_Close выполнить всего одно действие, а именно вызвать другую вложенную функцию Cancel_Callback, которая как раз обрабатывает событие Callback кнопки Cancel:

function Figure_Close(src,evt)
% функция обработки закрытия окна

% делаем то же самое, что и при нажатии пользователем на кнопку Cancel
Cancel_Callback(src,evt)
end

После вышеописанных изменений диалоговое окно Parameters работает корректно за исключением того, что пользователь может случайно ввести не числа в область ввода и никакого сообщения об ошибке выведено не будет.

Улучшим функциональность диалогового окна Parameters. Разумеется, для надежной работы следует поставить проверку на то, что в каждой области ввода текста было введено одно число в верном формате, иначе при преобразовании строки в число при помощи функции str2num получится пустой массив (если было введено не число), или вектор (если были введены разделенные пробелами числа, или вместо точки для отделения десятичных знаков случайно была набрана запятая). Кроме того, для удобства ввода данных желательно, чтобы при появлении окна курсор находился в первой области ввода X1= (т.е. она была бы в фокусе), при нажатии на клавишу Enter фокус ввода передавался бы второй области ввода X2=, затем при следующем нажатии клавиши Enter в фокусе оказывался флаг optimize и после установки или сброса флага optimize (что можно делать клавишей пробел) фокус передается кнопке OK (см. разд. Передача фокуса ввода объектам). Сделаем также нажатие кнопки OK возможным при помощи клавиши Enter, а не только пробела (см. разд. Обработка нажатия клавиш для элементов управления).

Для реализации вышеперечисленного необходимо обработать событие Callback каждой области ввода текста, которое возникает, когда пользователь ввел данные и совершил одно из следующих действий:

  1. щелкнул мышью по другому объекту диалогового окна или просто по окну, либо
  2. нажал клавишу Enter.

Обработку событий Callback областей ввода текста запрограммируем во вложенных функциях InputX1_Callback и InputX2_Callback. Все, что нужно в них сделать, это передать фокус ввода нужному объекту, что выполняется при помощи функции uicontrol, во единственном входном аргументе которой должен быть указатель на нужный объект. Во вложенной функции InputX1_Callback поставим передачу фокуса ввода второй области ввода X2=, а во вложенной функции InputX2_Callback передадим фокус ввода флагу optimize.

Обработку события Callback флага optimize запрограммируем во вложенной функции Flag_Callback. В ней передадим фокус ввода кнопке OK.

Во вложенной функции OK_Callback, которая обрабатывает нажатие на кнопку OK, сделаем проверку на результат, возвращаемый функцией str2num, которая преобразует строку в число. Если в результате этого преобразования получился пустой массив или хотя бы один из размеров массива превысил единицу, то выведем стандартное диалоговое окно с сообщением об ошибочном вводе данных (которое создает функция errordlg), приостановим работу приложения mydlg пока пользователь не закроет это окно, удалим введенные пользователем неверные данные и передадим фокус в соответствующую область ввода. Если же преобразование строки в число прошло успешно, то диалоговое окно Parameters закрывается и основная функция mydlg передает введенные пользователем параметры в точку ее вызова.

Кроме вложенной функции OK_Callback, которая обрабатывает событие Callback кнопки OK, возникаемое при нажатии на нее мышью или клавишей пробел (когда кнопка в фокусе), понадобится функция для обработки события кнопки KeyPressFcn. Событие KeyPressFcn возникает, если кнопка находится в фокусе и пользователь нажимает любую клавишу или комбинацию клавиш. При этом информация о нажатой клавише передается во втором входном аргументе функции обработки события KeyPressFcn. Назовем эту вложенную функцию OK_KeyPressFcn. В ней сделаем проверку, была ли нажата клавиша Enter. Если пользователь нажал Enter, то во вложенной функции OK_KeyPressFcn следует всего лишь вызвать уже имеющуюся вложенную функцию OK_Callback, которая обрабатывает нажатие на кнопку OK.

Следует внести дополнения в аргументы функций uicontrol, вызываемых в основной функции mydlg для создания кнопки OK, областей ввода и флага. При создании кнопки OK функцией uicontrol необходимо связать с событием KeyPressFcn вложенную функцию OK_KeyPressFcn, при создании областей ввода связать с их событиями Callback вложенные функции InputX1_Callback и InputX2_Callback и при создании флага optimize связать его событие Callback с вложенной функцией Flag_Callback.

Вложенная функция Cancel_Callback для обработки события Callback кнопки Cancel остается без изменений.

Изменения в основной функции mydlg, модифицированная вложенная функция OK_Callback и новые вложенные функции InputX1_Callback, InputX2_Callback, Flag_Callback и OK_KeyPressFcn приведены ниже

function [X1,X2,FLAG]=mydlg(x1,x2,flag)
. . . 
% создание области ввода для x1, запись указателя на нее в переменную hInputX1 
% и связывание ее события Callback с вложенной функцией InputX1_Callback
hInputX1=uicontrol('Style','edit','Position',[40 70 60 15],...
    'String',num2str(x1),'Callback',@InputX1_Callback);
% создание области ввода для x2, запись указателя на нее в переменную hInputX2 
% и связывание ее события Callback с вложенной функцией InputX2_Callback
hInputX2=uicontrol('Style','edit','Position',[40 50 60 15],...
    'String',num2str(x2),'Callback',@InputX2_Callback);
% создание флага, запись указателя на него в переменную hFlag 
% и связывание его события Callback с вложенной функцией Flag_Callback
hFlag=uicontrol('Style','checkbox','Position',[5 30 80 15],...
    'String','optimize','Callback',@Flag_Callback);
% создание кнопки OK, запись указателя на нее в переменную hOK, связь ее события Callback 
% со вложенной функцией OK_Callback, а события KeyPressFcn с OK_KeyPressFcn
hOK=uicontrol('Style','pushbutton','Position',[5 5 50 15],...
    'String','OK','Callback',@OK_Callback, 'KeyPressFcn', @OK_KeyPressFcn);
% создание кнопки Cancel, запись указателя на нее в переменную hCancel и связь 
% ее события Callback со вложенной функцией Cancel_Callback
hCancel=uicontrol('Style','pushbutton','Position',[65 5 50 15],...
    'String','Cancel','Callback',@Cancel_Callback);
% передача фокуса первой области ввода
uicontrol(hInputX1)
% приостановка работы основной функции, пока существует диалоговое окно
uiwait(hF)

    function InputX1_Callback(src,evt)
    % вложенная функция обработки события Callback области ввода для x1

   % передаем фокус области ввода для x2
    uicontrol(hInputX2)
    end

    function InputX2_Callback(src,evt)
    % вложенная функция обработки события Callback области ввода для x2

   % передаем фокус флагу
    uicontrol(hFlag)
    end
       
    function Flag_Callback(src,evt)
    % вложенная функция обработки события Callback флага

   % передаем фокус кнопке OK
    uicontrol(hOK)
    end

    function OK_Callback(src,evt)
    % вложенная функция обработки события Callback кнопки OK

    % считываем содержимое области ввода для x1
    s=get(hInputX1,'String');
    % преобразуем строку в число, заносим его в выходной аргумент X1 функции mydlg
    X1=str2num(s);
    % проверяем, как прошло преобразование
    if isempty(X1) | max(size(X1)>1)
        % первое число преобразовалось неудачно, получен пустой массив или не одно число
        % выводим стандартное диалоговое окно с сообщением об ошибке
        herr=errordlg('You must input a number','Error');
        % приостанавливаем работу, пока пользователь не закроет его
        uiwait(herr)
        % удаляем содержимое первой области ввода 
        set(hInputX1,'String','')
        % передаем фокус первой области ввода 
        uicontrol(hInputX1)
    else 
    % первое число преобразовалось удачно
        % считываем содержимое области ввода для x2
        s=get(hInputX2,'String');
        % преобразуем строку в число, заносим его в выходной аргумент X2 функции mydlg
        X2=str2num(s);
        % проверяем, как прошло преобразование
        if isempty(X2) | max(size(X2)>1)
           % второе число преобразовалось неудачно, получен пустой массив или не одно число
            % выводим стандартное диалоговое окно с сообщением об ошибке
            herr=errordlg('You must input a number','Error');
            % приостанавливаем работу, пока пользователь не закроет его
            uiwait(herr)
            % удаляем содержимое второй области ввода 
            set(hInputX2,'String','')
            % передаем фокус второй области ввода 
            uicontrol(hInputX2)
        else
    % второе число преобразовалось неудачно
            % заносим состояние флага в выходной аргумент FLAG функции mydlg
            FLAG=get(hFlag,'Value');
            % пользователь ввел все верно, удаляем диалоговое окно
            delete(hF)
        end
    end
    end

    function OK_KeyPressFcn(src,evt)
    % вложенная функция обработки события KeyPressFcn кнопки OK

    if isequal(evt.Key,'return')
    % была нажата клавиша Enter
       % вызываем функцию обработки события Callback кнопки OK
        OK_Callback(src,[])
    end
    end
end

Для программирования функции, создающей диалоговое окно и возвращающей значения введенных пользователем параметров, не обязательно было применять вложенные функции. Разумеется, все то же самое можно было реализовать при помощи подфункций, но тогда пропала бы выгода от доступности переменных основной функции (указателей на созданные объекты, значений входных и выходных аргументов) во вложенных функциях. Для обмена данными между подфункциями пришлось бы пользоваться структурой, содержащей данные приложения, а также функцией guidata для получения этих данных в подфункциях и сохранения обновленной структуры с данными приложения. Функция guidata работает следующим образом.

guidata(object_handle, handles) - сохраняет структуру handles с данными приложения, где первый входной аргумент object_handle должен быть указателем на окно приложения или одного из его потомков.

handles = guidata(object_handle) - записывает в handles структуру с данными приложения, здесь входной аргумент object_handle так же должен быть указателем на окно приложения или одного из его потомков. В подфункциях обработки событий, которые как правило имеют два входных аргумента (выше мы их называли src и evt), первый входной аргумент src содержит указатель на объект, событие которого выполняется. Поэтому в подфункциях обработки событий элементов управления мы будем писать

 handles = guidata(src)

для получения структуры с данными приложения и

guidata(src, handles)

для сохранения структуры с данными приложения.

Приведем для примера функцию mydlg2 с подфункциями, которая работает точно так же, как и описанная выше функция mydlg, за исключением того, что в ней убрана проверка на вводимые значения параметров. Эта проверка может быть выполнена аналогично тому, как было сделано во вложенной функции OK_Callback основной функции mydlg.

В основной функции mydlg2 создается диалоговое окно и элементы управления, указатели на них записываются в поля структуры handles, которая сохраняется при помощи функции guidata. Затем вызывается функция uiwait для приостановки работы функции mydlg2. Продолжение работы функции mydlg2 возможно только в двух случаях:

  1. либо пользователь нажал кнопку OK и тогда в подфункции OK_Callback обработки события Callback кнопки OK вызывается uiresume (которая служит для продолжения работы после вызова функции uiwait);
  2. либо пользователь нажал кнопку Cancel или выбрал другой способ закрытия окна (Alt + F4, кнопка с крестиком в верхнем правом углу окна) и тогда в подфункции Cancel_Callback обработки события Callback кнопки Cancel вызывается uiresume.

К этому моменту в структуре handles уже есть поля X1, X2 и FLAG, которые содержат новые значения (если пользователь нажал кнопку OK), либо исходные, если пользователь выбрал другой способ закрытия окна для того, чтобы отклонить сделанные изменения. Значения этих полей записываются в выходные аргументы X1, X2 и FLAG функции mydlg2, окно приложения удаляется и функция mydlg2 завершает работу, возвращая значения заданных пользователем параметров X1, X2 и FLAG в точку вызова.

Текст функции mydlg2 с вложенными функциями приведен ниже.

function [X1,X2,FLAG]=mydlg2(x1,x2,flag)
% основная функция, в которой создается окно и элементы управления

% создание окна, запись указателя на него в поле hF структуры handles, связывание 
% события CloseRequestFcn с подфункцией Figure_Close
handles.hF=figure('MenuBar','none',... %'WindowStyle','modal',
    'Position',[150 150 150 100],'NumberTitle','off',...
    'Name','Parameters','CloseRequestFcn',@Figure_Close);
              % создание статического текста 'X1=' 
uicontrol('Style','text','Position',[5 70 30 15],'String','X1=')
% создание области ввода для x1, запись в нее значения входного аргумента x1
% и  запись указателя на нее в поле hInputX1 структуры handles, связывание события 
% Callback с подфункцией InputX1_Callback
handles.hInputX1=uicontrol('Style','edit','Position',[40 70 60 15],...
    'String',num2str(x1),'Callback',@InputX1_Callback);
               % создание статического текста 'X2='              
uicontrol('Style','text','Position',[5 50 30 15],'String','X2=')
% создание области ввода для x2, запись в нее значения входного аргумента x2
% и  запись указателя на нее в поле hInputX2 структуры handles, связывание события 
% Callback с подфункцией InputX2_Callback
handles.hInputX2=uicontrol('Style','edit','Position',[40 50 60 15],...
    'String',num2str(x2),'Callback',@InputX2_Callback);
% создание флага, запись указателя на него в поле hFlag структуры handles, связывание события 
% Callback с подфункцией Flag_Callback
handles.hFlag=uicontrol('Style','checkbox','Position',[5 30 80 15],...
    'String','optimize','Callback',@Flag_Callback);
% установка или сброс флага в соответствии со значением входного аргумента flag
set(handles.hFlag,'Value',flag)
% создание кнопки OK, запись указателя на нее в поле hOK структуры handles, связь 
% ее события Callback с подфункцией OK_Callback и события KeyPressFcn с OK_KeyPressFcn
handles.hOK=uicontrol('Style','pushbutton','Position',[5 5 50 15],...
    'String','OK','Callback',@OK_Callback, 'KeyPressFcn', @OK_KeyPressFcn);
% создание кнопки Cancel, запись указателя на нее в поле hCancel структуры handles и связь 
% ее события Callback с подфункцией Cancel_Callback
handles.hCancel=uicontrol('Style','pushbutton','Position',[65 5 50 15],...
    'String','Cancel','Callback',@Cancel_Callback);
% помещения первой области ввода в фокус
uicontrol(handles.hInputX1)
% сохранение структуры handles
guidata(handles.hF, handles)
% приостановка работы основной функции, пока не будет вызвана функция uiresume
uiwait(handles.hF)
% к этому моменту пользователь решил закрыть диалоговое окно
% получаем обновленную структуру handles
handles=guidata(handles.hF);
% записываем в выходные аргументы значения соответствующих полей структуры handles
X1=handles.X1;
X2=handles.X2;
FLAG=handles.FLAG;
% удаляем диалоговое окно
delete(handles.hF)


function InputX1_Callback(src,evt)
% подфункция обработки события Callback первой области ввода
% получаем структуру данных приложения
handles=guidata(src);
% передаем фокус второй области ввода
uicontrol(handles.hInputX2)

function InputX2_Callback(src,evt)
% подфункция обработки события Callback второй области ввода
% получаем структуру данных приложения
handles=guidata(src);
% передаем фокус флагу
uicontrol(handles.hFlag)

function Flag_Callback(src,evt)
% подфункция обработки события Callback флага
% получаем структуру данных приложения
handles=guidata(src);
% передаем фокус кнопке OK
uicontrol(handles.hOK)

function OK_Callback(src,evt)
% подфункция обработки события Callback кнопки OK
% получаем структуру данных приложения
handles=guidata(src);
% считываем данный из областей ввода, преобразуем их в числа 
% и записываем результат в поля X1 и X2 структуры handles
s=get(handles.hInputX1,'String');
handles.X1=str2num(s);
s=get(handles.hInputX2,'String');
handles.X2=str2num(s);
% записываем состояние флага в поле FLAG структуры handles
handles.FLAG=get(handles.hFlag,'Value');
% сохраняем структуру с данными приложения
guidata(src, handles)
% разрешаем продолжение работы основной функции
uiresume(handles.hF)
   

function OK_KeyPressFcn(src,evt)
% подфункция обработки события KeyPressFcn кнопки OK
if isequal(evt.Key,'return')
   % пользователь нажал клавишу Enter, вызываем подфункцию OK_Callback
    OK_Callback(src,[])
end

function Cancel_Callback(src,evt)
% подфункция обработки события Callback кнопки Cancel
% получаем структуру данных приложения
handles=guidata(src);
% записываем исходные значения параметров в поля X1, X2 и FLAG структуры handles
handles.X1=handles.x1; 
handles.X2=handles.x2; 
handles.FLAG=handles.flag;
% сохраняем структуру с данными приложения
guidata(src, handles)
% разрешаем продолжение работы основной функции
uiresume(handles.hF)

function Figure_Close(src,evt)
% подфункция обработки закрытия окна приложения
Cancel_Callback(src,evt)

Поиск по сайту:

Система Orphus

Яндекс.Метрика