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

Обзор в качестве примера

Этот пример задает два класса:

  • 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 свойство получает функцию. Этот метод вычисляет значения для 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 propertyEventУстановка 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 класс для каждого подграфика, задает контекстные меню, которые позволяют/запрещают прослушиватели, и создает подграфики

Методы, наследованные от класса Handle

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

Методы Класса Handle предоставляют полный список методов, которые наследованы, когда вы разделяете на подклассы handle класс.

Методы, наследованные от класса HandleЦель
addlistenerУкажите прослушиватель для определенного события и присоедините прослушиватель объекта event-defining.
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 событие также обновляет поверхностные данные, все представления теперь синхронизируются

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

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

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

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 метод не мог инициировать событие и постараться не обновлять график. Однако метод мог все еще установить свойство на новое значение.

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

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 класс задает функцию множества для 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.

Укажите, что Атрибуты свойств предоставляют список всех атрибутов свойства.

Прослушиватель и обратный вызов для события 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 свойство.

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

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

  • Listen — Устанавливает Enabled свойство для обоих UpdateGraph и PostSet прослушиватели true и добавляет галочку рядом с пунктом меню Listen.

  • Don't Listen — Устанавливает Enabled свойство для обоих UpdateGraph и PostSet прослушиватели false и добавляет галочку рядом с пунктом меню Don't Listen.

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

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

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 функция вызвана, когда пользователь выбирает Don't Listen из контекстного меню.

function disableLisn(obj,src,evnt)
   obj.HLUpdateGraph.Enabled = false; % Disable listener
   obj.HLLm.Enabled = false; % Disable listener
   set(obj.HEnableCm,'Checked','off') % Uncheck 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