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

Обзор примера

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Сводные данные по классу fcneval

The fcneval класс вычисляет выражение MATLAB для заданной области двух переменных. The 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 событие свойстваУстановка event.listener Enabled объекта свойство к true включает прослушиватель, false отключает прослушиватель.
HEnableCmuimenu указателяЭлемент контекстного меню, используемый для включения прослушивателей (используется для обработки проверенного поведения)
HDisableCmuimenu указателяЭлемент контекстного меню, используемый для отключения прослушивателей (используется для управления проверенным поведением)
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 Class Methods предоставляет полный список методов, которые наследуются при подклассификации handle класс.

Методы, унаследованные от класса 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);

The 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 и прослушиватель

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

Определите и инициируйте событие UpdateGraph

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

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

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

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

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

events
   UpdateGraph 
end

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

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

The 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

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

The 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

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

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

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

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

Прослушиватель и коллбэк для события UpdateGraph

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

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

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

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

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

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

The 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 событие (для получения дополнительной информации о событиях свойств см. раздел Property-Set и Query Events). Этот пример использует PostSet событие для fcneval Lm свойство. Это свойство содержит двухэлементный вектор, задающий область значений, в котором вычисляется математическая функция. Сразу после того, как это свойство будет изменено (оператором like obj.Lm = [-3 5];), а fcnview объекты, прослушивающие это событие, обновляют график, чтобы отразить новые данные.

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

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

  1. Делается попытка присвоить значение аргумента Lm свойство.

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

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

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

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

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

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

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

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

Параметр «Задать атрибуты свойств» содержит список всех атрибутов свойств.

Прослушиватель и коллбэк для события PostSet

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

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

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

The 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 объект как аргумент (в дополнение к требуемым аргументам source и event data) для предоставления доступа к указателю на объекты прослушивателя.

The 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

The 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') % 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