2017. 5.24.
石立 喬

Visual Studio Community 2017の使い方(5)

―― Canvasを使用して、計算結果を文字列で表示する ――

 レイアウトパネルの一つに、図形や画像、文字を描画するのに便利なCanvasがある。ここでは、画像処理などへの応用の手始めとして、文字列を並べて数表を作る例を示す。具体的には、3種類の数表「三角関数」、「対数関数」、「冪関数」の中から、RadioButtonで一種を選び、Canvasを書き換えて表示する。これは、「Visual Studio 2012 Expressの易しい使い方(4)」のUWP版である。

CanvasでWin2Dグラフィックライブラリを使う
 Canvasとは、GridやStackPanelと同様に、内部にコントロール部品を配置できるレイアウトパネルの一つであるが、特に、この内部でCanvasControlクラスを使用すると、画像の描画や処理が可能になる。
 CanvasControlクラスは名前空間のMicrosoft.Graphics.Canvas.UI.Xamlに属し、これは、Win2D APIの一つなので、Win2Dをインストールする必要がある。Win2DはMicrosoftが提供しているオープンソースのWindows Runtime APIで、Direct2Dを使いやすくしたものである。UWP用として「Win2D.uwp」が、MicrosoftのNuGetパッケージマネージャに用意されている。
 イベントにCanvasControl_Drawがあり、このハンドラーに、Canvas上に図形や画像、文字列を描画するメソッドを記述する。このイベントは、最初にCanvasが表示された時、画面が縮小拡大された時、およびInvalidate()メソッドで再描画が強制された時に実行される。ここでは、RadioButtonが切り替えられたときに、数表を書き換えるためにInvalidate()を使用している。
 CanvasDrawingSessionクラスはWin2D APIの主要部分で、各種描画メソッドがある。主なものは下記の通り。
  DrawCircle、DrawEllipse、DrawRectangle、DrawLine、DrawImage、DrawText
  FillCircle、FillEllipse、FillRectangle

Win2Dのインストール
 Win2Dは、Visual Studioから容易にインストールすることができ、下記の手順を用いる。
1)「ソリューションエクスプローラー」で、「ソリューション'App5'(1プロジェクト)」(プロジェクト名は一例)を右クリックする。この代わりに、メニューから、「ツール」→「NuGetパッケージマネージャー」→「ソリューションのNuGetパッケージの管理」でも良い。
2)現れたメニューから、「ソリューションのNuGetパッケージの管理」を選択する。
3)現れたウィンドウで、左上の「参照」タブを選択し、使用できるパッケージのリストを表示させる。
4)左上の検索欄に「win2d」と入力して検索すると、図1に示す候補が現れるので、「Win2d.uwp」を選択し、右側のチェックボックス(図の範囲外のため図には示されていない)にチェックを入れ、これも図にはないが、右下の「インストール」をクリックする。
5)「ライセンスの同意」ウィンドウが開くので、「同意する」をクリックする。


図1 「Win2D.uwp」を選択して、右下(図にはないが)の「インストール」をクリックする



図2 インストールが完了すると、「インストール済み」タブのリストにチェックのついた「Win2D.uwp」のアイコン表示される


CanvasでWin2Dを使用するための準備
 1)XAMLコードのPageの最初の部分で、名前空間 Microsoft.Graphics.Canvas.UI.Xamlを追加する(図3参照)。


図3 xmlnsにnamespaceを設定する


 2)MainPage.xaml.cppに、下記のように名前空間を追加する(図6参照)。
   using namespace Microsoft::Graphics::Canvas;
 3)CanvasとCanvasControlを準備する
 「ツールボックス」の「すべてのXAMLコントロール」欄から「Canvas」を持ってきて、「デザイン」画面上の適当な場所に仮に配置すると、XAMLエディタ上に
   <Canvas HorizontalAlignment="Left" Hight="100" ・・・・・
ができるので、「Canvas」を「canvas:CanvasControl」に書き換え、必要なサイズ、位置に設定変更する(図5参照)。
 4)イベントハンドラーCanvasControl_Drawを生成する
 「XAML」エディタで「CanvasControl」を選択し、「プロパティ」ウィンドウで、名前を「canvas1」とし、Drawイベントの右の空欄をダブルクリックして、イベントハンドラーCanvasControl_Drawを生成する(図4参照、得られたハンドラーは図8参照)。


図4 CanvasControlのDrawイベントのハンドラーを生成する


XAMLコードの作成
 プログラム実行時の画面が図9に示されているので、「デザイン」画面の紹介は省略して、「XAML」エディタの内容を図5に示す。 Pageを閉じるときのイベントハンドラーとして、「Unload="Page_Unloaded"」を追加設定して、Canvasの破棄に使用している。これは、「XAML」エディタで「Page」を選択して「プロパティ」ウィンドウを開き、イベントでUnloadを選んでダブルクリックすることによって得られる。図8に示すイベントハンドラーPage_Unloadのスケルトンも同時に生成される。
 RadioButtonの作成と設定については、すでに述べてあるので、説明は省略する。


図5 CanvasControlとRadioButtonから成るXAMLコード


文字列の扱いについて
 プログラムの作成に当たって、あらかじめ説明が必要と思われるのが、文字列の扱いである。Windows Runtimeの文字列は、C++/CXでは、Platform::Stringクラスで表される。一方、標準のC++文字列では、ワイド文字列に対して、wstringとwchar_t*が用意されている。
 名前空間にPlatformとstdが宣言されているとして、
  wchar_t* → String^ は、String^ string1 = ref new String(wchar1);
  wstring → String^は、String^ string1 = ref new String(wstring1.c_str());
で、
  String^ → wchar_t*は、wchar_t* wchar1 = string1->Data();
  String^ → wstringは、wstring wstring1(string1->Data());
で相互変換できる。
 ここでは、swprintfで、wchar_t*のワイド文字バッファbufferに書き込み、ref new String(buffer)でString^に変換してる。

プログラムの作成
 プログラムは、まず最初に三角関数表をCanvas内に表示する。RadioButtonは、「三角関数」のものを選択状態にしておく(XAMLコードにおいて、名前が「radioSankaku」のRadioButtonに、「IsChecked="true"」として置く)。
 プログラムの起動により、Canvas::Invalidate()が発せられ、CanvasControl_Drawメソッドが呼び出され、radioSankaku->IsChecked->Value == trueが成立して、三角関数表が表示される。
 いずれかのRadioButtonのチェック状態が変更になると、そのためのクリックによりInvalidate()が発生し、その時のRadioButtonの状況により、対応する数表がCanvas上に描画される。
 図6はプログラムの最初の部分で、定数π(C++ではM_PI)のためのインクルードと、Canvasを使用するためなどの名前空間宣言がある。一般に、C++の場合は、<cmath>をインクルードするが、ここではこれが使うとエラーになり、<math.h>が良かった。
◎数表の描画
 図7は、CanvasクラスのInvalidateメソッドにより呼び出されるCanvasControl_Drawメソッドの内容を示したもので、三種類のRadioButtonのいずれかにより、異なった数表をCanvas上に描画する。
◎DrawTextメソッド
 CanvasDrawingSessionクラスは、Canvas上にグラフィックを描画するメソッドを発するのに用いられるが、DrawTextはその一つで、ここで使用する最も単純な形式のものは、
  DrawText(
     string text, ------ Platform::String型
     float x, --------- Canvas上のX座標
     float y, --------- Canvas上のY座標
     Color color ------ Windows::UI::Color型
  )
である。他に、位置をRectangleで表したもの、色をBrushで表したもの、Formatを定義したものなど多くのオーバーロードがある。
◎RadioButtonをクリックした時のイベントハンドラーの作成(図8上)
 いずれのRadioButtonをチェック(クリック)しても、canvas1->Invalidate()を実行するようにプログラムを作成する。方法は下記の通り。
 1)「XAML」エディタで「radioSankaku」を選択し、「プロパティ」ウィンドウで「Click」のイベントハンドラー「radioSankaku_Click」を作成する。
 2)「MainPage.xaml.cpp」をエディタ欄に表示させ、イベントハンドラーradioSankaku_Clickの名称をradio_Clickに書き換える。
 3)「XAML」エディタにできた「Click="radioSankaku_Click"」を「Click="radio_Click"」に書き換える。
 4)「XAML」エディタで、他のRadioButton、すなわち「radioTaisuu」、「radiobeki」についても、「Click="radio_Click"」を追加する。
 5)「MainPage.xaml.h」をエディタ欄に表示させ、そこにできている「void radioSankaku_Click」を「void radio_Click」に書き換える。
◎CanvasControlの解放(図8下)
 Pageを閉じてプログラムを終了するときは、念のためにcanvas1を解放して、メモリーリークを防止する。
 「XAML」エディタで「Page」を選択し、「プロパティ」ウィンドウの「イベント」(稲妻サイン)タブで
「Unload」の右の空欄をダブルクリックすると、「Page_Unload」のイベントハンドラが生成されるので、ここに、RemoveFromVisualTreeメソッドなどを記述し、canvas1をnullptrにする(C#では、単にnullで良い)。


図6 プログラムの最初の部分で、インクルードファイルと名前空間の追加を行う



図7 CanVasControl_Drawメソッドで、RadioButtonに応じた計算と作表が行われる



図8 Canvasの書き換えと破棄のためのプログラム


得られた結果
 得られた結果を図9に示す。プログラムを開始した時には、「三角関数」のRadioButtonにチェックが付いていて、三角関数表が表示される。他のRadioButtonにチェックを付けると他の数表が表示される。「角度」や「値」が常に二桁表示(頭の0を含めて)になっていて見苦しいが、 数字を揃えるためのやむを得ない方法である。




図9 得られた結果


書式設定と使用フォントについて
 数表を作成するには、数値を揃えて表示する必要があり、書式設定が欠かせない。従来、これには、String::Formatが用いられてきたが、これは名前空間Systemに属し、C++/CXでは使えない。当初、「共通言語ランタイムサポート(/clr)」を設定し、Systemを使用しようとしたら、「C++/CLIモードとC++/CXモードを組み合わせることはできません」と拒否された。そこで、C++標準のprintf系を使用した。
 Windows10の標準フォントは、YuGothic UIになっている。これはプロポーショナル(文字によって幅が異なる)なので、書式設定しても、文字の並びが揃わない。
 図10は、通常考えられるプログラムで、エディター上では" "内の上下が揃っている。また、書式指定は%2dで良いはずである。しかし、図11に示す通り、「正弦」、「余弦」の文字が左にずれていて、角度に対する表示でも、「0」が少し左にずれている。これらは、スペースの幅が通常の文字よりも狭いためと考えられる。


図10 「正弦」、「余弦」の文字を、下の「-----」の中央に置いてある



図11 スペースの幅が狭いために、「正弦」、「余弦」の文字が左に寄っている


 これらの現象を考慮して、図7に示す実際のプログラムでは、あらかじめ「正弦」などの文字をずらし、書式指定には、「%02d」(空白の頭に0を付ける)を用いた。








「Visual C++の勉強部屋」(目次)