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

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

Создание и программирование меню и контекстного меню

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

1. Меню File с пунктами:

1.1. пункт Open and Plot Data... (для выбора текстового файла с таблицей значений функции и построения ее графика на осях в окне приложения; многоточие в названии пункта меню говорит пользователю о том, что после выбора этого пункта сразу не будет выполнено никакое действие, а появится диалоговое окно для дальнейшей работы);
1.2. пункт Exit (для закрытия окна приложения).

2. Меню Grid с пунктами:

2.1. пункт XGrid с флагом (для включения или выключения сетки по оси X)
2.2. пункт YGrid с флагом (для включения или выключения сетки по оси Y)

Кроме этого, оси будут снабжены контекстным меню с пунктами:

  1. пункт XGrid с флагом (для включения или выключения сетки по оси X);
  2. пункт YGrid с флагом (для включения или выключения сетки по оси Y);

Понятно, что потребуется программирование согласованного поведения пунктов меню Grid и пунктов контекстного меню. Например, если включили сетку по оси x при помощи пункта XGrid контекстного меню, то соответственно должен быть включен флаг для пункта XGrid меню Grid, и наоборот.

На трех приведенных ниже скрин-шотах изображены: меню File с пунктами Open and Plot Data... и Exit, меню Grid с пунктами XGrid и YGrid, а также контекстное меню осей с пунктами XGrid и YGrid.


Рис. 1. Окно приложения myplotgui

Мы рассмотрим создание приложения с меню и контекстными меню как при помощи среды визуального программирования GUIDE (см. разделы Создание и программирование меню в среде GUIDE, Создание и программирование контекстного меню в среде GUIDE), так и без нее (см. разделы Создание и программирование меню при помощи функций, Создание и программирование контекстного меню при помощи функций).

Создание приложений с графическим интерфейсом в среде визуального программирования GUIDE описано в разд. Приложения с GUI, но можно читать про создание приложения с меню практически "с нуля", поскольку сначала кратко будут приведены необходимые сведения про работу в среде GUIDE.

Самостоятельное написание приложения с графическим интерфейсом без применения средств среды визуального программирования GUIDE разобрано в разд. Создание приложений с GUI без среды GUIDE.

Создание и программирование меню в среде GUIDE

Основные этапы создания приложений с графическим интерфейсом пользователя в среде GUIDE

Разработка приложения в среде визуального программирования GUIDE состоит из следующих этапов:

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

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

При создании элементов управления в окне приложения каждому из них задается некоторый тэг (имя) для обращения к этому элементу управления в подфункциях. Тэги, задаваемые автоматически в среде GUIDE, лучше изменять так, чтобы по тэгу легко было догадаться о назначении элемента управления. Например, при создании пункта XGrid меню Grid в примере, описанном в разд. Создание и программирование меню и контекстного меню, мы дадим пункту меню тэг mnGrid_XGrid, а при создании пункта XGrid контекстного меню мы дадим пункту меню тэг cmnAxes_XGrid. Следует отличать тэг объекта от надписи на нем. Тег в нашем случае - cmnAxes_XGrid, а надпись - XGrid.

При выборе пользователем пункта меню возникает его событие Callback и происходит обращение к соответствующей подфункции в m-файле. Ее имя состоит из двух частей, разделенных знаком подчеркивания: тэга и названия события. Например, при выборе пользователем пункта XGrid (с тэгом cmnAxes_XGrid) контекстного меню осей произойдет обращение к автоматически сгенерированной подфункции


Автоматически создаваемый заголовок подфункции

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

Для того, чтобы узнать, включил или выключил флаг пользователь, выбрав этот пункт меню, нам понадобится получить значение свойства Checked этого пункта. Для получения значения свойств объектов в MATLAB предназначена функция get. Ее первым входным аргументом является указатель на объект, значение свойства которого мы хотим получить, а во втором входном аргументе указывается название этого свойства, заключенное в апострофы:

state = get(hObject, 'Checked')

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

  • 'on' - флаг поставлен;
  • 'off' - флаг сброшен.

В зависимости от значения свойства Checked пункта меню мы и будем предпринимать дальнейшие действия при программировании обработки события, возникшего при выборе пользователем данного пункта меню.

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

 
handles.mnGrid_XGrid 

содержит указатель на пункт XGrid (с тэгом mnGrid_XGrid) меню Grid.

Для задания значения некоторому свойству объекта служит функция set, в ее первом входном аргументе записывается указатель на объект, во втором входном аргументе - название свойства в апострофах, а в третьем - значение свойства. Например:

set(handles.mnGrid_XGrid, 'Checked', 'off')

выключит флаг у пункта XGrid (с тэгом mnGrid_XGrid) меню Grid. Это все понадобится нам для программирования согласованного поведения элементов управления.

Запуск среды GUIDE создание заготовки окна приложения с осями и его сохранение

Для запуска среды визуального программирования GUIDE в командной строке MATLAB следует выполнить команду

>> guide

или нажать на кнопку GUIDE на панели инструментов основного окна MATLAB. При этом на экране появляется диалоговое окно GUIDE Quick Start с двумя вкладками Create New GUI (для создания нового приложения с графическим интерфейсом пользователя) и Open Existing GUI (для открытия уже существующего приложения и его редактирования).


Окно GUIDE Quick Start

Мы начнем с создания пустой заготовки для окна приложения, для чего на вкладке Create New GUI в списке GUIDE templates следует выбрать Blank GUI (Default) и нажать кнопку OK. После этого появляется окно среды визуального программирования GUIDE, изображенное ниже. Оно содержит:

  1. заготовку окна приложения;
  2. вертикальную панель инструментов для добавления элементов управления и объектов на заготовку окна приложения;
  3. меню и горизонтальную панель инструментов для доступа к средствам среды GUIDE (из них нам понадобится редактор меню и инспектор свойств).


Окно среды визуального программирования GUIDE

Разместим на заготовке окна оси, для чего надо на вертикальной панели инструментов щелкнуть по кнопке Axes и нарисовать их на заготовке окна приложения при помощи мыши (размеры и положение нарисованных осей можно изменять при помощи мыши).


Окно приложения с осями

Оси по умолчанию получили тэг axes1. В этом можно убедится, перейдя к свойствам осей в окне инспектора свойств. Для того, чтобы перейти к свойствам объекта, достаточно сделать по нему двойной щелчок. При этом открывается окно инспектора свойств Property Inspector. В первом столбце таблицы перечислены названия свойств, а во втором - их значения. Видим, что тэг осей - axes1.


Окно инспектора свойств со свойствами осей

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

Сохраним теперь созданное на данном этапе приложение. Для этого достаточно нажать на кнопку Save и задать имя приложению exmenu. Окно приложения сохраняется в файле exmenu.fig. Кроме этого в выбранном каталоге создается также файл exmenu.m, который сразу же открывается в окне редактора m-файлов. Он имеет следующую структуру

function varargout = exmenu(varargin)
% основная функция, инициализирующая приложение
…
% подфункции
function exmenu _OpeningFcn(hObject, eventdata, handles, varargin)
…
function varargout = exmenu _OutputFcn(hObject, eventdata, handles) 
…
% сюда будут добавляться заголовки автоматически создаваемых подфункций 
% для обработки событий от элементов управления.

Перейдем теперь к созданию меню при помощи редактора меню.

Создание меню в редакторе меню

Продолжим работу с приложением, начатую в предыдущем разделе Запуск среды GUIDE создание заготовки окна приложения с осями и его сохранение (вид окна приложения и его меню описаны в разделе Создание и программирование меню и контекстного меню). Добавим меню со следующими пунктами:

1. Меню File с пунктами:

1.1. пункт Open and Plot Data...
1.2. пункт Exit

2. Меню Grid с пунктами:

2.1. пункт XGrid
2.2. пункт YGrid

Для этого откроем редактор меню, выбрав в меню Tools среды GUIDE пункт Menu Editor (или нажав на кнопку Menu Editor) на горизонтальной панели инструментов среды GUIDE. При этом появляется окно редактора меню:


Окно редактора меню

Создадим меню File, для чего следует нажать на кнопку New Menu находясь на вкладке Menu Bar. Сначала на левой панели с иерархической структурой меню появляется меню Untitled1. Для задания его имени File и тега mnFile (смысл тэгов объяснен в разд. Основные этапы создания приложений с графическим интерфейсом пользователя в среде GUIDE) следует выделить при помощи мыши Untitled1 на левой панели с иерархической структурой меню. Тогда на правой панели со свойствами отображаются его свойства, значения которых и следует задать.

Зададим свойству Label значение File, а свойству Tag - значение mnFile. На следующем рисунке приведены основные элементы управления окна Menu Editor.


Элементы управления окна Menu Editor

Для быстрого выбора пункта меню можно в списке Accelerator задать сочетание клавиш <Ctrl> + <буквенная клавиша> (не нужно переопределять стандартные для Windows сочетания <Ctrl>+<c>, <Ctrl>+<v>, <Ctrl>+<x>) . Следует иметь ввиду, что сочетание клавиш задается только для тех пунктов меню, которые не имеют потомков (т.е. последние в иерархии). В нашем примере в меню File можно задавать сочетание клавиш для быстрого доступа к пунктам Open and Plot Data... и Exit.

Над пунктом меню можно поставить горизонтальную линию для формирования групп пунктов в меню. Для этого нужно установить флаг Separator above this item.

Если требуется пункт меню со включенным флагом (который сбрасывается или включается при каждом последующем выборе пользователем этого пункта), то следует установить флаг Check mark this item. Но тогда в самом начале работы приложения этот пункт будет со включенным флагом, что нам не нужно, т.к. сначала на осях не должно быть сетки. В разделе Программирование меню в среде GUIDE сказано, как программно выбирать состояние флага.

Для того, чтобы в работающем приложении меню или пункт был доступен, необходимо убедиться, что флаг Enable this item установлен.

В строке ввода Callback после нажатия кнопки View будет записана функция, которая вызывается при выборе пользователем соответствующего пункта меню. Вызывается основная функция приложения exmenu, которая затем вызывает подфункцию обработки события Callback выбранного меню или пункта меню. После нажатия кнопки View в редакторе меню заголовок соответствующей подфункции создается файле exmenu и выделяется в редакторе m-файлов. В нашем примере это заголовок

function mnFile_Callback(hObject, eventdata, handles)

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

Добавим теперь в меню File пункты Open and Plot Data... и Exit. Для этого на панели с иерархией меню в редакторе меню надо сделать меню File текущим при помощи щелчка мыши по нему и добавить пункт, нажав на кнопку New Menu Item. Для нового пункта надо задать свойству Label значение Open and Plot Data..., а свойству Tag - значение mnFile_OpenPlot. Для быстрого доступа зададим сочетание клавиш <Ctrl>+<O>.

Теперь надо добавить еще один пункт Exit в меню File. При добавлении пункта в редакторе меню надо делать текущим элемент меню более высокого уровня перед нажатием кнопки New Menu Item. Т.е. в нашем примере надо сделать текущим меню File. Новому пункту меню зададим для свойства Label значение Exit, а для свойства Tag - значение mnFile_Exit. Для быстрого доступа зададим сочетание клавиш <Ctrl>+<E>. Сгенерируем также для пункта Exit подфункцию обработки его события Callback.

В результате в m-файле должны появиться заголовки двух подфункции:

  • mnFile_OpenPlot_Callback - выполняется при выборе пользователем пункта Open and Plot Data... в меню File;
  • mnFile_Exit_Callback - выполняется при выборе пользователем пункта Exit в меню File.

Примечания

  1. Иерархию пунктов и порядок можно изменять при помощи кнопок с горизонтальными и вертикальными стрелками на панели инструментов редактора меню. Для передвижения выделенного пункта меню или меню по иерархии вниз или вверх применяются кнопки Move Selected Item Backward и Move Selected Item Forward, а для перемещения вверх или вниз по списку - кнопки Move Selected Item Up и Move Selected Item Down.
  2. Для удаления выделенного пункта меню или меню служит кнопка Delete Selected Item.

Осталось добавить меню Grid с пунктами XGrid и YGrid. Для добавления нового меню следует нажать на кнопку New Menu (не важно, что при этом выделено: меню или пункт) и действовать аналогично вышеописанному.

Дадим следующие тэги:

  1. для меню Grid - тэг mnGrig;
  2. для пункта XGrid - тэг mnGrig_XGrid;
  3. для пункта YGrid - тэг mnGrig_YGrid;

В результате в m-файле должны появиться заголовки двух подфункции:

  • mnGrid_XGrid_Callback - выполняется при выборе пользователем пункта XGrid в меню Grid;
  • mnGrid_YGrid_Callback - выполняется при выборе пользователем пункта YGrid в меню Grid;

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


Иерархическая структура меню

Если теперь на панели инструментов среды GUIDE нажать кнопку Run, то запустится наше приложение exmenu, в нем можно раскрывать меню и выбирать их пункты. Разумеется, пока происходить ничего не будет. Осталось запрограммировать действия, которые должны выполняться при выборе пунктов меню пользователем.

Программирование меню в среде GUIDE

В этом разделе объясняется как запрограммировать созданные в предыдущем разделе пункты меню (см. раздел Создание меню в редакторе меню).

При выборе в меню File пункта Open and Plot Data... должно появляться стандартное диалоговое окно открытия файла. Для вывода такого окна используем готовую функцию uigetfile (см. разд. Диалоговое окно открытия файла - функция uigetfile). В случае, если пользователь выбрал файл с данными, они должны отображаться на графике на осях в окне приложения. Будем считать, что в текстовом файле с данными есть два столбца, в которых, соответственно, записаны значения независимой переменной и табличной функции. Кроме того, поскольку мы будем использовать высокоуровневую графическую функцию plot для вывода графика данных, которая переназначает свойства осей (в том числе убирает сетку, если она есть), то надо проверить, установлены ли флаги у соответствующих пунктов XGrid и YGrid меню Grid и при необходимости добавить линии сетки.

При выборе пункта Exit в меню File приложение следует закрыть.

При выборе пункта XGrid следует в меню Grid следует действовать в зависимости от состояния флага рядом с названием этого пункта:

  • если флаг сброшен, то его следует установить и нанести линии координатной сетки для оси абсцисс;
  • если флаг установлен, то его надо сбросить и убрать линии координатной сетки для оси абсцисс.

Аналогично, при выборе пункта YGrid следует в меню Grid следует действовать в зависимости от состояния флага рядом с названием этого пункта:

  • если флаг сброшен, то его надо установить и нанести линии координатной сетки для оси ординат;
  • если флаг установлен, то его надо сбросить и убрать линии координатной сетки для оси ординат.

Ниже приведены соответствующие подфункции для обработки событий пунктов меню.

function mnFile_OpenPlot_Callback(hObject, eventdata, handles)
% обработка события Callback пункта Open and Plot Data... меню File

% открываем диалоговое окно для выбора файла с данными, 
% имя файла записывается в Fname, а путь к нему в PName
 [FName,PName]=uigetfile('*.txt');
% проверяем, был ли выбран файл
if ~isequal(FName,0)
    % пользователь выбрал файл, формируем его полное имя Name, сцепляя путь с именем.
    Name=strcat(PName,FName);
    % считываем данные и записываем их в вектора x и y
    A=load(Name);
    x=A(:,1);
    y=A(:,2);
    % делаем текущими оси с тэгом axes1, указатель на них в handles.axes1
    axes(handles.axes1)
    % строим график маркерами
    plot(x,y,'o')
    % получаем состояние флага у пункта XGrid меню Grid
    xGridState=get(handles.mnGrid_XGrid,'Checked')
   % если он установлен, то делаем сетку по x
    if isequal(xGridState,'on')
        set(handles.axes1,'XGrid','on')
    end
    % получаем состояние флага у пункта YGrid меню Grid
    yGridState=get(handles.mnGrid_YGrid,'Checked')
   % если он установлен, то делаем сетку по y
    if isequal(yGridState,'on')
        set(handles.axes1,'YGrid','on')
    end
end

Примечания

  1. У нас всего одна пара осей в окне приложения, они же и являются текущими, поэтому команда axes(handles.axes1) не является обязательной (функция axes делает текущими те оси, указатель на которые передается в ее входном аргументе, именно на текущие оси производится вывод графическими функциями). Однако, если бы в графическом окне были две пары осей, скажем с тегами axes1 и axes2, то перед графическим выводом надо было бы сделать нужную пару осей текущими при помощи функции axes: axes(handles.axes1) или axes(handles.axes2).
  2. Поскольку у свойств 'XGrid' оси и 'Checked' пункта меню могут быть одинаковые значения, то можно не проверять состояние пункта меню операторами
    if isequal(xGridState,'on')
        set(handles.axes1,'XGrid','on')
    end

а сразу написать

set(handles.axes1,'XGrid',xGridState)

Аналогично можно сделать и для 'XGrid'.

function mnFile_Exit_Callback(hObject, eventdata, handles)
% обработка события Callback пункта Exit меню File

% удаляем графическое окно, его тэг figure1, а указатель на него в handles.figure1
delete(handles.figure1)

function mnGrid_XGrid_Callback(hObject, eventdata, handles)
% обработка события Callback пункта XGrid меню Grid

% проверяем текущее состояние флага у пункта XGrid
xGridState=get(hObject,'Checked');
if isequal(xGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт XGrid
    % добавляем сетку по оси x
    set(handles.axes1,'XGrid','on')
    % устанавливаем флаг
    set(hObject,'Checked','on')
else
    % флаг был установлен, но пользователь выбрал  пункт XGrid
    % убираем сетку по оси x
    set(handles.axes1,'XGrid','off')
    % сбрасываем флаг
    set(hObject,'Checked','off')
end

function mnGrid_YGrid_Callback(hObject, eventdata, handles)
% обработка события Callback пункта YGrid меню Grid

% проверяем текущее состояние флага у пункта YGrid
yGridState=get(hObject,'Checked');
if isequal(yGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт YGrid
    % добавляем сетку по оси y
    set(handles.axes1,'YGrid','on')
    % устанавливаем флаг
    set(hObject,'Checked','on')
else
    % флаг был установлен, но пользователь выбрал  пункт YGrid
    % убираем сетку по оси y
    set(handles.axes1,'YGrid','off')
    % сбрасываем флаг
    set(hObject,'Checked','off')
end

После программирования приведенных выше подфункций обработки событий пунктов меню приложение exmenu работает верно. Сетка зависит только от состояния флагов пунктов XGrid и YGrid меню Grid (см. рисунок ниже), данные считываются из файла и отображаются маркерами, выбор пункта Exit в меню File приводит к закрытию приложения.


Связь пунктов меню Grid и сетки

Создание и программирование контекстного меню в среде GUIDE

Снабдим наше простое приложение exmenu, работа которого описана в разд. Создание и программирование меню и контекстного меню, контекстным меню осей. В этом контекстном меню будет два пункта XGrid и YGrid с флагами, выбор которых приводит к добавлению или удалению линий координатной сетки по оси абсцисс и ординат, соответственно. Кроме того, пункты контекстного меню осей и пункты меню Grid должны вести себя согласованно. Если при включении (выключении) линий сетки при помощи пункта контекстного меню рядом с его названием ставится (снимается) флаг, то флаг также должен появиться (сброситься) и рядом с названием соответствующего пункта меню Grid.

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

  1. Создать контекстное меню вместе с его пунктами в редакторе меню среды GUIDE, дать им имена и теги и, при необходимости установить флаги и горизонтальные разделители между группами пунктов меню.
  2. Связать контекстное меню с объектом окна приложения, установив тег контекстного меню в качестве значения свойства UIContextMenu объекта.
  3. Запрограммировать события Callback пунктов контекстного меню в автоматически создаваемых подфункциях m-функции приложения. Событие Callback пункта контекстного меню возникает при его выборе пользователем. При программировании пунктов контекстного меню нам понадобится их свойство Checked. Установка его значения в 'on' приводит к появлению флага рядом с пунктом меню, а в 'off' - к сбрасыванию флага.

Для создания контекстного меню следует в меню Tools среды GUIDE выбрать пункт Menu Editor…, что приводит к появлению редактора меню. В редакторе меню надо перейти на вкладку Context Menus и при помощи кнопки New Context Menu создать контекстное меню. Для добавления в него пунктов служит кнопка New Menu Item.

Примечание

В целом, создание контекстного меню в редакторе меню не отличается от создания обычного меню (см. раздел Создание меню в редакторе меню). Для изменения иерархической структуры служат кнопки Move Selected Item Backward (повысить уровень) и Move Selected Item Forward (понизить уровень). Перемещение вверх или вниз пункта меню производится при помощи кнопок Move Selected Item Up и Move Selected Item Down. Удаление ненужного пункта меню или меню осуществляется нажатием на кнопку Delete Selected Item.

На правой панели в окне редактора меню вводятся имя контекстного меню и имена и тэги его пунктов. Введем следующие имена и тэги:

  • для контекстного меню - имя cmnAxes;
  • для пункта XGrid - имя XGrid и тэг cmnAxes_XGrid;
  • для пункта YGrid - имя YGrid и тэг cmnAxes_YGrid.

В результате должно получиться так, как показано на рисунке ниже


Создание контекстного меню в редакторе меню

Контекстное меню создано. Для связывания его с осями следует перейти к свойствам осей в окне инспектора свойств, для чего достаточно сделать двойной щелчок по осям в основном окне среды GUIDE. В окне инспекторе свойств для свойства UIContextMenu осей необходимо установить значение тега контекстного меню, т.е. cmnAxes, выбрав его из раскрывающегося списка справа от названия свойства.

Осталось запрограммировать события Callback пунктов контекстного меню и модифицировать подфункции обработки события Callback пунктов XGrid и YGrid меню Grid. Для перехода к автоматически создаваемой подфункции обработки события пунктов меню и контекстного меню достаточно выделить этот пункт в окне редактора свойств и нажать на кнопку View.

В подфункциях обработки событий Callback пунктов контекстного меню следует:

  1. Проверить текущее состояние флага.
  2. В зависимости от состояния флага убрать или добавить сетку и сбросить или установить флаг у пункта контекстного меню и отвечающего ему пункта меню Grid.

Ниже приведены подфункции cmnAxes_XGrid_Callback и cmnAxes_YGrid_Callback обработки событий Callback пунктов контекстного меню XGrid и YGrid.

function cmnAxes_XGrid_Callback(hObject, eventdata, handles)
   % обработка события Callback пункта XGrid контекстного меню

   % проверяем текущее состояние флага у пункта XGrid
xGridState=get(hObject,'Checked');
if isequal(xGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт XGrid
    % добавляем сетку по оси x
    set(handles.axes1,'XGrid','on')
    % устанавливаем флаг у пункта XGrid контекстного меню
    set(hObject,'Checked','on')
    % устанавливаем флаг у пункта XGrid меню Grid
    set(handles.mnGrid_XGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт XGrid
       % убираем сетку по оси x
    set(handles.axes1,'XGrid','off')
    % сбрасываем флаг пункта XGrid контекстного меню
    set(hObject,'Checked','off')
    % сбрасываем флаг пункта XGrid  меню Grid
    set(handles.mnGrid_XGrid,'Checked','off')    
end


function cmnAxes_YGrid_Callback(hObject, eventdata, handles)
   % обработка события Callback пункта YGrid контекстного меню

   % проверяем текущее состояние флага у пункта YGrid
yGridState=get(hObject,'Checked');
if isequal(yGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт YGrid
    % добавляем сетку по оси y
    set(handles.axes1,'YGrid','on')
    % устанавливаем флаг у пункта YGrid контекстного меню
    set(hObject,'Checked','on')
    % устанавливаем флаг у пункта YGrid меню Grid
    set(handles.mnGrid_YGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт YGrid
       % убираем сетку по оси y
    set(handles.axes1,'YGrid','off')
    % сбрасываем флаг пункта YGrid контекстного меню
    set(hObject,'Checked','off')
    % сбрасываем флаг пункта YGrid  меню Grid
    set(handles.mnGrid_YGrid,'Checked','off')    
end

Ниже приведены измененные подфункции mnAxes_XGrid_Callback и mnAxes_YGrid_Callback обработки событий Callback пунктов XGrid и YGrid меню Grid, описанные в разделе Программирование меню в среде GUIDE. В них добавлена установка или сброс флага у пункта контекстного меню при выборе соответствующего пункта меню.

function mnAxes_XGrid_Callback(hObject, eventdata, handles)
   % обработка события Callback пункта XGrid меню Grid

   % проверяем текущее состояние флага у пункта XGrid
xGridState=get(hObject,'Checked');
if isequal(xGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт XGrid
    % добавляем сетку по оси x
    set(handles.axes1,'XGrid','on')
    % устанавливаем флаг у пункта XGrid  меню Grid
    set(hObject,'Checked','on')
    % устанавливаем флаг у пункта XGrid контекстного меню 
    set(handles.cmnGrid_XGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт XGrid
       % убираем сетку по оси x
    set(handles.axes1,'XGrid','off')
    % сбрасываем флаг пункта XGrid  меню Grid
    set(hObject,'Checked','off')
    % сбрасываем флаг пункта XGrid  контекстного меню
    set(handles.сmnGrid_XGrid,'Checked','off')    
end

function mnAxes_YGrid_Callback(hObject, eventdata, handles)
   % обработка события Callback пункта YGrid меню Grid

   % проверяем текущее состояние флага у пункта YGrid
yGridState=get(hObject,'Checked');
if isequal(yGridState,'off')
    % флаг был сброшен, но пользователь выбрал  пункт YGrid
    % добавляем сетку по оси y
    set(handles.axes1,'YGrid','on')
    % устанавливаем флаг у пункта YGrid  меню Grid
    set(hObject,'Checked','on')
    % устанавливаем флаг у пункта YGrid контекстного меню 
    set(handles.cmnGrid_YGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт YGrid
       % убираем сетку по оси y
    set(handles.axes1,'YGrid','off')
    % сбрасываем флаг пункта YGrid  меню Grid
    set(hObject,'Checked','off')
    % сбрасываем флаг пункта YGrid  контекстного меню
    set(handles.сmnGrid_YGrid,'Checked','off')    
end

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

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

Обработка события от одинаковых пунктов меню и контекстного меню в одной подфункции

Поскольку выбор пункта меню Grid и соответствующего пункта контекстного меню должен приводить к одинаковым действиям, то можно для обработки событий Callback пункта XGrid меню Grid и пункта XGrid контекстного меню написать одну подфункцию. Назовем ее XGrid_set. Аналогично для обработки событий Callback пункта YGrid меню Grid и пункта YGrid контекстного меню напишем функцию YGrid_set. Эти функции добавим в качестве подфункций в основную функцию приложения exmenu, находящуюся в файле exmenu.m.

В функциях XGrid_set и YGrid_set надо проверить состояние флага того объекта, событие Callback которого выполняется, и в зависимости от этого установить (сбросить) флаги у пунктов XGrid меню Grid и контекстного меню и добавить (убрать) линии сетки по оси абсцисс.

function XGrid_set(hObject, eventdata, handles)
   % обработка события Callback пункта XGrid меню Grid или контекстного меню

   % проверяем текущее состояние флага у пункта XGrid
xGridState=get(hObject,'Checked');
if isequal(xGridState,'off')
       % флаг был сброшен, но пользователь выбрал  пункт XGrid
       % добавляем сетку по оси x
    set(handles.axes1,'XGrid','on')
    % устанавливаем флаг у пункта XGrid  контекстного меню
    set(handles.cmnAxes_XGrid,'Checked','on')
    % устанавливаем флаг у пункта XGrid  меню Grid
    set(handles.mnGrid_XGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт XGrid
       % убираем сетку по оси x
    set(handles.axes1,'XGrid','off')
    % сбрасываем флаг пункта XGrid  контекстного меню
    set(handles.cmnAxes_XGrid,'Checked','off')    
    % сбрасываем флаг пункта XGrid  меню Grid
    set(handles.mnGrid_XGrid,'Checked','off')    
end

function YGrid_set(hObject, eventdata, handles)
   % обработка события Callback пункта YGrid меню Grid или контекстного меню

   % проверяем текущее состояние флага у пункта YGrid
yGridState=get(hObject,'Checked');
if isequal(yGridState,'off')
       % флаг был сброшен, но пользователь выбрал  пункт YGrid
       % добавляем сетку по оси y
    set(handles.axes1,'YGrid','on')
    % устанавливаем флаг у пункта YGrid  контекстного меню
    set(handles.cmnAxes_YGrid,'Checked','on')
    % устанавливаем флаг у пункта YGrid  меню Grid
    set(handles.mnGrid_YGrid,'Checked','on')
else
       % флаг был установлен, но пользователь выбрал  пункт YGrid
       % убираем сетку по оси y
    set(handles.axes1,'YGrid','off')
    % сбрасываем флаг пункта YGrid  контекстного меню
    set(handles.cmnAxes_YGrid,'Checked','off')    
    % сбрасываем флаг пункта YGrid  меню Grid
    set(handles.mnGrid_YGrid,'Checked','off')    
end

Кроме программирования подфункций XGrid_set и YGrid_set необходимо сделать так, чтобы они вызывались при возникновении соответствующих событий, т.е. при выборе пользователем меню или пункта меню. Для этого необходимо в редакторе меню для пунктов XGrid и YGrid меню Grid и контекстного меню в строке ввода Callback внести изменения. Например, для пункта XGrid меню Grid сейчас в строке ввода Callback стоит вызов основной функции

exmenu('mnAxes_XGrid_Callback ',gcbo,[],guidata(gcbo))

Изменим его на

exmenu('XGrid_set',gcbo,[],guidata(gcbo))

Аналогичную операцию выполним для пункта XGrid контекстного меню. Для пункта YGrid меню Grid содержимое строки ввода Callback

exmenu('mnAxes_YGrid_Callback ',gcbo,[],guidata(gcbo))

изменим на

exmenu('YGrid_set ',gcbo,[],guidata(gcbo))

Теперь при выборе пользователем пункта XGrid в меню Grid или в контекстном меню осей будет вызываться подфункция XGrid_set, а при выборе YGrid в меню Grid или в контекстном меню осей - YGrid_set.

Создание и программирование меню при помощи функций

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

Создание и программирование контекстного меню без среды GUIDE описано в разделе Создание и программирование контекстного меню при помощи функций.

Один из способов быстрой разработки многооконных приложений с привлечением среды визуального программирования GUIDE только для создания диалоговых окон и самостоятельным программированием приложения в отдельной функции описан в разделе Быстрая разработка графического интерфейса.

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

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

  • меню File с пунктами Open and Plot Data... (для выбора текстового файла, чтения из него числовых данных и их визуализации) и меню Exit (для завершения работы приложения);
  • меню Grid с пунктами XGrid и YGrid (каждый выбор которых приводит к появлению или исчезновению линий координатной сетки по осям абсцисс и ординат, соответственно).


Меню приложения

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

Использование функции uimenu

Одна и та же функция uimenu служит как для создания меню приложения, так и пунктов меню или подменю. Если требуется создать меню, например File, то функция uimenu вызывается следующим образом (свойство Label отвечает за название меню):

mnFile = uimenu('Label', 'File');

Функция uimenu возвращает указатель на созданное меню File (про указатели на графические объекты MATLAB говорится в разделе Текущий графический объект; указатели на объекты). Во входных аргументов функции uimenu могут быть не только свойство Label и его значение, но и пары: 'НазваниеСвойства', значение, 'НазваниеСвойства', значение,… Свойства меню и их возможные значения описаны в разделе Свойства меню.

Далее, для создания пункта меню или подменю следует вызвать функцию uimenu, указав в качестве ее первого входного аргумента указатель на само меню, полученный при его создании, а далее пары 'НазваниеСвойства', значение:

mnOpenPlot = uimenu(mnFile,'Label','Open and Plot Data...');

В переменной mnOpenPlot возвращается указатель на пункт Open and Plot Data... меню File. Как и при создании меню, при создании пункта меню или подменю во входных аргументов функции uimenu можно указывать пары: 'НазваниеСвойства', значение, 'НазваниеСвойства', значение, … (см. раздел Свойства меню).

Аналогично при помощи функции uimenu создаются и подпункты (пункты подменю), только в этом случае первым входным аргументом функции uimenu должен быть указатель на тот пункт меню, для которого требуется создать подпункт.

При создании меню в процессе разработки приложения с графическим интерфейсом пользователя следует иметь в виду, что функция uimenu добавляет новое меню справа к стандартным меню графического окна MATLAB: File, Edit, View, Insert, Tools, Desktop, Windows, Help. Т.е. последовательность операторов

figure
mnFile = uimenu('Label','File'); 

приведет к тому, что после стандартного меню Help появится новое меню File. Для того, чтобы убрать стандартную строку меню следует при создании графического окна его свойству Menubar установить значение 'off':

figure('MenuBar','none')
mnFile = uimenu('Label','File');

Примечание
Свойства графических окон описаны в разделе Свойства графических окон.

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

  1. при создании меню или пункта меню установить его свойству Callback в качестве значения указатель на подфункцию обработки события (или команду MATLAB), которое возникает при выборе пользователем данного пункта меню;
  2. если значением свойства Callback является указатель на подфункцию, то требуется создать ее и запрограммировать в ней нужные действия.

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

  • окно приложения;
  • оси;
  • меню File с пунктами Open and Plot Data... и Exit;
  • меню Grid с пунктами XGrid и YGrid.

Графическое окно создается функцией figure, входными аргументами которой могут быть пары: 'НазваниеСвойства', значение. При создании графического окна свойству MenuBar устанавливается значение 'none' для того, чтобы в окне приложения не было стандартной для графического окна MATLAB строки меню и панели инструментов.

При создании в графическом окне осей функцией axes, входными аргументами которой так же могут быть пары: 'НазваниеСвойства', значение, их свойству 'NextPlot' устанавливается значение 'replacechildren' для того, чтобы при выводе графиков высокоуровневой функцией plot свойства осей не принимали принятые по умолчанию значения (например, чтобы сохранялись линии сетки). Свойства осей подробно описаны в разделе "Объект Axes (оси)".

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

  • для пункта Open and Plot Data... меню File - подфункция OpenPlot_Callback;
  • для пункта XGrid меню Grid - подфункция XGrid_Callback;
  • для пункта YGrid меню Grid - подфункция YGrid_Callback;

Значением свойства Callback как правило является указатель на подфункцию, который в MATLAB обозначается при помощи символа @.

Значением свойства Callback меню или пункта меню (и любого графического объекта) может быть не только указатель на функцию обработки события, но и команда MATLAB, заключенная в апострофы. В качестве примера, для обработки события Callback пункта Exit меню File указана команда delete(gcf). Сама функция delete уничтожает графический объект, указатель на который передан в ее входном аргументе, а функция gcf возвращает указатель на текущее графическое окно, т.е. как раз на окно приложения exmenu.

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

Опишем программирование подфункций.

Программирование подфункций обработки событий Callback пунктов меню

В подфункции OpenPlot_Callback обработки события Callback пункта Open and Plot Data... меню File вызывается функция uigetfile, которая приводит к появлению стандартного диалогового окна открытия файла. (Функции MATLAB для стандартных диалоговых окон описаны в разделе Стандартные диалоговые окна). В ее входном аргументе в качестве фильтра файлов указано расширение txt, а два выходных строковых аргумента FName и PName содержат, соответственно, имя выбранного пользователем файла с данными вместе с расширением и полный путь к файлу.

Если пользователь закрыл диалоговое окно открытия файла при помощи кнопки Cancel, т.е. не выбрал файл, то значение переменной FName равно нулю. Поэтому после вызова функции uigetfile делается проверка на равенство нулю переменной FName. Если файл был выбран, то из строковых переменных FName и PName формируется полное имя файла сцеплением строк с использованием функции strcat. Сформированное полное имя файла записывается в строковую переменную Name. Текстовые данные считываются из этого файла функцией load в массив A, причем предполагается, что данные в текстовом файле записаны в два столбца, в первом из них - значения аргумента, а во втором - соответствующие значения табличной функции, например:

0.1   1.1
0.2   0.8
0.3   2.1
0.4   2.2

Далее значения первого столбца массива A заносятся в вектор x, а второго столбца - в вектор y. Считанная из текстового файла табличная функция визуализируется маркерами при помощи функции plot.

Подфункции XGrid_Callback и YGrid_Callback, обрабатывающие события Callback пунктов XGrid и YGrid меню Grid программируются практически одинаково. Пункты XGrid и YGrid должны быть снабжены флагами, которые включаются и сбрасываются при последовательных выборах этих пунктов меню пользователем. Для того, чтобы добавить флаг рядом с названием пункта меню следует установить его свойству Checked значение 'on', а для сброса флага, соответственно, значение 'off'. Поэтому в начале каждой из этих подфункций в переменную state заносится текущее состояние флага рядом с названием пункта меню. Значение любого свойства объекта может быть получено при помощи функции get. Ее первым входным аргументом является указатель на объект (в нашем случае указатель на пункт меню содержится во входном аргументе src функции обработки события Callback пункта меню). Второй аргумент функции get является названием требуемого свойства, значение которого она и возвращает.

Далее, если флаг был сброшен, то он устанавливается рядом с названием пункта меню. Установка свойству графического объекта некоторого значения производится при помощи функции set, ее первым входным аргументом является указатель на объект. Во втором аргументе функции set указывается название свойства (за наличие флага отвечает свойство Checked пункта меню), а в третьем - значение 'on' (для свойства Checked значение может быть 'on' или 'off'). После установки флага рядом с названием пункта меню на оси наносятся линии координатной сетки по нужному направлению (по оси абсцисс или ординат, в зависимости от того, какая из подфункций XGrid_Callback или YGrid_Callback выполняется). Для нанесения линий координатной сетки используются свойства осей XGrid или YGrid, значения которых могут быть 'on' или 'off'. Указатель на текущие оси возвращается функцией gca, он и является первым входным аргументом функции set, а во втором и третьем ее входных аргументах задаются название свойства и его значение.

Если флаг был установлен, то он сбрасывается и удаляются соответствующие линии сетки.

Примечание
Использование функций set и get описано в разделе Доступ к значениям свойств графических объектов.

Ниже приведена основная функция приложения exmenu вместе с подфункциями обработки событий Callback пунктов меню.

function exmenu
% основная функция приложения exmenu 

% создание графического окна без строки меню и панели инструментов
figure('MenuBar','none')
% создание осей
axes('NextPlot','replacechildren')
% создание меню File
mnFile=uimenu('Label','File');
% создание пункта Open and Plot Data... меню File и связывание с его событием Callback 
% функции OpenPlot_Callback
mnOpenPlot=uimenu(mnFile,'Label','Open and Plot Data...','Callback',@OpenPlot_Callback);
% создание пункта Exit меню File и связывание с его событием Callback 
% команды удаления окна приложения
mnExit=uimenu(mnFile,'Label','Exit','Callback','delete(gcf)');
% создание меню Grid
mnGrid=uimenu('Label','Grid');
% создание пункта XGrid меню Grid и связывание с его событием Callback 
% функции XGrid_Callback
mnXGrid=uimenu(mnGrid,'Label','XGrid','Callback',@XGrid_Callback);
% создание пункта YGrid меню Grid и связывание с его событием Callback 
% функции YGrid_Callback
mnYGrid=uimenu(mnGrid,'Label','YGrid','Callback',@YGrid_Callback);

function OpenPlot_Callback(src,evt)
% подфункция обработки события Callback пункта Open and Plot Data... меню File

% открываем диалоговое окно для выбора файла с данными, 
% имя файла записывается в Fname, а путь к нему в PName
 [FName,PName]=uigetfile('*.txt');
% проверяем, был ли выбран файл
if ~isequal(FName,0)
    % пользователь выбрал файл, формируем его полное имя Name, сцепляя путь с именем.
    Name=strcat(PName,FName);
    % считываем данные и записываем их в вектора x и y
    A=load(Name);
    x=A(:,1);
    y=A(:,2);
    % визуализируем данные маркерами
    plot(x,y,'o')
end

function XGrid_Callback(src, evt)
% подфункция обработки события Callback пункта XGrid меню Grid
% в src - указатель на пункт меню XGrid

% записываем в state состояние флага рядом с названием пункта меню XGrid
state=get(src,'Checked')
% проверяем, установлен или сброшен флаг
if isequal(state,'off')
    % флаг сброшен, устанавливаем его и добавляем сетку по оси x
    set(src,'Checked','on')
    set(gca,'XGrid','on')
else
    % флаг установлен, сбрасываем его и убираем сетку по оси x
    set(src,'Checked','off')
    set(gca,'XGrid','off')
end

function YGrid_Callback(src, evt)
% подфункция обработки события Callback пункта YGrid меню Grid
% в src - указатель на пункт меню YGrid

% записываем в state состояние флага рядом с названием пункта меню YGrid
state=get(src,'Checked')
% проверяем, установлен или сброшен флаг
if isequal(state,'off')
    % флаг сброшен, устанавливаем его и добавляем сетку по оси y
    set(src,'Checked','on')
    set(gca,'YGrid','on')
else
    % флаг установлен, сбрасываем его и убираем сетку по оси y
    set(src,'Checked','off')
    set(gca,'YGrid','off')
end

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

Свойства меню

Для получения информации о свойствах меню и пунктов меню и их значениях достаточно перейти к разделу справочной системы MATLAB, посвященному функции uimenu, создающей меню и его пункты

>> doc uimenu

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

Accelerator - сочетание клавиш для быстрого доступа к меню или пункту меню. Значением свойства Accelerator может быть символ. Если задан, например символ 'o', то сочетание клавиш <Crtl>+'o' приведет к выполнению подфункции обработки события этого пункта меню. Сочетание клавиш может быть назначено только тем меню, которые не имеют пунктов, или тем пунктам, которые не имеют подпунктов, т.е. тем элементам меню, выбор которых пользователем приводит не к раскрытию меню или подменю, а непосредственно к выполнению некоторой подфункции обработки события Callback.

Примечание
Не следует переопределять стандартные сочетания клавиш Windows: <Ctrl>+'c', <Ctrl>+'v', <Ctrl>+'x'.

В нашем приложении exmenu (см. Создание и программирование меню при помощи функций) при создании, например, пункта Open and Plot Data... меню File можно назначить для быстрого доступа к этому пункту сочетание клавиш <Crtl>+'o', задав пару 'Accelerator', 'o' во входных аргументах функции uimenu:

mnOpenPlot=uimenu(mnFile,'Label','Open and Plot Data...',
'Callback',@OpenPlot_Callback,...'Accelerator','o');

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

 
set(mnOpenPlot,  'Accelerator', '')

Label - название меню или пункта меню. Значением свойства Label является строка. Для быстрого перехода к пункту меню без использования мыши или клавиш со стрелками можно назначить данному пункту символьную клавишу. Для этого перед соответствующим символом в строке с названием меню следует поставить символ &. В работающем приложении этот символ выводится подчеркнутым в названии пункта меню. В приложении exmenu (см. Создание и программирование меню при помощи функций) можно было поступить следующим образом:

mnOpenPlot=uimenu(mnFile,'Label','&Open and Plot Data...','Callback',@OpenPlot_Callback,...
    'Accelerator','o');
mnExit=uimenu(mnFile,'Label','E&xit','Callback','delete(gcf)');

Теперь при нажатии клавиши Alt в работающем приложении происходит переход к меню, а при раскрытии меню клавишей <?> или <Enter> его пункты можно быстро выбирать при помощи клавиш <o> и <x>.

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

Enable - доступно или нет меню или пункт меню. Значения: 'on' (по умолчанию, доступно) 'off' (недоступно).

Checked - установлен или нет флаг рядом с названием пункта меню. Значения 'on' (установлен), 'off' (сброшен).

Пример программирования обработки события Callback пункта меню с использованием его свойства Checked приведен в подфункции XGrid_Callback (см. Программирование подфункций обработки событий Callback пунктов меню).

Примечание
Для меню и подменю свойство Checked не используется. Его имеет смысл задавать только для пунктов меню.

Separator - вывод горизонтальной линии для отделения групп пунктов меню и подменю. Значения: 'on' (над данным пунктом меню или подменю рисуется горизонтальная линия), 'off' (линия убирается).

Visible - виден или нет меню или пункт меню. Значения: 'on' (по умолчанию, виден), 'off' (не виден).

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

Position - положение меню в строке меню, или пунктов в меню. Используется для переупорядочения меню и его пунктов. Более подробно про переупорядочение меню сказано в следующем разделе Переупорядочение пунктов меню.

Parent - указатель на меню или подменю, которому принадлежит данный пункт, т.е. предок пункта меню в иерархии графических объектов MATLAB (сведения об иерархии графических объектов MATLAB содержатся в разделе Иерархия графических объектов).

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

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

Tag - тэг (уникальное имя) меню, подменю или пункта меню. Тэги используются для доступа к свойствам объектов приложения (для получения и изменения значений свойств объектов приложения), чаще всего в подфункциях обработки различных событий других объектов. Значением свойства Tag является строка. Более подробно про использование тэгов меню, подменю и пунктов меню говорится в разделе Создание и программирование контекстного меню при помощи функций, где приведен пример приложения с меню и контекстным меню, требующий согласованного поведения некоторых пунктов как меню, так и контекстного меню.

Переупорядочение пунктов меню

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

За порядок меню в строке меню приложения и пунктов меню в самом меню отвечает их свойство Position. Значением свойства Position является число, причем единица соответствует крайнему левому положению меню в строке меню, или самому верхнему положению пункта меню в списке пунктов меню.

Например, если в приложении было создано два меню File и Grid

figure('MenuBar','none')
mnFile=uimenu('Label','File');
mnGrid=uimenu('Label','Grid');

то они расположатся в строке меню слева направо в порядке создания. После присвоения двойки свойству Position меню File

set(mnFile, 'Position',2)

меню File и Grid поменяются местами.

Аналогично свойство Position используется и для пунктов меню. Если для меню Grid созданы два пункта XGrid и YGrid

mnXGrid=uimenu(mnGrid,'Label','&XGrid','Callback',@XGrid_Callback);
mnYGrid=uimenu(mnGrid,'Label','&YGrid','Callback',@YGrid_Callback);

то они расположатся в списке пунктов меню сверху вниз в порядке создания. После присвоения двойки свойству Position меню XGrid

set(mnXGrid, 'Position',2)

пункты XGrid и YGrid поменяются местами.

Меню приложения имеют иерархическую структуру, в которой предком меню является графическое окно, а потомками меню - подменю и пункты меню. Аналогично и для подменю, его потомками являются пункты меню и, возможно, снова подменю. Для каждого меню, подменю или пункта меню значением его свойства Parent является указатель на предка, а значение свойства Children содержит вектор указателей на его потомков. Ясно, что у пунктов меню нет потомков, а следовательно, значением их свойства Children является пустой массив. Сведения об иерархической структуре графических объектов MATLAB изложены в разделе Иерархия графических объектов).

Приведем пример перестройки иерархической структуры меню с использованием свойства Parent. Предположим, что при помощи функции uimenu было создано меню Menu с пятью пунктами Item1, Item2, ... , Item5.

figure('MenuBar','none')
mnMenu=uimenu('Label','Menu');
mnItem1=uimenu(mnMenu,'Label','Item 1');
mnItem2=uimenu(mnMenu,'Label','Item 2');
mnItem3=uimenu(mnMenu,'Label','Item 3');
mnItem4=uimenu(mnMenu,'Label','Item 4');
mnItem5=uimenu(mnMenu,'Label','Item 5');

Тогда структура меню Menu выглядит так, как приведено на рисунке ниже:


Исходная структура меню Menu

Теперь сделаем предком пунктов Item 3 и Item 4 пункт Item 2 (при этом пункт Item 2 станет подменю)

set(mnItem3,'Parent',mnItem2)
set(mnItem4,'Parent',mnItem2)

Тогда иерархическая структура меню Menu станет такой, как показано на рисунке ниже


Измененная структура меню Menu

Свойства Children и Parent можно использовать и для переноса пунктов меню из одного меню приложения в другое и для переносов меню из одного окна в другое окно. Достаточно получить указатели на них и сделать пункты, подменю или меню потомком нужного графического объекта (потомком графического окна для меню и меню для пункта).

Создание и программирование контекстного меню при помощи функций

Для создания контекстного меню служит функция uicontextmenu, которая возвращает указатель на контекстное меню. Пункты контекстного меню создаются при помощи функции uimenu. Так же как и при создании пунктов обычного меню (см. раздел Использование функции uimenu) первым входным аргументом функции uimenu является указатель, но только теперь не на меню, а на контекстное меню, возвращаемый функцией uicontextmenu. После создания контекстного меню вместе с его пунктами следует связать контекстное меню с тем объектом, для которого оно предназначено. У объектов есть свойство UIContextMenu, в качестве его значения следует задать указатель на контекстное меню, возвращаемый функцией uicontextmenu.

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

В основной функции приложения exmenu кроме создания графического окна, осей и меню вместе с его пунктами теперь добавим создание контекстного меню и его пунктов, а также свяжем контекстное меню с осями. При создании пунктов контекстного меню XGrid и YGrid назначим пока для обработки их события Callback те же самые функции, что и для пунктов XGrid и YGrid меню Grid, т.е. XGrid_Callback и YGrid_Callback, соответственно, поскольку при выборе этих пунктов меню и контекстного меню должны выполняться одни и те же действия (далее мы увидим, что для согласованной работы пунктов XGrid и YGrid меню Grid и пунктов XGrid и YGrid контекстного меню в основную функцию exmenu и ее подфункции обработки событий потребуется внести некоторые изменения).

function exmenu
   % основная функция приложения exmenu 

    % создание графического окна без строки меню и панели инструментов
figure('MenuBar','none')
   % создание осей
hA=axes('NextPlot','replacechildren') 
   % создание меню File
mnFile=uimenu('Label','File');
   % создание пункта Open and Plot Data... меню File и связывание с его событием Callback 
   % функции OpenPlot_Callback
mnOpenPlot=uimenu(mnFile,'Label','Open and Plot Data...','Callback',@OpenPlot_Callback,...
    'Accelerator','o');
   % создание пункта Exit меню File и связывание с его событием Callback 
   % команды удаления окна приложения
mnExit=uimenu(mnFile,'Label','Exit','Callback','delete(gcf)');
   % создание меню Grid
mnGrid=uimenu('Label','Grid');
   % создание пункта XGrid меню Grid и связывание с его событием Callback 
   % функции XGrid_Callback
mnXGrid=uimenu(mnGrid,'Label','XGrid','Callback',@XGrid_Callback);
   % создание пункта YGrid меню Grid и связывание с его событием Callback 
   % функции YGrid_Callback
mnYGrid=uimenu(mnGrid,'Label','YGrid','Callback',@YGrid_Callback);
% создание контекстного меню
cmnAxes=uicontextmenu;
   % создание пункта XGrid контекстного меню и связывание с его событием Callback 
   % функции XGrid_Callback
cmnXGrid=uimenu(cmnAxes,'Label','XGrid','Callback',@XGrid_Callback);
   % создание пункта YGrid контекстного меню и связывание с его событием Callback 
   % функции YGrid_Callback
cmnYGrid=uimenu(cmnAxes,'Label','YGrid','Callback',@YGrid_Callback);
% связывание контекстного меню с осями
set(hA,'UIContextMenu',cmnAxes)

Больше пока никаких изменений вносить не будем и убедимся, что контекстное меню работает верно. Однако, пункты XGrid и YGrid меню Grid и пункты XGrid и YGrid контекстного меню несогласованны. При нанесении, например, линий сетки по оси x при помощи контекстного меню она добавляется, но если открыть меню Grid, то видно, что рядом с его пунктом XGrid флаг отсутствует, хотя при наличии линий сетки по оси x он должен быть. Первый выбор пункта XGrid меню Grid не приводит к исчезновению линий сетки по оси x, а только устанавливает флаг рядом с ним. Только второй выбор пункта XGrid меню Grid приводит к исчезновению линий координатной сетки по оси x. Аналогично обстоит дело с пунктами контекстного меню, если линии сетки были добавлены при помощи пунктов меню Grid.

Для обеспечения согласованного поведения пунктов меню требуется внести изменения как в основную функцию приложения exmenu, так и в подфункции XGrid_Callback и YGrid_Callback обработки события пунктов XGrid и YGrid контекстного меню и меню Grid. Основное изменение состоит в том, что при обработке события, например, пункта XGrid меню Grid необходимо изменить значение свойства Checked пункта XGrid контекстного меню и наоборот. Аналогично и для пункта YGrid. Т.е. в подфункции обработки события Callback одного объекта требуется получить доступ к свойствам другого объекта.

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

mnXGrid=uimenu(mnGrid,'Label','XGrid','Callback',@XGrid_Callback,'Tag','mnXGrid');

Для доступа к свойствам объектов приложения необходимо знать указатели на эти объекты. Этого можно добиться при помощи свойства Tag объектов. В данном примере пункт XGrid меню Grid получил тэг mnXGrid. В подфункции обработки события Callback пункта меню вызывается функция guihandles, которая возвращает структуру с указателями на объекты приложения, причем названия полей этой структуры совпадают с тэгами объектов, т.е. после обращения

handles=guihandles;

указатель на пункт XGrid меню Grid содержится в поле mnXGrid структуры handles. Поле структуры в MATLAB отделяется точкой от имени структуры, т.е. для доступа к содержимому поля следует писать handles.mnXGrid.

Примечание
Если тип данных структуры Вам не знаком, то можно почитать здесь краткие сведения о работе со структурами в пакете MATLAB.

Далее, для изменения значений свойств пункта XGrid меню Grid достаточно использовать функцию set, указав handles.mnXGrid в качестве ее первого входного аргумента и перечислив пары 'НазваниеСвойства', значение, 'НазваниеСвойства', значение, в остальных входных аргументах. Ниже приведена измененная основная функция приложения exmenu вместе с модифицированными подфункциями, которая обеспечивает согласованное поведение пунктов меню Grid и контекстного меню. В принципе, не обязательно было при создании всех объектов приложения задавать им тэги. Мы будем использовать только тэги четырех объектов: пунктов XGrid и YGrid меню Grid и контекстного меню.

function exmenu
   % основная функция приложения exmenu 

    % создание графического окна без строки меню и панели инструментов с тэгом mainwin
hF=figure('MenuBar','none','Tag','mainwin')
   % создание осей с тэгом mainwin
hA=axes('NextPlot','replacechildren','Tag','mainax')
   % создание меню File с тэгом mnFile
mnFile=uimenu('Label','File','Tag','mnFile');
   % создание пункта Open and Plot Data... меню File с тэгом mnOpenPlot 
   % и связывание с его событием Callback функции OpenPlot_Callback
mnOpenPlot=uimenu(mnFile,'Label','Open and Plot Data...','Callback',@OpenPlot_Callback,...
    'Tag','mnOpenPlot');
   % создание пункта Exit меню File с тэгом mnExit 
   % и связывание с его событием Callback команды удаления окна приложения
mnExit=uimenu(mnFile,'Label','Exit','Callback','delete(gcf)','Tag','mnExit');
   % создание меню Grid с тэгом mnGrid
mnGrid=uimenu('Label','Grid','Tag','mnGrid');
   % создание пункта XGrid меню Grid с тэгом mnXGrid 
   % и связывание с его событием Callback функции XGrid_Callback
mnXGrid=uimenu(mnGrid,'Label','XGrid','Callback',@XGrid_Callback,'Tag','mnXGrid');
   % создание пункта YGrid меню Grid с тэгом mnYGrid 
   % и связывание с его событием Callback функции YGrid_Callback
mnYGrid=uimenu(mnGrid,'Label','YGrid','Callback',@YGrid_Callback,'Tag','mnYGrid');
% создание контекстного меню с тэгом cmnAxes
cmnAxes=uicontextmenu('Tag','cmnAxes');
   % создание пункта XGrid контекстного меню с тэгом cmnXGrid  
   % и связывание с его событием Callback  функции XGrid_Callback
cmnXGrid=uimenu(cmnAxes,'Label','XGrid','Callback',@XGrid_Callback,'Tag','cmnXGrid');
   % создание пункта YGrid контекстного меню с тэгом cmnYGrid  
   % и связывание с его событием Callback  функции YGrid_Callback
cmnYGrid=uimenu(cmnAxes,'Label','YGrid','Callback',@YGrid_Callback,'Tag','cmnYGrid');
% связывание контекстного меню с осями
set(hA,'UIContextMenu',cmnAxes)

function OpenPlot_Callback(src,evt)
% подфункция обработки события Callback пункта Open and Plot Data... меню File

% открываем диалоговое окно для выбора файла с данными, 
% имя файла записывается в Fname, а путь к нему в PName
 [FName,PName]=uigetfile('*.txt');
% проверяем, был ли выбран файл
if ~isequal(FName,0)
    % пользователь выбрал файл, формируем его полное имя Name, сцепляя путь с именем.
    Name=strcat(PName,FName);
    % считываем данные и записываем их в вектора x и y
    A=load(Name);
    x=A(:,1);
    y=A(:,2);
    % визуализируем данные
    plot(x,y,'o')
end

function XGrid_Callback(src, evt)
   % подфункция обработки события Callback пункта XGrid меню Grid и контекстного меню

% получаем структуру с указателями на объекты приложения
handles=guihandles;
   % записываем в state состояние флага рядом с названием пункта меню XGrid
state=get(src,'Checked') 
   % проверяем, установлен или сброшен флаг
if isequal(state,'off')
       % флаг сброшен, устанавливаем его для пунктов XGrid меню Grid и контекстного меню
    set(handles.mnXGrid,'Checked','on')
    set(handles.cmnXGrid,'Checked','on')    
       % добавляем сетку по оси x
    set(gca,'XGrid','on')
else
       % флаг установлен, сбрасываем его для пунктов XGrid меню Grid и контекстного меню
    set(handles.mnXGrid,'Checked','off')
    set(handles.cmnXGrid,'Checked','off')    
       % убираем сетку по оси x
    set(gca,'XGrid','off')
end

function YGrid_Callback(src, evt)
   % подфункция обработки события Callback пунктов YGrid меню Grid и контекстного меню

% получаем структуру с указателями на объекты приложения
handles=guihandles;
   % записываем в state состояние флага рядом с названием пункта меню YGrid
state=get(src,'Checked')
   % проверяем, установлен или сброшен флаг
if isequal(state,'off')
      % флаг сброшен, устанавливаем его для пунктов YGrid меню Grid и контекстного меню
    set(handles.mnYGrid,'Checked','on')
    set(handles.cmnYGrid,'Checked','on')    
       % добавляем сетку по оси y
    set(gca,'YGrid','on')
else
       % флаг установлен, сбрасываем его для пунктов YGrid меню Grid и контекстного меню
    set(handles.mnYGrid,'Checked','off')
    set(handles.cmnYGrid,'Checked','off')    
       % убираем сетку по оси y
    set(gca,'YGrid','off')
end

В модифицированном приложении exmenu пункты XGrid и YGrid меню Grid и контекстного меню работают согласованно и флаги для соответствующих пунктов меню сбрасываются или устанавливаются синхронно вне зависимости от того, к пункту меню или контекстного меню обратился пользователь:


Согласованное поведение пунктов меню и контекстного меню


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

Система Orphus

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