exponenta event banner

Методы использования событий и прослушивателей

Пример обзора

В этом примере определяются два класса:

  • fcneval - Класс вычислителя функций содержит выражение MATLAB ® и вычисляет это выражение в указанном диапазоне

  • fcnview - Класс просмотра функций содержит fcneval и отображает графики поверхности вычисляемого выражения с использованием данных, содержащихся в fcneval.

Этот класс определяет два события:

  • Определяемое классом событие, возникающее при указании нового значения для функции MATLAB

  • Событие свойства, которое происходит при изменении свойства, содержащего пределы

На следующей схеме показана взаимосвязь между двумя объектами. fcnview объект содержит fcneval и создает графики на основе содержащихся в них данных. fcnview создает прослушиватели для изменения графиков, если какие-либо данные в fcneval изменение объекта.

Методы, продемонстрированные в этом примере

  • Присвоение имени событию в определении класса

  • Запуск события путем вызова notify

  • Включение события свойства с помощью SetObservable признак

  • Создание прослушивателей для определяемых классом событий и свойств PostSet события

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

  • Включение и отключение прослушивателей

Краткое описание класса fcneval

fcneval класс оценивает выражение MATLAB в указанном диапазоне из двух переменных. fcneval является источником данных, которые объекты fcnview граф класса как поверхность. fcneval является источником событий, используемых в этом примере. Список определений классов см. в разделе @ fcneval/fcneval.m Код класса

СобственностьСтоимостьЦель
FofXYдескриптор функцииВыражение MATLAB (функция двух переменных).
Lmдвухэлементный векторПределы, над которыми вычисляется функция в обеих переменных. SetObservable атрибут имеет значение true для включения прослушивателей событий свойств.
Dataструктура с матрицами x, y и zДанные, полученные в результате оценки функции. Используется для графика поверхности. Dependent атрибут имеет значение true, что означает get.Data вызывается метод для определения значения свойства при запросе и отсутствии сохраненных данных.

СобытиеПри срабатывании
UpdateGraphFofXY функция набора свойств (set.FofXY) вызывает notify при указании нового значения для выражения MATLAB для объекта этого класса.

МетодЦель
fcnevalКонструктор класса. Входами являются дескриптор функции и двухэлементный вектор, задающий пределы для вычисления функции.
set.FofXYFofXY функция набора свойств. Вызывается при установке значения свойства, в том числе при построении объекта.
set.LmLm функция набора свойств. Используется для проверки допустимых пределов.
get.DataData свойство get function. Этот метод вычисляет значения для Data свойство при каждом запросе данных (членами класса или извне).
gridСтатический метод (Static атрибут имеет значение true) используется при расчете данных.

Краткое описание класса fcnview

Объекты fcnview класс содержит fcneval объекты как источник данных для четырех графиков поверхности, созданных в представлении функции. fcnview создает прослушиватели и функции обратного вызова, которые реагируют на изменения в данных, содержащихся в fcneval объекты. Список определений классов см. в разделе @ fcnview/fcnview.m Код класса

СобственностьСтоимостьЦель
FcnObjectfcneval объектЭтот объект содержит данные, используемые для создания графиков функций.
HAxesрукоятка осейКаждый экземпляр fcnview объект хранит маркер перемещения осей, содержащих его вложенный график.
HLUpdateGraphevent.listener объект для UpdateGraph событиеУстановка event.listener объект Enabled свойство для true включает прослушиватель; false отключает прослушиватель.
HLLmevent.listener объект для Lm событие свойстваУстановка event.listener объект Enabled свойство для true включает прослушиватель, false отключает прослушиватель.
HEnableCmдескриптор uimenuЭлемент в контекстном меню, используемый для включения прослушивателей (используется для обработки проверенного поведения)
HDisableCmдескриптор uimenuЭлемент контекстного меню, используемый для отключения прослушивателей (используется для управления проверенным поведением)
HSurfaceручка поверхностиИспользуется обратными вызовами событий для обновления данных поверхности.

МетодЦель
fcnviewКонструктор класса. Вход: fcneval объект.
createLisnТребования addlistener создание прослушивателей для UpdateGraph и Lm собственность PostSet слушатели.
limsУстанавливает пределы осей для текущего значения fcneval объект Lm собственность. Используется обработчиками событий.
updateSurfaceDataОбновление данных поверхности без создания нового объекта. Используется обработчиками событий.
listenUpdateGraphОбратный вызов для UpdateGraph событие.
listenLmОбратный вызов для Lm собственность PostSet событие
deleteМетод удаления для fcnview класс.
createViewsСтатический метод, создающий экземпляр fcnview класс для каждого вложенного графика, определяет контекстные меню, которые включают/отключают прослушиватели, и создает вложенные графики

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

Оба fcneval и fcnview классы наследуют методы от handle класс. В следующей таблице перечислены только унаследованные методы, использованные в этом примере.

Handle Class Methods предоставляет полный список методов, наследуемых при подклассе handle класс.

Методы, унаследованные из класса дескрипторовЦель
addlistenerЗарегистрируйте прослушиватель для определенного события и присоедините прослушиватель к определяющему событие объекту.
notifyЗапуск события и уведомление всех зарегистрированных прослушивателей.

Использование классов fcneval и fcnview

В этом разделе описывается использование классов.

  • Создание экземпляра fcneval класс, содержащий выражение MATLAB функции из двух переменных и диапазон, по которому требуется вычислить эту функцию

  • Используйте fcnview статическая функция класса createViews для визуализации функции

  • Изменение выражения MATLAB или ограничений, содержащихся в fcneval объект и все fcnview объекты реагируют на сгенерированные события.

Вы создаете fcneval объект путём вызова его конструктора с двумя аргументами - анонимной функцией и двухэлементным, монотонно возрастающим вектором. Например:

feobject = fcneval(@(x,y) x.*exp(-x.^2-y.^2),[-2 2]);

Используйте createViews статический метод для создания графиков функции. Используйте имя класса для вызова статической функции:

fcnview.createViews(feobject);

createView метод генерирует четыре представления функции, содержащейся в fcneval объект.

Каждый вложенный график определяет контекстное меню, которое может включать и отключать прослушиватели, связанные с этим графиком. Например, если отключить прослушиватели на вложенной диаграмме 221 (вверху слева) и изменить выражение MATLAB, содержащееся в fcneval объект, только оставшиеся три вложенные диаграммы обновляются при UpdateGraph событие инициируется:

feobject.FofXY = @(x,y) x.*exp(-x.^.5-y.^.5);

Аналогично, если изменить пределы, назначив значение feobject.Lm свойство, feobject запускает PostSet событие свойства и обратные вызовы прослушивателя обновляют граф.

feobject.Lm = [-8 3];

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

Реализация события и прослушивателя StartGraph

UpdateGraph происходит, когда MATLAB представление математической функции, содержащейся в fcneval объект изменен. fcnview объекты, содержащие графики поверхности, прослушивают это событие, поэтому они могут обновить графики для представления новой функции.

Определение и инициирование события StartGraph

UpdateGraph событие является событием, определяемым классом. fcneval именует событие и вызовы notify когда происходит событие.

fcnview класс определяет прослушиватель для этого события. Когда fcneval запускает событие, fcnview прослушиватель выполняет функцию обратного вызова, которая выполняет следующие действия:

  • Определяет, хранится ли маркер перемещения объекта поверхности в fcnview объект по-прежнему действителен (то есть объект все еще существует)

  • Обновление поверхности XData, YData, и ZData путем запроса fcneval объект Data собственность.

fcneval класс определяет имя события в event блок:

events
   UpdateGraph 
end

Определить, когда следует инициировать событие

fcneval класс определяет метод набора свойств для FofXY собственность. FofXY - свойство, хранящее выражение MATLAB для математической функции. Это выражение должно быть допустимым выражением MATLAB для функции двух переменных.

set.FofXY способ:

  • Определяет пригодность выражения

  • Если выражение подходит:

    • Назначает выражение FofXY собственность

    • Запускает UpdateGraph событие

Если fcneval.isSuitable не возвращает MException объект, set.FofXY метод присваивает значение свойству и запускает UpdateGraph событие.

function set.FofXY(obj,func)
% Determine if function is suitable to create a surface
   me = fcneval.isSuitable(func);
   if ~isempty(me)
      throw(me)
   end
% Assign property value
   obj.FofXY = func; 
% Trigger UpdateGraph event
   notify(obj,'UpdateGraph');
end

Определение пригодности выражения

set.FofXY метод вызывает статический метод (fcneval.isSuitable) для определения пригодности указанного выражения. fcneval.isSuitable возвращает MException объект, если он определяет, что выражение не подходит. fcneval.isSuitable вызывает MException непосредственно для создания более полезных сообщений об ошибках для пользователя.

set.FofXY выдает исключение с помощью throw способ. Выдача исключения прекращает выполнение set.FofXY и предотвращает назначение метода свойству или запуск UpdateGraph событие.

Вот fcneval.isSuitable способ:

function isOk = isSuitable(funcH)
   v = [1 1;1 1];
   % Can the expression except 2 numeric inputs
   try
      funcH(v,v);
   catch %#ok<CTCH>
      me = MException('DocExample:fcneval',...
         ['The function ',func2str(funcH),' Is not a suitable F(x,y)']);
      isOk = me;
      return
   end
   % Does the expression return non-scalar data
   if isscalar(funcH(v,v));
      me = MException('DocExample:fcneval',...
         ['The function ',func2str(funcH),'' Returns a scalar when evaluated']);
      isOk = me;
      return
   end
   isOk = [];
end

fcneval.isSuitable метод может обеспечить дополнительный тест, чтобы гарантировать, что выражение назначено FofXY свойство соответствует критериям, требуемым проектом класса.

Другие подходы

Класс мог реализовать событие набора свойств для FofXY собственность и, следовательно, не нужно будет звонить notify (см. раздел Прослушивание изменений значений свойств). Определение события класса обеспечивает большую гибкость в этом случае, поскольку можно лучше управлять инициированием события.

Например, предположим, что требуется обновить график, только если новые данные отличаются. Если новое выражение дало те же данные в пределах некоторого допуска, set.FofXY метод не может инициировать событие и избежать обновления графика. Однако метод все равно может установить для свойства новое значение.

Прослушиватель и обратный вызов для события

fcnview создает прослушиватель для UpdateGraph события с использованием addlistener способ:

obj.HLUpdateGraph = addlistener(obj.FcnObject,'UpdateGraph',...
            @(src,evnt)listenUpdateGraph(obj,src,evnt)); % Add obj to argument list

fcnview объект сохраняет дескриптор для event.listener объект в его HLUpdateGraph свойство, которое используется для включения/отключения прослушивателя с помощью контекстного меню (см. Включение и отключение прослушивателей).

fcnview объект (obj) добавляется к двум аргументам по умолчанию (src, evnt) передан в обратный вызов прослушивателя. Имейте в виду, источник события (src) - fcneval объект, но fcnview содержит дескриптор объекта поверхности, который обновляется при обратном вызове.

listenUpdateGraph функция определяется следующим образом:

function listenUpdateGraph(obj,src,evnt)
   if ishandle(obj.HSurface) % If surface exists
      obj.updateSurfaceData % Update surface data
   end
end

updateSurfaceData функция - это метод класса, который обновляет данные поверхности при назначении другой математической функции fcneval объект. Обновление данных графического объекта более эффективно, чем создание нового объекта с использованием новых данных:

function updateSurfaceData(obj)
% Get data from fcneval object and set surface data
   set(obj.HSurface,...
      'XData',obj.FcnObject.Data.X,...
      'YData',obj.FcnObject.Data.Y,...
      'ZData',obj.FcnObject.Data.Matrix); 
end

Прослушиватель событий PostSet

Все свойства поддерживают предопределенные PostSet (Дополнительные сведения о событиях свойств см. в разделе События набора свойств и запроса). В этом примере используется PostSet событие для fcneval Lm собственность. Это свойство содержит двухэлементный вектор, определяющий диапазон, в котором вычисляется математическая функция. Сразу после изменения этого свойства (оператором, например obj.Lm = [-3 5];), fcnview объекты, прослушивающие это событие, обновляют график для отражения новых данных.

Последовательность во время Lm Присвоение свойств

fcneval класс определяет функцию set для Lm собственность. При назначении значения этому свойству во время построения объекта или переназначения свойства происходит следующая последовательность:

  1. Предпринята попытка присвоить значение аргумента Lm собственность.

  2. set.Lm метод выполняется для проверки того, находится ли значение в соответствующем диапазоне - если да, он выполняет назначение, если нет, он генерирует ошибку.

  3. Если значение Lm установлен успешно, MATLAB запускает PostSet событие.

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

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

Включить событие свойства PostSet

Создание прослушивателя для PostSet событие, необходимо задать свойство SetObservable атрибут для true:

properties (SetObservable = true)
   Lm = [-2*pi 2*pi];  % specifies default value
end 

MATLAB автоматически запускает событие, поэтому нет необходимости вызывать notify.

Команда Задать атрибуты свойства (Specify Property Attributes) предоставляет список всех атрибутов свойства.

Прослушиватель и обратный вызов для события PostSet

fcnview создает прослушиватель для PostSet события с использованием addlistener способ:

obj.HLLm = addlistener(obj.FcnObject,'Lm','PostSet',...
            @(src,evnt)listenLm(obj,src,evnt)); % Add obj to argument list

fcnview объект сохраняет дескриптор для event.listener объект в его HLLm свойство, которое используется для включения/отключения прослушивателя с помощью контекстного меню (см. Включение и отключение прослушивателей).

fcnview объект (obj) добавляется к двум аргументам по умолчанию (src, evnt) передан в обратный вызов прослушивателя. Имейте в виду, источник события (src) - fcneval объект, но fcnview содержит дескриптор объекта поверхности, который обновляется при обратном вызове.

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

function listenLm(obj,src,evnt)
   if ishandle(obj.HAxes) % If there is an axes
      lims(obj); % Update its limits
      if ishandle(obj.HSurface) % If there is a surface
         obj.updateSurfaceData % Update its data
      end
   end
end 

Включение и отключение прослушивателей

Каждый fcnview объект сохраняет дескриптор объектов прослушивателя, которые он создает, чтобы прослушиватели можно было включить или отключить с помощью контекстного меню после создания графиков. Все прослушиватели являются экземплярами event.listener класс, определяющий свойство с именем Enabled. По умолчанию это свойство имеет значение true, что позволяет прослушивателю. Если для этого свойства задано значение false, прослушиватель все еще существует, но отключен. В этом примере создается контекстное меню, активное на осях каждого графика, которое позволяет изменить значение Enabled собственность.

Обратный вызов контекстного меню

Контекстное меню использует два обратных вызова, соответствующих двум пунктам меню:

  • Прослушивание - устанавливает Enabled для обоих UpdateGraph и PostSet слушатели true и добавляет флажок рядом с пунктом меню «Слушать».

  • Не слушать - устанавливает Enabled для обоих UpdateGraph и PostSet слушатели false и добавляет флажок рядом с пунктом меню «Не слушать».

Оба обратных вызова включают в себя fcnview объект в качестве аргумента (в дополнение к требуемым аргументам данных источника и события) для предоставления доступа к дескриптору объектов прослушивателя.

enableLisn вызывается, когда пользователь выбирает в контекстном меню команду «Прослушать».

function enableLisn(obj,src,evnt)
   obj.HLUpdateGraph.Enabled = true; % Enable listener
   obj.HLLm.Enabled = true; % Enable listener
   set(obj.HEnableCm,'Checked','on') % Check Listen
   set(obj.HDisableCm,'Checked','off') % Uncheck Don't Listen
end

disableLisn вызывается, когда пользователь выбирает «Не слушать» в контекстном меню.

function disableLisn(obj,src,evnt)
   obj.HLUpdateGraph.Enabled = false; % Disable listener
   obj.HLLm.Enabled = false; % Disable listener
   set(obj.HEnableCm,'Checked','off') % Unheck Listen
   set(obj.HDisableCm,'Checked','on') % Check Don't Listen
end

@ fcneval/fcneval.m Код класса

classdef fcneval < handle
   properties
      FofXY
   end 
   
   properties (SetObservable = true)
      Lm = [-2*pi 2*pi]
   end % properties SetObservable = true
   
   properties (Dependent = true)
      Data
   end 
   
   events
      UpdateGraph 
   end
   
   methods
      function obj = fcneval(fcn_handle,limits)  % Constructor returns object
         if nargin > 0
            obj.FofXY = fcn_handle;                 % Assign property values
            obj.Lm = limits;
            
         end
      end 
      
      function set.FofXY(obj,func)
         me = fcneval.isSuitable(func);
         if ~isempty(me)
            throw(me)
         end
         obj.FofXY = func;
         notify(obj,'UpdateGraph');  
      end 
      
      function set.Lm(obj,lim)  
         if  ~(lim(1) < lim(2))
            error('Limits must be monotonically increasing')
         else
            obj.Lm = lim;
         end
      end 
      
      function data = get.Data(obj)   
         [x,y] = fcneval.grid(obj.Lm);  
         matrix = obj.FofXY(x,y);
         data.X = x;
         data.Y = y;
         data.Matrix = real(matrix);  
         
      end 
      
   end % methods
   
   methods (Static = true)      
      function [x,y] = grid(lim)
         inc = (lim(2)-lim(1))/20;
         [x,y] = meshgrid(lim(1):inc:lim(2));
      end % grid
      
      function isOk = isSuitable(funcH)
         v = [1 1;1 1];
         try
            funcH(v,v);
         catch  %#ok<CTCH>
            me = MException('DocExample:fcneval',...
               ['The function ',func2str(funcH),' Is not a suitable F(x,y)']);
            isOk = me;
            return
         end
         if isscalar(funcH(v,v));
            me = MException('DocExample:fcneval',...
               ['The function ',func2str(funcH),' Returns a scalar when evaluated']);
            isOk = me;
            return
         end
         isOk = [];
      end
      
   end 
   
end 

@ fcnview/fcnview.m Код класса

classdef fcnview < handle
   properties
      FcnObject     % fcneval object
      HAxes         % subplot axes handle
      HLUpdateGraph % UpdateGraph listener handle
      HLLm          % Lm property PostSet listener handle
      HEnableCm     % "Listen" context menu handle
      HDisableCm    % "Don't Listen" context menu handle
      HSurface      % Surface object handle
   end
   
   methods
      function obj = fcnview(fcnobj)
         if nargin > 0
            obj.FcnObject = fcnobj;
            obj.createLisn;
         end
      end
      
      function createLisn(obj)
         obj.HLUpdateGraph = addlistener(obj.FcnObject,'UpdateGraph',...
            @(src,evnt)listenUpdateGraph(obj,src,evnt));
         obj.HLLm = addlistener(obj.FcnObject,'Lm','PostSet',...
            @(src,evnt)listenLm(obj,src,evnt));
      end
      
      function lims(obj)
         lmts = obj.FcnObject.Lm;
         set(obj.HAxes,'XLim',lmts);
         set(obj.HAxes,'Ylim',lmts);
      end
      
      function updateSurfaceData(obj)
         data = obj.FcnObject.Data;
         set(obj.HSurface,...
            'XData',data.X,...
            'YData',data.Y,...
            'ZData',data.Matrix);
      end
      
      function listenUpdateGraph(obj,~,~)
         if ishandle(obj.HSurface)
            obj.updateSurfaceData
         end
      end
      
      function listenLm(obj,~,~)
         if ishandle(obj.HAxes)
            lims(obj);
            if ishandle(obj.HSurface)
               obj.updateSurfaceData
            end
         end
      end
      
      function delete(obj)
         if ishandle(obj.HAxes)
            delete(obj.HAxes);
         else
            return
         end
      end
      
   end
   methods (Static)
      createViews(a)
   end
end

@ fcnview/createViews

function createViews(fcnevalobj)
   p = pi; deg = 180/p;
   hfig = figure('Visible','off',...
      'Toolbar','none');
   
   for k=4:-1:1
      fcnviewobj(k) = fcnview(fcnevalobj);
      axh = subplot(2,2,k);
      fcnviewobj(k).HAxes = axh;
      hcm(k) = uicontextmenu;
      set(axh,'Parent',hfig,...
         'FontSize',8,...
         'UIContextMenu',hcm(k))
      fcnviewobj(k).HEnableCm = uimenu(hcm(k),...
         'Label','Listen',...
         'Checked','on',...
         'Callback',@(src,evnt)enableLisn(fcnviewobj(k),src,evnt));
      fcnviewobj(k).HDisableCm = uimenu(hcm(k),...
         'Label','Don''t Listen',...
         'Checked','off',...
         'Callback',@(src,evnt)disableLisn(fcnviewobj(k),src,evnt));
      az = p/k*deg;
      view(axh,az,30)
      title(axh,['View: ',num2str(az),' 30'])
      fcnviewobj(k).lims;
      surfLight(fcnviewobj(k),axh)
   end
   set(hfig,'Visible','on')
end
function surfLight(obj,axh)
   obj.HSurface = surface(obj.FcnObject.Data.X,...
      obj.FcnObject.Data.Y,...
      obj.FcnObject.Data.Matrix,...
      'FaceColor',[.8 .8 0],'EdgeColor',[.3 .3 .2],...
      'FaceLighting','phong',...
      'FaceAlpha',.3,...
      'HitTest','off',...
      'Parent',axh);
   lims(obj)
   camlight left; material shiny; grid off
   colormap copper
end

function enableLisn(obj,~,~)
   obj.HLUpdateGraph.Enabled = true;
   obj.HLLm.Enabled = true;
   set(obj.HEnableCm,'Checked','on')
   set(obj.HDisableCm,'Checked','off')
end

function disableLisn(obj,~,~)
   obj.HLUpdateGraph.Enabled = false;
   obj.HLLm.Enabled = false;
   set(obj.HEnableCm,'Checked','off')
   set(obj.HDisableCm,'Checked','on')
end