Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛАБ № 5 Создание приложений с GUI без среды GU...doc
Скачиваний:
14
Добавлен:
24.11.2019
Размер:
471 Кб
Скачать
☆

Обмен данными между функциями обработки событий. Обработка событий объектов, создаваемых приложением.

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

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

Обсудим эти вопросы на примере приложения plotlines, окно которого приведено на рис. 5.

Рис. 5. Окно приложения plotlines

Приложение plotlines содержит оси, область ввода для задания функции в соответствиями с правилами MATLAB и кнопку, нажатие на которую приводит к построению графика введенной функции на отрезке [-1,1]. График каждой новой функции добавляется на оси. Приложение plotlines запоминает все введенные формулы и при щелчке мышью по любой линии на осях в области ввода появляется соответствующая ей формула.

В основной функции приложения создаются:

  • окно приложения с тегом win;

  • оси c тегом axMain и свойством NextPlot, установленным в add, для добавления линий;

  • кнопка с тегом btnPlot и функцией BtnPlotCallback обработки события Callback;

  • область ввода текста с тегом edtFun.

Указатели на объекты приложения plotlines хранятся в структуре handles, которая создается в конце основной функции приложения при помощи функции guihandles. Напомним, что названия полей структуры handles совпадают с тегами объектов, т.е. handles.win содержит указатель на графическое окно приложения, handles.axMain - на оси, handles.btnPlot - на кнопку и handles. edtFun - на область ввода текста (не все указатели могут понадобиться, однако, лучше всегда при создании объектов приложения давать им уникальные теги).

Затем в структуру handles добавляется два поля:

  • Funs - для хранения введенных формул в массиве ячеек, каждая ячейка содержит строку с формулой;

  • Lines - для хранения указателей на построенные линии в векторе.

Начальными значениями этих полей должны быть пустые массивы: handles.Funs - пустой массив ячеек {}, handles.Lines - пустой числовой массив []. После добавления полей Funs и Lines в структуру handles и инициализации их значений вызывается функция guidata для сохранения структуры handles.

В функции BtnPlotCallback обработки события Callback кнопки вызывается функция guidata для записи в handles структуры данных приложения. Входным аргументом функции guidata должен быть указатель на объект приложения, в нашем случае это указатель на кнопку, который содержится в первом входном аргументе src функции BtnPlotCallback. Далее определяется номер новой линии графика (число построенных линий, т.е. длина массива указателей на линии handles.Lines, плюс один). В новую ячейку массива handles.Funs заносится содержимое строки ввода на текущий момент (указатель на нее находится в handles.edtFun) и заданная функция визуализируется. Функция flpot не строит график, она только вычисляет функцию на отрезке [-1, 1] и записывает абсциссы и ординаты в массивы x и y. Объект линия получается в результате работы функции plot, которая возвращает указатель на линию. Он добавляется в новый элемент массива handles.Lines.

Для линии указывается, что ее событие ButtonDownFcn, которое возникает при щелчке мышью по линии, обрабатывается функцией LineButtonDownFcn (эта функция будет одна для всех линий). В функции LineButtonDownFcn значение первого входного аргумента src будет указателем на линию. Поэтому необходимо найти номер элемента массива handles.Lines, совпадающего с src, и в строку ввода поместить содержимое ячейки массива handles.Funs с тем же самым номером.

function plotlines

% создаем графическое окно с тегом win

hF = figure('Name', 'plotlines', 'NumberTitle','off',...

'MenuBar', 'none', 'Units', 'characters',...

'Position', [10 10 100 30], 'Tag', 'win');

% создаем оси с тегом axMain, свойство NextPlot = 'add' для добавления новых линий

axes('Position', [0.1 0.15 0.8 0.8], 'Tag', 'axMain',...

'NextPlot', 'add');

% создаем область ввода с тегом edtFun

uicontrol('Style', 'edit', 'Units', 'normalized',...

'Position', [0.02 0.02 0.3 0.06],...

'BackgroundColor', 'w',...

'Tag', 'edtFun');

% создаем кнопку с тегом btnPlot и функцией BtnPlotCallback обработки

% события Callback

uicontrol('Style', 'pushbutton', 'Units','normalized',...

'Position', [0.35 0.02 0.1 0.06],...

'String', 'Plot', 'Callback', @BtnPlotCallback,...

'Tag', 'btnPlot');

% записываем указатели на объекты в структуру handles

handles = guihandles(hF);

% добавляем в структуру handles поле Funs для записи строк с формулами

% в массив ячеек и присваиваем ему пустой массив ячеек

handles.Funs = {};

% добавляем в структуру handles поле Lines для записи указателей на линии

% и присваиваем ему пустой числовой массив

handles.Lines=[];

% сохраняем обновленную структуру

guidata(hF, handles)

% скрываем указатели

set(hF, 'HandleVisibility', 'callback');

function BtnPlotCallback(src, evt)

% функция обработки события Callback кнопки

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

handles = guidata(src);

% определяем номер новой линии

k = length(handles.Lines)+1;

% заносим в новую ячейку поля Funs структуры handles строку с формулой

handles.Funs{k} = get(handles.edtFun, 'String')

% вычисляем значения функции на отрезке [-1,1]

[x,y] = fplot(handles.Funs{k}, [-1 1]);

% строим график функции, указатель на линию графика записываем в новую

% ячейку массива handles.Lines

handles.Lines(k) = plot(x,y,'LineWidth',3);

% связываем функцию LineButtonDownFcn с событием, которое возникает при

% нажатии кнопки мыши на линии

set(handles.Lines(k), 'ButtonDownFcn', @LineButtonDownFcn)

% сохраняем структуру handles

guidata(src, handles)

function LineButtonDownFcn(src, evt)

% обработка нажатия кнопки мыши на линии, в src - указатель

% на текущую линию, событие ButtonDownFcn которой обрабатывается

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

handles = guidata(src);

% ищем номер текущей линии с указателем src

k = find(handles.Lines == src);

% записываем в строку ввода формулу, соответствующую текущей линии графика

set(handles.edtFun, 'String', handles.Funs{k})

Вообще говоря, этот пример приведен только для демонстрации обмена данными между функциями обработки событий. Приложение plotlines можно было запрограммировать проще. У объектов, в том числе и линий, есть свойство UserData, значением которого могут быть данные, ассоциированные с объектом. В нашем случае достаточно при построении линии задать соответствующую строку с формулой в качестве значения ее свойства UserData. В функции LineButtonDownFcn, обрабатывающей нажатие кнопки мыши на линии, значение свойства UserData текущей линии (указатель на нее - во входном аргументе src) записывается в область ввода. В таком варианте функция guidata не нужна - обмен данными между подфункциями производится при помощи свойства UserData объекта.

Вот листинг измененной функции с подфункциями.

function plotlines

% создаем графическое окно с тегом win

hF = figure('Name', 'plotlines', 'NumberTitle','off',...

'MenuBar', 'none', 'Units', 'characters',...

'Position', [10 10 100 30], 'Tag', 'win');

% создаем оси с тегом axMain, свойство NextPlot = 'add' для добавления новых линий

axes('Position', [0.1 0.15 0.8 0.8], 'Tag', 'axMain',...

'NextPlot', 'add');

% создаем область ввода с тегом edtFun

uicontrol('Style', 'edit','Units', 'normalized',...

'Position', [0.02 0.02 0.3 0.06],...

'BackgroundColor','w',...

'Tag', 'edtFun');

% создаем кнопку с тегом btnPlot и функцией BtnPlotCallback обработки

% события Callback

uicontrol('Style', 'pushbutton', 'Units','normalized',...

'Position', [0.35 0.02 0.1 0.06],...

'String', 'Plot', 'Callback', {@BtnPlotCallback},...

'Tag', 'btnPlot');

% скрываем указатели

set(hF, 'HandleVisibility', 'callback');

function BtnPlotCallback(src, evt)

% функция обработки события Callback кнопки

% получаем структуру указателей на объекты приложения

handles = guihandles(src);

% записываем в formula содержимое строки ввода

formula = get(handles.edtFun, 'String')

% строим график функции, заданной строкой formula

[x,y] = fplot(formula, [-1 1]);

hL = plot(x,y,'LineWidth',3);

% связываем функцию LineButtonDownFcn с событием, возникающим при нажатии

% кнопки мыши на линии

set(hL, 'ButtonDownFcn', @LineButtonDownFcn)

% записываем в свойство UserData линии строку с соответствующей ей формулой

set(hL, 'UserData', formula)

function LineButtonDownFcn(src, evt)

% обработка нажатия кнопки мыши на линии, в src - указатель

% на текущую линию, событие ButtonDownFcn которой обрабатывается

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

handles = guihandles(src);

% считываем значение свойства UserData линии, оно содержит формулу

formula = get(src, 'UserData');

% записываем формулу в строку ввода

set(handles.edtFun, 'String', formula)

В MATLAB 7 структура графических объектов несколько изменилась по сравнению с предыдущими версиями. В частности, появились рисованные объекты, которые строятся высокоуровневыми графическими функциями (например, plot), в отличие от базовых, которые получаются при вызове низкоуровневых функций (например line). У рисованных объектов линий (Lineseries) есть свойство DisplayName, значением которого может быть строка (именно эта строка будет отображаться в легенде рядом с образцом линии при использовании функции legend). В нашем примере можно было задействовать свойство DisplayName вместо UserData.