プログラムによるカスタム UI コンポーネントのプロパティの管理
ComponentContainer
基底クラスのサブクラスとしてカスタムの UI コンポーネントを作成する際には、特定の手法を使えば、よりロバストで、効率的で、使いやすいコードを作成できます。これらの手法では、ユーザー クラスのプロパティを定義し管理する方法に焦点を当てます。作成するコンポーネントのタイプと提供するユーザー エクスペリエンスに役立つものは、すべて使用してください。
プロパティ値の初期化 — ユーザーが入力引数なしで暗黙的なコンストラクターを呼び出す場合に備えて、UI コンポーネントの既定の状態を設定します。
プロパティ値の検証 — 値を使用する前に、その値が有効であることを確認します。
プロパティ表示のカスタマイズ — ユーザーがセミコロンなしで UI コンポーネント オブジェクトを参照したときに、コマンド ウィンドウにカスタマイズされたプロパティリストを示します。
update メソッドの最適化 — 時間のかかる計算にプロパティのサブセットのみが使用されている場合、
update
メソッドのパフォーマンスを改善します。
この手法の例については、例: カスタマイズされたプロパティ表示をもつ最適化された多項式近似 UI コンポーネントを参照してください。
また、App Designer でカスタムの UI コンポーネントを使用する場合、または App Designer でアプリを開発するユーザーとコンポーネントを共有する場合には、注意すべき特定の考慮事項や制限があります。これらの考慮事項は、App Designer 用のカスタム UI コンポーネントの構成の個別のページに示されています。
プロパティ値の初期化
ユーザー クラスのパブリック プロパティすべてに対し既定値を割り当てます。これにより、MATLAB では、ユーザーがコンストラクター メソッドを呼び出す際に名前と値の引数をいくつか省略しても、有効な UI コンポーネントが作成されます。
チャートを含み、座標のデータを格納するプロパティをもつ UI コンポーネントでは、初期値を NaN
値または空の配列に設定することで、ユーザーが座標を指定しない場合は既定のチャートが空になるようにします。
プロパティ値の検証
コードでプロパティ値を使用する前に、そのサイズとクラスが正しいことを確認します。たとえば、次のプロパティ ブロックでは、3 つのプロパティのサイズとクラスが検証されます。
properties LineColor {validateattributes(LineColor,{'double'}, ... {'<=',1,'>=',0,'size',[1 3]})} = [1 0 0] XData (1,:) double = NaN YData (1,:) double = NaN end
LineColor
は、それぞれの値が範囲 [0,1]
内にある、クラス double
の 1 行 3 列の配列でなければなりません。XData
と YData
の両方が、クラス double
の行ベクトルでなければなりません。
UI コンポーネントにおいて、基となるコンポーネント オブジェクトを格納するプロパティを検証することもできます。この検証を行うには、各オブジェクトの正しいクラス名を知る必要があります。オブジェクトのクラス名を確認するには、コマンド ラインで対応する UI コンポーネント関数を呼び出し、続いて関数 class
を呼び出してクラス名を取得します。たとえば、setup
メソッドでドロップダウン コンポーネントを作成する場合は、コマンド ラインで出力引数を指定して関数 uidropdown
を呼び出します。次に、出力を関数 class
に渡してそのクラス名を取得します。
dd = uidropdown; class(d)
ans = 'matlab.ui.control.DropDown'
関数 class
の出力を使用して、ユーザー クラスで対応するプロパティについてクラスを検証します。プロパティ名の後にクラスを指定します。たとえば、次のプロパティは DropDown
オブジェクトを格納し、そのクラスを検証します。
properties (Access = private, Transient, NonCopyable) DropDown matlab.ui.control.DropDown end
場合によっては、異なった形状とクラスの値を格納できるプロパティを定義することもできます。たとえば、文字ベクトル、文字ベクトルの cell 配列、または string 配列を格納できるプロパティを定義する場合は、サイズとクラスの検証を省略するか、カスタムのプロパティ検証法を使用します。プロパティ検証の詳細については、プロパティ値の検証を参照してください。
プロパティ表示のカスタマイズ
UI コンポーネントを ComponentContainer
基底クラスのサブクラスとして定義することの利点の 1 つは、matlab.mixin.CustomDisplay
クラスからの継承もあることです。これにより、UI コンポーネントをセミコロンなしで参照したときに MATLAB® コマンド ウィンドウに表示されるプロパティのリストを、カスタマイズすることができます。プロパティ表示をカスタマイズするには、getPropertyGroups
メソッドをオーバーロードします。そのメソッド内で、リストされるプロパティとリストの順序をカスタマイズできます。たとえば、次のパブリック プロパティをもつ FitPlot
クラスについて考えます。
properties LineColor {validateattributes(LineColor,{'double'}, ... {'<=',1,'>=',0,'size',[1 3]})} = [1 0 0] XData (1,:) double = NaN YData (1,:) double = NaN end
次の getPropertyGroups
メソッドは、スカラー オブジェクトのプロパティ リストを XData
、YData
、および LineColor
として指定します。
function propgrp = getPropertyGroups(comp) if ~isscalar(comp) % List for array of objects propgrp = getPropertyGroups@matlab.mixin.CustomDisplay(comp); else % List for scalar object propList = {'XData','YData','LineColor'}; propgrp = matlab.mixin.util.PropertyGroup(propList); end end
ユーザーがこの UI コンポーネントのインスタンスをセミコロンなしで参照すると、MATLAB はカスタマイズされたリストを表示します。
p = FitPlot
p =
FitPlot with properties:
XData: NaN
YData: NaN
LineColor: [1 0 0]
プロパティ表示のカスタマイズの詳細については、プロパティ表示のカスタマイズを参照してください。
update
メソッドの最適化
ほとんどの場合、ユーザー クラスの update
メソッドは、パブリック プロパティに依存する UI コンポーネントのあらゆる関連特性を再構成します。場合によっては、再構成には時間のかかる高負荷な計算が伴います。計算にプロパティのサブセットのみが関与する場合は、そのコードが必要な場合にのみ実行されるようにユーザー クラスを設計できます。
update
メソッドを最適化する 1 つの方法は、以下の要素をユーザー クラスに追加することです。
logical
値を受け入れるExpensivePropChanged
という名前のプライベート プロパティ。このプロパティは、高負荷な計算に使用されるプロパティのいずれかが変更されたかどうかを示します。高負荷な計算に関与する各プロパティ用の
set
メソッド。各set
メソッド内で、ExpensivePropChanged
プロパティをtrue
に設定します。高負荷な計算を実行する、
doExpensiveCalculation
という名前の保護されたメソッド。ExpensivePropChanged
の値をチェックする、update
メソッド内の条件付きステートメント。この値がtrue
の場合は、doExpensiveCalculation
を実行します。
以下のコードは、この設計のテンプレートを示しています。
classdef OptimizedUIComponent < matlab.ui.componentcontainer.ComponentContainer properties Prop1 Prop2 end properties(Access=private,Transient,NonCopyable) ExpensivePropChanged (1,1) logical = true end methods(Access = protected) function setup(comp) % Configure UI component % ... end function update(comp) % Perform expensive computation if needed if comp.ExpensivePropChanged doExpensiveCalculation(comp); comp.ExpensivePropChanged = false; end % Update other aspects of UI component % ... end function doExpensiveCalculation(comp) % Expensive code % ... end end methods function set.Prop2(comp,val) comp.Prop2 = val; comp.ExpensivePropChanged = true; end end end
この場合、Prop2
が高負荷な計算に関与しています。set.Prop2
メソッドは Prop2
の値を設定し、続いて ExpensivePropChanged
を true
に設定します。次に update
メソッドが実行されるときは、ExpensivePropChanged
が true
である場合にのみ doExpensiveCalculation
が呼び出されます。その後、update
メソッドは UI コンポーネントの他の特性を引き続き更新します。
例: カスタマイズされたプロパティ表示をもつ最適化された多項式近似 UI コンポーネント
この例では、最適な多項式近似を対話的に表示する FitPlot
クラスを定義し、これら 4 つのベスト プラクティスをすべて使用します。properties ブロックで定義されたプロパティは既定値をもち、サイズとクラスの検証を使用します。getPropertyGroups
メソッドは、プロパティ表示のカスタムの順序を定義します。changeFit
メソッドは高負荷になる可能性のある多項式近似計算を実行し、update
メソッドは、プロットされたデータが変更された場合にのみ changeFit
を実行します。
このクラスを定義するために、MATLAB パス上にあるフォルダー内の FitPlot.m
というファイルに FitPlot
クラス定義を保存します。
classdef FitPlot < matlab.ui.componentcontainer.ComponentContainer % Choose a fit method for your plotted data properties LineColor {validateattributes(LineColor,{'double'}, ... {'<=',1,'>=',0,'size',[1 3]})} = [1 0 0] XData (1,:) double = NaN YData (1,:) double = NaN end properties (Access = private, Transient, NonCopyable) DropDown matlab.ui.control.DropDown Axes matlab.ui.control.UIAxes GridLayout matlab.ui.container.GridLayout DataLine (1,1) matlab.graphics.chart.primitive.Line FitLine (1,1) matlab.graphics.chart.primitive.Line FitXData (1,:) double FitYData (1,:) double ExpensivePropChanged (1,1) logical = true end methods (Access=protected) function setup(comp) % Set the initial position of this component comp.Position = [100 100 300 300]; % Create the grid layout, drop-down, and axes comp.GridLayout = uigridlayout(comp,[2,1], ... 'RowHeight',{20,'1x'},... 'ColumnWidth',{'1x'}); comp.DropDown = uidropdown(comp.GridLayout, ... 'Items',{'None','Linear','Quadratic','Cubic'}, ... 'ValueChangedFcn',@(s,e) changeFit(comp)); comp.Axes = uiaxes(comp.GridLayout); % Create the line objects comp.DataLine = plot(comp.Axes,NaN,NaN,'o'); hold(comp.Axes,'on'); comp.FitLine = plot(comp.Axes,NaN,NaN); hold(comp.Axes,'off'); end function update(comp) % Update data points comp.DataLine.XData = comp.XData; comp.DataLine.YData = comp.YData; % Do an expensive operation if comp.ExpensivePropChanged comp.changeFit(); comp.ExpensivePropChanged = false; end % Update the fit line comp.FitLine.Color = comp.LineColor; comp.FitLine.XData = comp.FitXData; comp.FitLine.YData = comp.FitYData; end function changeFit(comp) % Calculate the fit line based on the drop-down value if strcmp(comp.DropDown.Value,'None') comp.FitXData = NaN; comp.FitYData = NaN; else switch comp.DropDown.Value case 'Linear' f = polyfit(comp.XData,comp.YData,1); case 'Quadratic' f = polyfit(comp.XData,comp.YData,2); case 'Cubic' f = polyfit(comp.XData,comp.YData,3); end comp.FitXData = linspace(min(comp.XData),max(comp.XData)); comp.FitYData = polyval(f,comp.FitXData); end end function propgrp = getPropertyGroups(comp) if ~isscalar(comp) % List for array of objects propgrp = getPropertyGroups@matlab.mixin.CustomDisplay(comp); else % List for scalar object propList = {'XData','YData','LineColor'}; propgrp = matlab.mixin.util.PropertyGroup(propList); end end end methods function set.XData(comp,val) comp.XData = val; comp.ExpensivePropChanged = true; end function set.YData(comp,val) comp.YData = val; comp.ExpensivePropChanged = true; end end end
サンプル データをいくつか定義し、そのデータを使用して FitPlot
のインスタンスを作成します。
x = [0 0.3 0.8 1.1 1.6 2.3]; y = [0.6 0.67 1.01 1.35 1.47 1.25]; p = FitPlot('XData',x,'YData',y)
ans =
FitPlot with properties:
XData: [1×43 double]
YData: [1×43 double]
LineColor: [1 0 0]
ドロップダウンを使用して、最適な 2 次近似曲線を表示します。
LineColor
プロパティを設定して、最適な近似曲線の色を緑色に変更します。
p.LineColor = [0 0.5 0];