【C++/CLI】アンカープロパティによるフォームのリサイズ処理

フォームのリサイズ時にボタンなどの位置をフォームの大きさに合わせて調整する場合、位置を調整するコントロールのAnchorプロパティを設定すると簡単に位置調整が可能となります。

 

 

Anchorプロパティは指定した方向がリサイズ時の位置の基準となり、指定した方向の距離が一定に保たれるようにコントロールの位置が調整されます。

 

何はともあれ、以下の動きを見て頂くと分かりやすいと思います。

 

【button1~button4:Top,Leftの場合】※Top,Leftはデフォルト設定値です。


 

【button4:Bottom,Rightの場合】

 

【button2,button4:Top,Left,Rightの場合】

 

【button3,button4:Bottomの場合】

 

【button4:Top,Bottom,Left,Rightの場合】

 


VB6.0の時はフォームのリサイズイベントで座標を計算しながら位置を調整していましたが、.NETからは、このAnchorプロパティを使う事でやたらと簡単になりました。

【C++/CLI】フォーム間参照

下図のように、メインのフォームから設定値を設定するための子ウィンドウ(ダイアログボックス)を
表示し親のウィンドウに値を設定しなおす方法を紹介します。

 

 

フォームを開く

フォームをモーダルで表示する場合はShowDialogメソッドを、
モードレスで表示する場合はShowメソッドを用います。

 

(コード例) Form1.hにて

#include "Form2.h"
:
:
Form2^ frm2 = gcnew Form2;
//Form2の表示、Form2の親(Owner)をForm1(this)に設定
frm2->ShowDialog(this);

ここでのポイントはForm1からForm2を参照できるようにForm2をfrm2という
フィールド(メンバ変数)に代入していることと、Form2の親がForm1であることがわかるように
ShowDialogメソッドでthisを設定しています。
こうすることで、自分のフォームの親はどのフォームなのか?を調べる場合はフォームの
Ownerプロパティを参照することで可能となります。

 

別フォームの参照

別のフォームからテキストボックスなどのオブジェクトを参照する場合には

 

frm2->textBox1->Text

 

などとしたくなるのですが、デフォルトではエラーとなってしまいます。
そこで別のフォームからオブジェクトを参照できるようにオブジェクトのModifiersプロパティ
Publicなどに設定すると、別のフォームからオブジェクトを参照できるようになります。

 

 

循環参照(相互参照)

今回の例のように、Form1からForm2を参照、Form2からForm1を参照するので、
Form1.hにて

#include “Form2.h”

Form2.hにて

#include “Form1.h”

としたくなるのですが、お互いを参照してグルグル回ってしまうので、ヘッダの宣言の部分を
*.hファイルではなく、*.cppファイルに持って行きます。

今回のサンプルの例ではイベント処理の部分も*.cppファイルに持っていって

 

(コード例) Form2.cppにて

#include "StdAfx.h"
#include "Form2.h"

#include "Form1.h"

using namespace prjForm;

System::Void Form2::Form2_Load(System::Object^  sender, System::EventArgs^  e) {

    Form1^ ParentForm;

    if (this->Owner != nullptr){
        //親のフォームクラス
        ParentForm = static_cast<Form1^>(this->Owner);

        this->textBox1->Text = ParentForm->textBox1->Text;
        this->textBox2->Text = ParentForm->textBox2->Text;
        this->textBox3->Text = ParentForm->textBox3->Text;
    }
}

 

サンプルプログラム

このサンプルプログラムはフォーム間参照サンプルプログラムでダウンロードができます。
VisualStudio2005 Express Edition で作成しています。

 

【C++/CLI】フォーム(ウィンドウ)のサイズ固定

プログラム実行時のウィンドウのサイズをユーザに変えられないようにサイズを固定するには
フォームのFormBorderStyleプロパティFixed××に設定します。

 

 

なんとなく、FormResizeみたいなプロパティが無いか?探したくなっちゃいます...

 

ちなみに、こちら↓はVB6.0のプロパティ

VB6.0ではBorderStyleプロパティです。

 

【C++/CLI】ウィンドウの押されたボタンを取得(DialogResultプロパティ)

一般的なウィンドウでは下図のようにOKボタンCancelボタンを配置しボタンが押されるとウィンドウを閉じるようにしますが、このOKボタンCancelボタンのどちらのボタンを押されたのか?を取得する方法を紹介します。

 

 

まず、buttonコントロールOKボタンCancelボタン用の2つを配置します。
次にボタンのDialogResultプロパティの中からボタンに応じてOKCancelなどを選択します。

 

 

DialogResultプロパティを設定することで、ボタンが押されると自動的にウィンドウが閉じられるので、ボタンのイベント処理を記載する必要はありません。 (ShowDialogメソッドを使ってフォームを表示した場合)
ただし、ウィンドウが非表示になるだけなので、ウィンドウが必要なくなったら、フォームを解放しておきます。

 

以下、Form2が閉じられた時に、何のボタンを押されてウィンドウが閉じられたのか?
を取得する部分のサンプルプログラムです。

 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
     //Form2を開く
     Form2^ frm = gcnew Form2();
     frm->ShowDialog();

     //押されたボタン別の処理
     if (frm->DialogResult == System::Windows::Forms::DialogResult::OK)
          MessageBox::Show("Okボタンが押されました");
     else if (frm->DialogResult == System::Windows::Forms::DialogResult::Cancel)
          MessageBox::Show("Cancelボタンが押されました");

     //フォームの解放
     delete frm;
    }

実行例

Form2を開くボタンをクリック

 

 

OKボタンをクリックすると、Form2のウィンドウが閉じられ、

 

 

と表示されます。

ウィンドウの×ボタンでウィンドウが閉じられた場合はCancelボタンとして認識されます。

【OpenCV2.2】サンプルプログラム(C++/CLI版)

先日、C言語によるOpenCVのサンプルプログラムについては、

 

【OpenCV2.2】新規プロジェクトの作成方法(C言語版)

 

のページにて紹介しましたが、C言語だとウィンドウの作成やマウスイベント処理などが、少々面倒です。
そこで、.NETの中でもC言語寄りなC++/CLIを使って、OpenCVのIplImageを.NETのBitmapへ変換し、GUI部分は、.NETに任せて、より簡単なウィンドウプログラムを作ってみました。

 

サンプルプログラムはこちら→OpenCV22_CLISample.zip

動作環境

  • Visual Studio 2010 Express C++/CLI
  • OepnCV2.2 (OpenCV2.2のコンパイル済みのライブラリをデフォルトでセットアップした状態の設定になっています。)

 

このサンプルではファイルメニューから画像ファイルを開き、二値化、平滑化などの簡単なフィルタ処理を行い、マウスポインタを画像上で動かすと、左下のステータスバーに輝度値が表示されるようになっています。

 

このサンプルプログラムは、できるだけ初心者の方にも分かり易く?書いたつもりですが、逆に、ある程度詳しい人にとっては、画像の描画の部分など、無駄に見える部分もあるかと思いますが、そのへんの最適化はみなさんにお任せします。

(あまりマジメに書くと、本職に支障が出そうなので...)

といっても、このサンプル、そこそこ便利だと思います。

 

OpenCVへ戻る

 

【OpenCV】IplImageから.NETのBitmapへ変換

OpenCVのプログラムを作っていると、OpenCV用のGUI(highgui)はかなり物足りなく、ウィンドウや表示まわりは.NETに任せたいので、OpenCVのIplImageから.NET(C++/CLI)のBitmapへ変換すると、簡単にウィンドウプログラムを作成する事が可能となります。

 

変換部分のサンプルプログラムは以下の通りです。

// IplImage の確保
IplImage *src_img = cvLoadImage("c:\\Sample.bmp");
//  IplImageからBitmapの確保
Bitmap^ bmp = gcnew Bitmap(src_img->width, src_img->height, src_img->widthStep,
      System::Drawing::Imaging::PixelFormat::Format24bppRgb, (IntPtr)src_img->imageData);

ただし、PixelFormatはIplImageで確保した画像データのdepthおよびnChannelsに合わせて設定して下さい。

 

PixelFormat depth nChannels
Format8bppIndexed 8 1
Format24bppRgb 8 3

 

他の組合せも考えられますが、.NETやOpenCVの関数が対応していないものが多いので、実質的に、この2つの組合せになると思います。
モノクロ8Bit画像(Format8bppIndexed)の場合は、別途、カラーパレットを設定する必要があります。
カラーパレットの設定については、8Bitモノクロのカラーパレット設定方法のページを参照願います。

 

ここで作成したBitmapをPictureBoxに表示する場合、

 

pictureBox1->Image = bmp;

 

とすると

 

‘System.AccessViolationException’ のハンドルされていない例外が System.Drawing.dll で発生しました。
追加情報: 保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。

 

というエラーメッセージが出てしまうので、DrawImageを使って

 

g->DrawImage(bmp, 0, 0, src_img->width, src_img->height);

 

というようにして、ピクチャボックスへ描画します。

 

ちなみに今回はIplImageからBitmapクラスへ変換する方法を紹介しましたが、BitmapクラスからIplImageへ変換する場合はBitmapクラスのポインタがガーベージコレクションにより移動してしまう可能性があるので、BitmapのポインタをLock~Unlockで取得し、IplImageのimageDataへコピーすればよいと思います。

 

また、OpenCV2.0からは画像データにC++用のcv::Matがありますが、cv::Matでは画像データのメモリの幅が4の倍数に調整されていないので、画像の幅が4の倍数でない場合はcv::Matと.NETのBitmapとではメモリのサイズが異なるため、そのままcv::MatのポインタをBitmapへ渡す事ができません。
そのため、cv::MatからBitmapへ変換する場合はcv::MatそのものをIplImageを確保してからcv:Matへ変換するか、画像の1行ごとにデータをコピーするなどの工夫が必要となります。

 

 

OpenCVへ戻る

 

【C++/CLI】画像の拡大縮小表示(簡易版)

C++/CLIで簡単にできる画像の拡大縮小表示を紹介します。

 

今回、作成したプログラムはこんな感じ↓です。

 

 

このサンプルプログラムはこちら
SimpleZoomImage.zip
(VisualStudio2005 Express Edtionで作成)

 

作成手順は本当に簡単。
下図のようにフォームの上にMenuStripPanel、Panelの上にPictureBoxと配置していきます。

 

 

Panelをクリックすると、右上に三角マークが表示されるので、それをクリックし、
親コンテナにドッキングするをクリックします。

 

 

次にパネルとピクチャボックスのプロパティを以下のように設定します。

 

panel1->AutoScroll = true;
pictureBox1->SizeMode = System::Windows::Forms::PictureBoxSizeMode::Zoom;

 

■AutoScroll

trueに設定するとパネル上に配置されたコントロールコンテンツ(ピクチャボックスなど)がパネルの大きさより大きい場合は自動的にスクロールバーを表示し、コントロールをスクロールしてくれます。

■SizeMode

ピクチャボックスに設定されたイメージをどのように表示するかを設定します。

 

Normal 画像をピクチャボックスの左上に合わせて表示します。
StretchImage 画像をピクチャボックスの幅、高さに合わせて表示します。
画像をピクチャボックスの幅、高さに合わせて表示します。
AutoSize ピクチャボックスのサイズを画像サイズに合わせて変更します。
CenterImage ピクチャボックスの中心と画像の中心を合わせるようにして表示します。画像サイズがピクチャボックスより大きい場合は、画像がはみ出して表示されます。
Zoom 画像全体をピクチャボックス全体に表示するように画像表示サイズを変更し、ピクチャボックスの中心に表示します。
画像の縦横比はくずれません。

 

画像の読み込みは、こんな感じ↓です。

 

private: System::Void mnuFileOpen_Click(System::Object^  sender, System::EventArgs^  e) {
	//ファイルを開くダイアログの作成
	OpenFileDialog^ dlg = gcnew OpenFileDialog;
	//ファイルフィルタ
	dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,*.ico)|*.bmp;*.jpg;*.png;*.tif;*.ico";
	//ダイアログの表示
	dlg->ShowDialog();
	//ビットマップファイルから、Bitmapを作成
	Bitmap^ bmp = gcnew Bitmap(dlg->FileName);
	//ピクチャボックスをビットマップ画像サイズに合わせる
	pictureBox1->Width = bmp->Width;
	pictureBox1->Height = bmp->Height;
	//ピクチャボックスのImageへ
	pictureBox1->Image = bmp;
}

あとは、ピクチャボックスの大きさを拡大縮小したい倍率に合わせて変更すれば、勝手に画像は拡大縮小し、スクロールバーは自動的に調整してくれます。

private: System::Void mnuZoomEnlargement_Click(System::Object^  sender, System::EventArgs^  e) {
	//拡大(2倍)
	pictureBox1->Width *= 2;
	pictureBox1->Height *= 2;
}
private: System::Void mnuZoomReduce_Click(System::Object^  sender, System::EventArgs^  e) {
	//縮小(1/2倍)
	pictureBox1->Width /= 2;
	pictureBox1->Height /= 2;
}

と、これだけ!
本当に簡単にすごいことができちゃいます。

ただし、この方法では、大きい画像やモノクロの画像の上に線などの描画ができません。
その場合はDrawImageメソッドをお使い下さい。

【C++/CLI】8Bitモノクロのカラーパレット設定方法

モノクロ8Bitの画像を新規に作成する場合の、モノクロのカラーパレットは、以下のように作成します。

 

//8BitのBitmap作成
Bitmap^ bmp = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height, Imaging::PixelFormat::Format8bppIndexed);

Imaging::ColorPalette^ pal = bmp->Palette;

for (i = 0; i < 256; i++){ pal->Entries[i] = Color::FromArgb(255, i, i, i);
}

bmp->Palette = pal;

 

この処理を使ったサンプルプログラムは、こちらです。
cppcli_colorpalette(Visual C++ 2005 Express Editionで作成 )

 

プログラムのイメージはこんな感じです。

 

【C++/CLI】System::String^からchar*へ変換

アンマネージのC言語で作られたライブラリなどへ.NETのプログラム(マネージ)から文字列を渡す場合、System::String^からchar*へ変換する必要があります。

 

この場合、
System::Runtime::InteropServices::Marshal::StringToHGlobalAnsiメソッド
を使って変換します。
char*ポインタを使い終わったら
System::Runtime::InteropServices::Marshal::FreeHGlobalメソッド
でメモリを解放します。

 

以下、.NETのファイルを開くダイアログボックスを使ってファイル名を取得し、OpenCVの画像読込関数(cvLoadImage)へ渡す例を示します。

 

//ファイルを開くダイアログの作成
OpenFileDialog^ dlg = gcnew OpenFileDialog;
//ファイルフィルタ
dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,jp2)|*.bmp;*.jpg;*.png;*.tif;*.jp2";
//ダイアログの表示
dlg->ShowDialog();

//System::String^型のファイル名
System::String^ strFilename = dlg->FileName;
//System::String^からchar*へ変換
char* pStr = (char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(strFilename).ToPointer();
//アンマネージ関数へchar*を渡す
IplImage *src_img = cvLoadImage(pStr, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
//メモリの解放
System::Runtime::InteropServices::Marshal::FreeHGlobal((IntPtr)pStr);

 

【C++/CLI】新しくウィンドウを開く/閉じる

例えば、Form1からForm2というフォームを表示する場合は、

 

モーダル表示

表示したウィンドウしか操作できないウィンドウを開く

#include "Form2.h"

(中略)

Form2^ frm = gcnew Form2();
// モーダル表示
frm->ShowDialog(this);

 

モーダレス表示

表示したウィンドウと表示元のウィンドウの両方が操作できる

#include "Form2.h"

(中略)

Form2^ frm = gcnew Form2();
// モーダレス表示
frm->Show(this);

 

フォームを閉じる場合

frm->Close();

のようにします。

 

ShowDialogおよびShowの引数で渡しているthisは無くてもよいのですが、このthisを渡す事で、
Form2からthis->Ownerを参照する事で、親のフォーム(どのフォームから呼ばれたのか?)が分かるので、thisを渡した方が何かと便利です。

 

また、

frm->Hide();

のようにすると、フォームそのものは破棄されずウィンドウを非表示にする事ができます。
そのため、再びウィンドウを表示したい場合は、再度

frm->Show();

を呼び出すと、Hide()する直前の状態のフォームが表示されます。

 

【C++/CLI】マウスイベント処理

マウスイベント(マウスをクリック、ダブルクリックなど)の処理を追加するには、イベント処理を行うオブジェクト(ピクチャボックスやボタンなど)を選択した状態でイベントのプロパティウィンドウを表示し、イベント処理の文字の部分をダブルクリックします。

 

 

すると、イベントハンドラが自動的に作成されます。
下記の例はMouseClickを追加した場合

 

this->pictureBox1->MouseClick += gcnew System::Windows::Forms::MouseEventHandler(this, &Form1::pictureBox1_MouseClick);

:
:

private: System::Void pictureBox1_MouseClick(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {

        //この位置にイベント処理を追加する。

}

 

このイベントハンドラ内にイベント処理を追加していきます。

 

ここで注意しないといけないのが、pictureBox1_MouseClickという名前になっていますが、必ずしもpicutureBox1からのイベントとは限りません。
どのオブジェクトかは、最初の引数の System::Object^ sender を参照します。
sender のプロパティはそのまま参照できないので、下記のようにキャストします。

 

PictureBox^ pic = static_cast<PictureBox^>(sender);

 

また、マウスのどのボタンがクリックされ、どの位置でクリックされたか?などは2番目の引数の
System::Windows::Forms::MouseEventArgs^ e を参照します。

 

ボタンの判別例は以下の通りです。

 

if (e->Button == System::Windows::Forms::MouseButtons::Left){
      //左ボタンクリック
      MessageBox::Show("左ボタンがクリックされました。");
}else if (e->Button == System::Windows::Forms::MouseButtons::Right){
      //右ボタンクリック
      MessageBox::Show("右ボタンがクリックされました。");
}else if (e->Button == System::Windows::Forms::MouseButtons::Middle){
      //中ボタンクリック
      MessageBox::Show("中ボタンがクリックされました。");
}

 

クリックされた位置のX座標は e->X、Y座標は e->Y で取得できます。

 

また、マウスをクリックした時にShiftキー、Ctrlキー、Altキー、が押されているかどうかを判別するにはControl::ModifierKeysプロパティを参照すれば良いのですが、厳密にはマウスがクリックされたときのキーを取得するのはなく、Control::ModifierKeysプロパティが呼ばれた時のキーを取得するので、ご注意下さい。

 

//Shift,Ctrl,Altキーが押されているか?
Keys key = Control::ModifierKeys;

if ((key & Keys::Control) == Keys::Control){
      //Controlボタンクリック
      MessageBox::Show("Controlボタンがクリックされました。");
}else if ((key & Keys::Shift) == Keys::Shift){
      //Shiftボタンクリック
      MessageBox::Show("Shiftボタンがクリックされました。");
}else if ((key & Keys::Alt) == Keys::Alt){
      //Altボタンクリック
      MessageBox::Show("Altボタンがクリックされました。");
}

マウスイベントには以下のようなものがあります。

 

イベント 意味
Click クリックされたとき
DoubleClick ダブルクリックされたとき
MouseCaptureChanged マウスのキャプチャがなくなるとき(意味不明???)
MouseClick マウスでクリックされたとき
MouseDoubleClick マウスでダブルクリックされたとき
MouseDown マウスボタンが押されたとき
MouseEnter マウスポインタがコントロールの外側から内側に入ったとき
MouseHover マウスポインタがコントロール上に留まっているとき
MouseLeave マウスポインタがコントロールの内側から外側に出たとき
MouseMove マウスポインタがコントロール上を移動したとき
MouseUp マウスボタンが離されたとき
MouseWheel コントロールにフォーカスがあり、マウスホイールが動いたとき

 

ClickイベントとMouseClickイベント、DoubleClickイベントとMouseDoubleClickイベントとは、ほぼ同じですが、2番目の引数が EventArgs^  e か MouseEventArgs^  e の違いがあります。
マウスの情報をより詳しく取得したい場合は Mouse××イベントをお使い下さい。

また、イベントの発生順番は

 

  1. MouseDown
  2. Click
  3. MouseClick
  4. MouseUp
  5. MouseDown
  6. DoubleClick
  7. MouseDoubleClick
  8. MouseUp

 

となります。

 

 

【C++/CLI】メニューを付ける

新規プロジェクトの作成のページでは、何もしないだたのウィンドウ表示のプログラムを作成しましたが、このウィンドウにメニューを付けたいと思います。

 

と、その前に簡単にVisualStudioの操作説明をしたいと思います。

 

フォーム(ウィンドウ)上にメニューやボタンなどを配置するときは、ソリューションエクスプローラのタブを選択し、フォームのファイル(*.h)を選択し、デザイナの表示アイコンをクリックします。

 

 

デザイナの表示からイベント処理などのソースコードを書くときはコードの表示アイコンをクリックします。

 

 

オブジェクト(メニューやボタン、ピクチャボックスなど)の名前や大きさ、位置などの情報を設定するには右下のプロパティタブを選択し、プロパティアイコンをクリックします。

 

 

メニューをクリックしたときなどの処理(イベント処理)を表示するにはイベントアイコンをクリックします。

 

 

と、準備はここまで。

 

フォームファイル(*.h)を選択し、デザイナを表示します。
右側のツールボックスをタブを選択し、この中からMenuStripを選択し、フォームの上にドラッグ&ドロップします。

 

 

次にここへ入力と書かれた部分に表示するメニューの文字を記入していきます。

 

 

ここで、ファイルの文字の右側に(F)と表示されていますが、これはメニューをAltキーを使って操作するときの文字で、文字の入力時にはファイル(&F)のようにアルファベットの頭に&を付けます。
また、メニューの間に表示されている仕切り線(Separator)はここへ入力の部分に - (ハイフン)を入力します。

 

 

ここで、デフォルトではそれぞれのメニューの名前(Name)は開くOToolStripMenuItemなどとなっており、このままだとソースコードに日本語が入ってしまっていまいちなので、それぞれ下表のように名前を付けておきます。

 

Text (Name)
ファイル(&F) mnuFile
開く(&O) mnuFileOpen
終了(&X) mnuFileExit

 

この名前の付け方はVB6.0の時に使っていたプレフィックスを用いていますが、詳しく知りたい方は
このページ↓を参照すると良いと思います。
http://msdn.microsoft.com/en-us/library/aa263493(VS.60).aspx

 

次にメニューをクリックしたときの処理(イベント処理)を追加していきます。
メニューのイベント処理は開く(O)をダブルクリックすると、メニューをクリックした時の処理のソースコードが自動的に作成されます。このへんはVB6.0と同じです。

private: System::Void mnuFileOpen_Click(System::Object^  sender, System::EventArgs^  e) {

             }

 

この{ } の間にメニューをクリックしたときの処理を書いていきます。
下記は開くメニューをクリックした時にファイルを開くダイアログボックスを表示し、ファイル名を眼セージボックスで表示するソースコードです。

 private: System::Void mnuFileOpen_Click(System::Object^  sender, System::EventArgs^  e) {
                 //ファイル→ファイルを開く

                 //ファイルを開くダイアログの作成
                 OpenFileDialog^ dlg = gcnew OpenFileDialog;
                 //ファイルフィルタ
                 dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,*.ico)|*.bmp;*.jpg;*.png;*.tif;*.ico";
                 //ダイアログの表示 (Cancelボタンがクリックされた場合は何もしない)
                 if (dlg->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;
                 //取得したファイル名の表示
                 MessageBox::Show(dlg->FileName);
             }

 

終了メニューは下記の通りです。

 

private: System::Void mnuFileExit_Click(System::Object^  sender, System::EventArgs^  e) {
                 //ファイル→終了
                 this->Close();
             }

【C++/CLI】新規プロジェクトの作成

VisualStudioで新規にC++/CLIのプログラムを作成する場合は以下の手順で行います。

 

VisualStudioを起動すると下図のようなウィンドウが開きます。

 

 

次に作成の文字の右側にあるプロジェクトの文字をクリックします。
すると下図ウィンドウが開きます。

 

 

ここで、

プロジェクトの種類:CLR
テンプレート:Windowsフォームアプリケーション

 

を選択し、プロジェクト名に適当な名前を入力し、OKボタンをクリックします。
(ソリューションのディレクトリを作成のチェックは入れておきます。)
すると下図のようなウィンドウが表示されます。

 

 

この状態で、ツールバーにある再生ボタン(デバッグ開始)をクリックすると、ビルドの確認ダイアログボックスが表示されるので、はいボタンをクリックします。

 

 

するとプログラムがビルドされ、これだけで空のウィンドウが表示されるだけのプログラムが実行されます。

 

 

ところで、ソリューションって何???と思う人もいるかと思いますが、今回はTestというプロジェクトを
作成しましたが、このとき作成されたファイルのディレクトリ構造は以下のようになっています。

Test ←ソリューションフォルダ
┣ Test ←プロジェクトフォルダ
┃  ┣ app.ico
┃  ┣ apprc
┃  ┣ AssemblyInfo.cpp
┃  ┣ Form1.h
┃  ┣ Form1.resX
┃  ┣ ReadMe.txt
┃  ┣ resource.h
┃  ┣ stdafx.cpp
┃  ┣ stdafx.cpp
┃  ┣ stdafx.h
┃  ┣ Test.cpp
┃  ┗ Test.vcproj ←プロジェクトファイル
┣ Test.ncb
┣ Test.sln ←ソリューションファイル
┗ Test.suo

 

となっています。
つまり、プロジェクトの1つ上の階層にソリューションが作成されているのですが、アプリケーションを開発するときに、メインのプロジェクト、ライブラリのプロジェクト、ユーザコントロールのプロジェクトなどを
同時進行で開発する場合など、各プロジェクトを取りまとめるのがソリューションの役目です。
このようにすることで、各プロジェクトをまたいでデバッグができるようになるので、うまく使うと便利な機能です。
もっとも、1つのプロジェクトしか使わない場合はソリューションは邪魔にしか思えないと思いますが、
ソリューションファイル(*.sln)は、必ず1つ作成されます。

 

 

C++/CLIって何?

よく、お使いの言語は何ですか?と尋ねると

 

『Visual C++』

 

です。
という答えが返ってくるのですが、このC++/CLIの登場によって、Visual C++が差すものが何なのか?ますます分からなくなってきました。

 

現在、Visual StudioでC++言語が扱えるのは

  • MFC(Microsoft Foundation Class)
  • SDK(Software Development Kit)
  • C++/CLI

の3つでしょうか?

 

C++/CLIはこれらの良いとこ取りをしたような言語で、GUI部分はVB6.0のようなフォームエディタで作成し、ボタンをダブルクリックする事でイベント処理を追加していきます。
また、従来のWin32 APIも使えるし、MFCのクラスも使えるし、最近主流になってきているVB.NETやC#などが使っている.NET Frameworkも使う事が可能です。

 

また、C#などでは基本的に使えないポインタもそのまま使う事が可能です。

 

もし、これまで、GUIはVB6.0で作って、処理部分はWin32APIや自作のライブラリを作って来たような人にとっては、比較的とっつき易いと思います。

 

ただ、あまりにゴチャゴチャに開発ができるようにしてしまったせいか、最新のVisual Studio 2010ではIntellisenseが使えないなど、ここ最近は、いまいちMicrosoftのやる気が感じられません。

 

という事で、これから先が不透明感のある感じなのですが、これまで作成してきたC++の資産を生かしつつ簡単なGUI周りを作成したい方にはオススメです。
ただし、多少凝ったソフトになると、フォーム間の参照や64bitの対応など、他のVB.NETやC#と比べてかなり面倒なので、評価用のサンプルを作る程度に留めておいた方が無難です。

 

もし、新規にプログラムを始めたい方にはC#の方が良いと思います。
C#もC++/CLIも.NET Frameworkを使うプログラムなので、基本的には同じような物と言いつつも、少しずつC#の方が優遇されているような気がします。

 

なので、C++/CLIで従来のC++のライブラリを使ったクラスライブラリを作成し、画面周りなどのアプリケーションよりな部分はC#で作る!というのが私なりの現在の結論なのですが、C++/CLIの情報は非常に少ないので、記事にまとめていこうと思います。

 

【追記】

結局、C++/CLIを使うのは辞めました。

フォーム間参照が面倒だし、/MT(d)が指定できないし、Any CPUがないし・・・

AnyCPUが無いと、OSが64bitであっても32bitで動いているVisual Studioでは、フォームエディタにカスタムコントロールを配置しようとすると、64bitにコントロールを対応させようとすると、AnyCPUでないと都合が悪いんですよね。

 

という事で、フォーム周りはC#で作る方がおすすめです。