前回のおさらい
前回は、簡単なお絵描きツールとして、マウス操作をキャプチャするfigureのコールバック関数を中心に紹介しました。
今回の内容
せっかくなので、「消去」「画像保存」「線の色変更」「線の太さ変更」ができるように、お絵描きツールを拡張します。
ポイントとなる技術は、ボタンの作成と、各種ダイアログの使用です。
共通変数の追加
前準備として、線の色と線の幅の設定を保存するための変数を追加します。
ここでは、コールバック関数をネスト関数とすることで、共通に呼び出せるようにします。
LineColor = [0,0.4470,0.7410]; % Lineの色
LineWidth = 1; % Lineの線幅
線を描画するところも以下のように変更し、色と線幅を指定するようにします。
curLineH = line(axH,curLineX,curLineY,'Color',LineColor,'LineWidth',LineWidth);
ボタンの配置
axes 表示域を少し小さくして、ウィンドウの下にボタンを配置します。
figure上のボタンは、uicontrol で Style をpushbutton に指定して作成します。
なお、uicontrol のStyle のデフォルト設定が、pushbutton なので、Style指定は省略することもできます。
axes の更新
前回のコードを以下のように少し修正します。
Position を変更して、figureの下部分に、ボタンを表示する領域を確保します。
また、画像保存するときに、枠表示が邪魔になるので、XAxis, YAxisのColorの指定を'none' にします。
%% Axesの表示
axH = axes(figH); % axH: 軸オブジェクト
axH.XTick = []; % X軸目盛をオフ
axH.YTick = []; % Y軸目盛をオフ
axH.Units = 'normalized'; % Positionの単位指定
axH.Position = [0,0.1,1,0.9]; % Axesの位置指定 (下10%の領域はボタン用に残す)
axH.XLim = [0,1]; % X軸範囲を指定
axH.YLim = [0,1]; % Y軸範囲を指定
axH.XAxis.Color ='none'; % 枠を無色に指定
axH.YAxis.Color ='none'; % 枠を無色に指定
ボタンの作成
例えば、「消去」用のボタンは、uicontrol を使って、以下のように設定します。
ボタンに表示する文字は、Stringで指定し、またボタン押下時のコールバック関数は、Callback に指定します。
% 消去ボタン
btnClearH = uicontrol(figH); % btnClearH :「消去」のボタンオブジェクト
btnClearH.Units = 'normalized'; % Position の単位指定
btnClearH.Position = [0,0,0.1,0.1]; % ボタンの位置指定
btnClearH.String = '消去'; % 表示文字列の指定
btnClearH.Callback = @Callback_btnClearH; % コールバック関数の指定
コールバック関数の指定
コールバック関数には、ボタン押下時の処理を記載します。
「消去」ボタンのコールバック
findobj で axes 上の Lineを探索し、deleteですべて消去するようにします。
function Callback_btnClearH(~,~)
%% 消去ボタンのコールバック
delete(findobj(axH,'Type','Line')); % Axes上にあるLineをすべて消去
end
「保存」ボタンのコールバック
画像としてファイルに保存するため、まず、ファイル名を取得します。
便利なダイアログがすでにあり、uiputfile を使ってファイル名を指定させます。
ファイル名が指定されれば、print を使ってファイルに保存します。
function Callback_btnSaveH(~,~)
%% 保存ボタンのコールバック
[FileName,PathName] = uiputfile('*.png','保存ファイル名'); % ファイル名の指定
if ischar(FileName)
% キャンセルでない場合
print(figH,'-dpng','-noui',fullfile(PathName,FileName));
end
end
ファイル指定のダイアログは、次のようなものが立ち上がります。
「線色」のコールバック
線の色を変更するために、色を指定します。
色の指定にも、便利なダイアログがあり、uisetcolor を使って指定します。
function Callback_btnLineColorH(~,~)
%% 線色のコールバック
% ダイアログで色の指定
RGB = uisetcolor(LineColor);
if length(RGB)==3
% キャンセルでない場合
LineColor = RGB;
end
end
色の指定は、次のようなダイアログが立ち上がります。
「線幅」のコールバック
線の幅(太さ)を指定します。
ここでは、簡単のため、inputdlg を使って入力します。
inputdlg の結果は文字列になるため、数値に変換します。
function Callback_btnLineWidthH(~,~)
%% 線幅のコールバック
% ダイアログで線幅の指定
WidthStr = inputdlg('線幅','',1,{num2str(LineWidth)});
if ~isempty(WidthStr)
% キャンセルでない場合
% 文字列から数値に変換
Width = str2double(WidthStr);
if ~isnan(Width)
% 数値に変換できたとき線幅を変更
LineWidth = Width;
end
end
end
線の指定では、次のようなダイアログが立ち上がります。
完成したプログラム
実行しやすいようにプログラム全体を表示します。
function simple_draw2()
%% 共通変数の定義
ButtonState = false; % マウスボタンの押下状態
curLineH = gobjects(); % 現在のLineのオブジェクト
curLineX = []; % 現在のLineのX座標
curLineY = []; % 現在のLineのY座標
LineColor = [0,0.4470,0.7410]; % Lineの色
LineWidth = 1; % Lineの線幅
%% Figureの表示
figH = figure(); % figH: Figureオブジェクト
figH.MenuBar = 'none'; % メニューをオフ
figH.WindowButtonDownFcn = @WindowButtonDownFcn_figH; % マウスボタン押下時のコールバック関数を指定
figH.WindowButtonMotionFcn = @WindowButtonMotionFcn_figH; % マウスボタン移動時のコールバック関数を指定
figH.WindowButtonUpFcn = @WindowButtonUpFcn_figH; % マウスボタンリリース時のコールバック関数を指定
%% Axesの表示
axH = axes(figH); % axH: 軸オブジェクト
axH.XTick = []; % X軸目盛をオフ
axH.YTick = []; % Y軸目盛をオフ
axH.Units = 'normalized'; % Positionの単位指定
axH.Position = [0,0.1,1,0.9]; % Axesの位置指定 (下10%の領域はボタン用に残す)
axH.XLim = [0,1]; % X軸範囲を指定
axH.YLim = [0,1]; % Y軸範囲を指定
axH.XAxis.Color ='none'; % 枠を無色に指定
axH.YAxis.Color ='none'; % 枠を無色に指定
%% ボタン
% 消去ボタン
btnClearH = uicontrol(figH); % btnClearH :「消去」のボタンオブジェクト
btnClearH.Units = 'normalized'; % Position の単位指定
btnClearH.Position = [0,0,0.1,0.1]; % ボタンの位置指定
btnClearH.String = '消去'; % 表示文字列の指定
btnClearH.Callback = @Callback_btnClearH; % コールバック関数の指定
% 保存ボタン
btnSaveH = uicontrol(figH); % btnSaveH :「保存」のボタンオブジェクト
btnSaveH.Units = 'normalized'; % Position の単位指定
btnSaveH.Position = [0.1,0,0.1,0.1]; % ボタンの位置指定
btnSaveH.String = '保存'; % 表示文字列の指定
btnSaveH.Callback = @Callback_btnSaveH; % コールバック関数の指定
% 線色ボタン
btnLineColorH = uicontrol(figH); % btnLineColorH :「線色」のボタンオブジェクト
btnLineColorH.Units = 'normalized'; % Position の単位指定
btnLineColorH.Position = [0.2,0,0.1,0.1]; % ボタンの位置指定
btnLineColorH.String = '線色'; % 表示文字列の指定
btnLineColorH.Callback = @Callback_btnLineColorH; % コールバック関数の指定
% 線幅ボタン
btnLineWidthH = uicontrol(figH); % btnLineWidthH :「線幅」のボタンオブジェクト
btnLineWidthH.Units = 'normalized'; % Position の単位指定
btnLineWidthH.Position = [0.3,0,0.1,0.1]; % ボタンの位置指定
btnLineWidthH.String = '線幅'; % 表示文字列の指定
btnLineWidthH.Callback = @Callback_btnLineWidthH; % コールバック関数の指定
%% コールバック関数の定義
function WindowButtonDownFcn_figH(~,~)
%% マウスボタン押下時のコールバック
ButtonState = true; % 押下状態を保存
% マウスの位置の取得
curLineX = axH.CurrentPoint(1,1);
curLineY = axH.CurrentPoint(1,2);
% 線の描画
curLineH = line(axH,curLineX, curLineY,'Color',LineColor,'LineWidth',LineWidth);
end
function WindowButtonMotionFcn_figH(~,~)
%% マウスボタン移動時のコールバック
if ButtonState
% マウスボタンを押下時には、Lineの描画を更新
% 現在のマウスの位置
X = axH.CurrentPoint(1,1);
Y = axH.CurrentPoint(1,2);
% 線の座標値を更新
curLineX = [curLineX;X];
curLineY = [curLineY;Y];
% 描画の更新
curLineH.XData = curLineX;
curLineH.YData = curLineY;
end
end
function WindowButtonUpFcn_figH(~,~)
%% マウスボタンリリース時のコールバック
ButtonState = false; % ボタン押下状態を解除
end
function Callback_btnClearH(~,~)
%% 消去ボタンのコールバック
delete(findobj(axH,'Type','Line')); % Axes上にあるLineをすべて消去
end
function Callback_btnSaveH(~,~)
%% 保存ボタンのコールバック
[FileName,PathName] = uiputfile('*.png','保存ファイル名'); % ファイル名の指定
if ischar(FileName)
% キャンセルでない場合
print(figH,'-dpng','-noui',fullfile(PathName,FileName));
end
end
function Callback_btnLineColorH(~,~)
%% 線色のコールバック
% ダイアログで色の指定
RGB = uisetcolor(LineColor);
if length(RGB)==3
% キャンセルでない場合
LineColor = RGB;
end
end
function Callback_btnLineWidthH(~,~)
%% 線幅のコールバック
% ダイアログで線幅の指定
WidthStr = inputdlg('線幅','',1,{num2str(LineWidth)});
if ~isempty(WidthStr)
% キャンセルでない場合
% 文字列から数値に変換
Width = str2double(WidthStr);
if ~isnan(Width)
% 数値に変換できたとき線幅を変更
LineWidth = Width;
end
end
end
end
実行例
起動するとボタン付きの figureが表示されます。
実際に絵を描いてみます。(相変わらず絵心がなくてすみません。。。)
終わりに
この例では、uicontrol を使って、figure上にボタンを配置してお絵描きツールを拡張しました。
uiputfile, uisetcolor, inputdlg といったダイアログを使用することで、各ボタンの操作も簡単に記述できました。
他にも、背景色の変更やグリッドの表示、等、いろんな機能を追加することもできると思います。
よくある子供向けのお絵描きアプリには、書いた絵が動くようなものも多いので、そのような実装も可能でしょう。以上を参考に様々なアイデアを実装してみてください!