bio_img_japan-community

MATLAB ユーザーコミュニティー

MATLAB & Simulink ユーザーコミュニティー向け日本語ブログ

MATLAB グラフィックス オブジェクト 〜コールバック編

こんにちは,道家です.新年度・新学期も始まり,もうそろそろゴールデンウィークという時期ですが,新しい環境に入られた方は慣れてきましたでしょうか?
さて先月,トレーニングチームの遠藤さんが執筆した MATLAB グラフィックス オブジェクトの記事 いかがでしたでしょうか.私にとっては MATLAB グラフィックスは好きな機能トップ3の一つなので,楽しく読ませてもらいました.MATLABでは簡単にデータを可視化できるだけではなく,プロパティを操作することによって思い通りの可視化を実現する事ができます.
実は,グラフィックス オブジェクトには外観を操作するプロパティ以外に,対話的な機能を追加するためのプロパティも存在します.例えば,グラフをクリックした時に線の色を変えたり,オブジェクトをクリック アンド ドラッグで動かしたりできます.

コールバックで振る舞いを定義

plotpatch などの描画コマンドで作成するグラフィックス オブジェクトにはコールバックという対話的機能を定義するプロパティが存在します.これらはマウスでクリックするなどユーザーが何か操作を行った時にどう振る舞ってほしいかをプログラムするのに使われます.反応できるユーザーからの操作は決まっていて,コールバックの名前でだいたい分かります.
例えば,一般的なのは多くのグラフィックス オブジェクトに存在する ButtonDownFcn です.これは,グラフィックス オブジェクトの上でマウスボタンをクリックした時の振る舞いを定義するプロパティです.このプロパティに実行してほしい関数を設定しますと,毎回クリックされる度にこの関数が実行されます.因みにコールバック関数には決まった書き方があります.こちら,ラインをクリックすると「ポチッ」と表示される例です.
plot(rand(1,10),“ButtonDownFcn”,@clickFcn)
 
function clickFcn(src, event)
disp(“ポチッ”)
end
ButtonDownFcnclickFcn に設定することによって,「plot で描画されたグラフをクリックした時に clickFcn を実行してください」と定義したことになります.すると,振る舞いはマウスクリックのタイミングでコールバックの clickFcn が呼ばれ,その中のプログラム(ここでは disp)が実行され,コマンドウィンドウに文字が表示されます.
さて,ここからいくつかの例を見ていきましょう.

例1:マウスクリックで図形の色を変更

コールバックはグラフィックス オブジェクト毎に設定できます.こちらの例では patch で作成された三つの図形それぞれに ButtonDownFcn を設定します.コールバックは全て同じで,クリックするごとに図形の色を赤→緑→青の順に変更させるものです.
figure
 
% 赤い四角
p1 = patch([3 5 5 3],[1 1 3 3],“r”);
 
% 緑の三角
p2 = patch([5 7 6],[4 4 6],“g”);
 
% 青い丸
x = cos(linspace(0,2*pi,100))+2;
y = sin(linspace(0,2*pi,100))+5;
p3 = patch(x,y,“b”);
 
axis equal
 
axH = gca;
axH.Toolbar.Visible = “off”; % ツールバーを無効化
axH.Interactions = []; % 操作オブジェクトを無効化
 
% 各図形に,マウスクリックに反応するコールバックを定義
p1.ButtonDownFcn = @clickShapeFcn;
p2.ButtonDownFcn = @clickShapeFcn;
p3.ButtonDownFcn = @clickShapeFcn;
 
%%———————
function clickShapeFcn(src,event)
% 図形をクリックした時に実行されるコールバック
 
% オブジェクトの色を取得
c = src.FaceColor;
 
% 赤->緑,緑->青,青->赤の順でサイクル
if isequal(c,[1 0 0])
src.FaceColor = [0 1 0];
elseif isequal(c,[0 1 0])
src.FaceColor = [0 0 1];
else % obj.FaceColor = [0 0 1]
src.FaceColor = [1 0 0];
end
 
end
click_change_animation.gif

例2:コンテキストメニューより色を変更

クリックではなくコンテキストメニューによって色を変化させたい場合はどうでしょう.それにはもちろん uicontextmenuuimenu を活用します.uimenu の場合は MenuSelectedFcn というプロパティを使いますが,それに色を変えるコールバックを定義します.
hFig = figure();
 
% 赤い四角
p1 = patch([3 5 5 3],[1 1 3 3],“r”);
 
% 緑の三角
p2 = patch([5 7 6],[4 4 6],“g”);
 
% 青い丸
x = cos(linspace(0,2*pi,100))+2;
y = sin(linspace(0,2*pi,100))+5;
p3 = patch(x,y,“b”);
 
axis equal
 
axH = gca;
axH.Toolbar.Visible = “off”; % ツールバーを無効化
axH.Interactions = []; % 操作オブジェクトを無効化
 
% コンテキストメニューを定義
cm = uicontextmenu(hFig);
uimenu(cm,“Text”,“赤”,“MenuSelectedFcn”,@(src,event) colorSelectedFcn(“r”,hFig));
uimenu(cm,“Text”,“緑”,“MenuSelectedFcn”,@(src,event) colorSelectedFcn(“g”,hFig));
uimenu(cm,“Text”,“青”,“MenuSelectedFcn”,@(src,event) colorSelectedFcn(“b”,hFig));
 
% コンテキストメニューをそれぞれの図形に追加
p1.ContextMenu = cm;
p2.ContextMenu = cm;
p3.ContextMenu = cm;
 
%%———————
function colorSelectedFcn(color,hFig)
% コンテキストメニュー(赤,緑,青)が選択された時に実行
 
% クリックされた図形オブジェクト
currentPatch = hFig.CurrentObject;
 
% 渡された色に設定
currentPatch.FaceColor = color;
end
※ この例ではMenuSelectedFcn のコールバックに通常とは違う入力を渡すために無名関数を使っています.
contextmenu_animation.gif

例3:ダブルクリックに応答

普通のクリックではなくダブルクリックに反応させるには,figureの SelectionType プロパティを使います.直近のマウスクリックが左クリック,右クリック,中央ボタン,ダブルクリックなのかを返してくれます.この例では,図形をダブルクリックする毎に色が変化します.
hFig = figure;
 
% 赤い四角
p1 = patch([3 5 5 3],[1 1 3 3],“r”);
 
% 緑の三角
p2 = patch([5 7 6],[4 4 6],“g”);
 
% 青い丸
x = cos(linspace(0,2*pi,100))+2;
y = sin(linspace(0,2*pi,100))+5;
p3 = patch(x,y,“b”);
 
axis equal
 
axH = gca;
axH.Toolbar.Visible = “off”; % ツールバーを無効化
axH.Interactions = []; % 操作オブジェクトを無効化
 
% 各図形に,マウスクリックに反応するコールバックを定義
p1.ButtonDownFcn = @(src,event) clickShapeFcn(src,event,hFig);
p2.ButtonDownFcn = @(src,event) clickShapeFcn(src,event,hFig);
p3.ButtonDownFcn = @(src,event) clickShapeFcn(src,event,hFig);
 
%%—————–
function clickShapeFcn(src,event,hFig)
% 図形をクリックした時に実行されるコールバック
 
% ダブルクリック以外は何もしない
if hFig.SelectionType ~= “open”
return
end
 
% オブジェクトの色を取得
c = src.FaceColor;
 
% 赤->緑,緑->青,青->赤の順でサイクル
if isequal(c,[1 0 0])
src.FaceColor = [0 1 0];
elseif isequal(c,[0 1 0])
src.FaceColor = [0 0 1];
else % obj.FaceColor = [0 0 1]
src.FaceColor = [1 0 0];
end
 
end
double_click_animation.gif

例4:マウスでオブジェクトを移動

クリック反応以外に,マウスの動きに対してオブジェクトを反応させることもできます.それには figureWindowButtonMotionFcn プロパティを使います.このプロパティを設定することによって,マウスを動かしている間,何度もこのコールバックが実行し続けられます.
こちらの例では,図形をクリック アンド ドラッグして動かします.マウスをクリックしている間だけ図形が動くようにするためには,以下のような手順になります.
  1. 図形をクリックすると ButtonDownFcn が実行される
  2. ButtonDownFcnで figure の WindowButtonMotionFcn を設定する
  3. WindowButtonMotionFcn で図形の位置をマウスのポジションに合わせる
  4. マウスボタンを離すと figure の WindowButtonUpFcn が実行される
  5. WindowButtonUpFcnWindowButtonMotionFcn を削除する
figure(“WindowButtonUpFcn”,@unclickFcn);
hAx = axes();
 
% 赤い四角
hPatch1 = patch([3 5 5 3],[1 1 3 3],“r”);
 
% 緑の三角
hPatch2 = patch([5 7 6],[4 4 6],“g”);
 
% 青い丸
x = cos(linspace(0,2*pi,100))+2;
y = sin(linspace(0,2*pi,100))+5;
hPatch3 = patch(x,y,“b”);
 
axis(hAx, “equal”)
axis(hAx, [0 8 0 8])
 
hAx.Toolbar.Visible = “off”; % ツールバーを無効化
hAx.Interactions = []; % 操作オブジェクトを無効化
 
% 各図形に,マウスクリックに反応するコールバックを定義
hPatch1.ButtonDownFcn = @clickShapeFcn;
hPatch2.ButtonDownFcn = @clickShapeFcn;
hPatch3.ButtonDownFcn = @clickShapeFcn;
 
%%————
function clickShapeFcn(hPatch,event)
% 図形をクリックした時に実行されるコールバック
clickPt = get(gca,“CurrentPoint”); % クリックした座標
deltaX = hPatch.XData – clickPt(1,1); % 図形の座標とクリック座標の差
deltaY = hPatch.YData – clickPt(1,2); % 図形の座標とクリック座標の差
 
set(gcf,“WindowButtonMotionFcn”, @(o,e) mouseMoveFcn(hPatch,deltaX,deltaY));
end
 
%%————
function mouseMoveFcn(hPatch, deltaX, deltaY)
% マウスを移動している間実行されるコールバック
mousePt = get(gca,“CurrentPoint”);
hPatch.XData = deltaX + mousePt(1,1);
hPatch.YData = deltaY + mousePt(1,2);
end
 
%%————
function unclickFcn(hFig,event)
% マウスボタンが離された時に実行されるコールバック
hFig.WindowButtonMotionFcn = ;
end
move_shape_animation.gif

最後に

今回はマウスを使ったグラフィックス オブジェクトの操作方法について見てみました.実は,マウスボタンや動きに対する反応以外に
などがあります.いろいろ駆使するとグラフィックス オブジェクトだけでもかなり複雑なインタラクティブアプリを作る事ができます.もちろんプッシュボタンやスライダーなどを使うともっとリッチなアプリが作れます
最後に,この記事で紹介したコールバックを組み合わせて作った Signal Manipulator をお見せして終わりにしたいと思います.
function sigManipulator()
 
hFig = figure(“WindowButtonUpFcn”,@unclickFcn);
hAx = axes;
axis(hAx,[0 10 0 10])
 
cm = uicontextmenu(hFig);
uimenu(cm,“Text”,“linear”,“MenuSelectedFcn”,@changeFitType,“Checked”,“on”);
uimenu(cm,“Text”,“pchip”,“MenuSelectedFcn”,@changeFitType);
uimenu(cm,“Text”,“spline”,“MenuSelectedFcn”,@changeFitType);
 
fitType = “linear”;
 
title(“マウスで数箇所クリックをして終わったらEnterキーを押してください”,“FontName”,“Meiryo UI”)
xy = ginput;
xx = linspace(min(xy(:,1)),max(xy(:,1)),100);
yy = interp1(xy(:,1),xy(:,2),xx,fitType);
id = [];
hold on
hFit = plot(xx,yy,“-“,“LineWidth”,2,“ContextMenu”,cm,“ButtonDownFcn”,@clickLine);
hLine = plot(xy(:,1),xy(:,2),“o”,“MarkerFaceColor”,“r”,“MarkerSize”,10,“ButtonDownFcn”,@clickPoint);
hold off
axis(hAx,[0 10 0 10])
title(“”)
 
function changeFitType(src,event)
% 補間手法の変更(コンテキストメニュー)
temp = [“off” “off” “off”];
[cm.Children.Checked] = temp{:};
src.Checked = “on”;
fitType = src.Text;
updateFit()
end
 
function clickLine(src,event)
% 線をダブルクリックした時に点を追加
if hFig.SelectionType ~= “open”
return
end
pt = hAx.CurrentPoint(1,1:2);
xy = [xy;pt];
updatePoints()
updateFit()
end
 
function clickPoint(src,event)
% データ点をクリック(クリック アンド ドラッグ機能の設定)
pt = hAx.CurrentPoint(1,1:2);
[~,id] = min(sum((xy – pt).^2,2));
hFig.WindowButtonMotionFcn = @pointMoveFcn;
end
 
function pointMoveFcn(src,event)
% データ点をドラッグ
pt = hAx.CurrentPoint(1,1:2);
xy(id,:) = pt;
updatePoints()
updateFit()
end
 
function updatePoints()
% 描画のデータ更新
hLine.XData = xy(:,1);
hLine.YData = xy(:,2);
end
 
function updateFit()
% 補間グラフの更新
xx = linspace(min(xy(:,1)),max(xy(:,1)),100);
yy = interp1(xy(:,1),xy(:,2),xx,fitType);
hFit.XData = xx;
hFit.YData = yy;
end
 
function unclickFcn(src,event)
% マウスボタンを離す
hFig.WindowButtonMotionFcn = “”;
end
 
end
signal_creator_animation.gif

|
  • print

Comments

To leave a comment, please click here to sign in to your MathWorks Account or create a new one.