Main Content

プログラムによるカスタム 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 列の配列でなければなりません。XDataYData の両方が、クラス 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 メソッドは、スカラー オブジェクトのプロパティ リストを XDataYData、および 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 の値を設定し、続いて ExpensivePropChangedtrue に設定します。次に update メソッドが実行されるときは、ExpensivePropChangedtrue である場合にのみ 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]

Instance of the FitPlot class displaying a drop-down with the value 'None' and an axes with some sample data.

ドロップダウンを使用して、最適な 2 次近似曲線を表示します。

Instance of the FitPlot class. The drop-down is expanded the mouse pointer is on the "Quadratic" option. The axes shows sample data and a red quadratic line of best fit.

LineColor プロパティを設定して、最適な近似曲線の色を緑色に変更します。

p.LineColor = [0 0.5 0];

Instance of the FitPlot class. The drop-down value is "Quadratic" and the axes show sample data and a green quadratic line of best fit.

参考

クラス

関数

関連するトピック