2006.10.17.
2007. 6.30. Form1_Load()の作成方法を追加
石立 喬

Visual C++ 2005 Express Edition の易しい使い方(7)

――― マウスでパターンを入力し、ファイルに格納する―――


 画面上でマウスをクリックして、視覚的にデータを入力できれば便利である。具体的には、7×11のマトリックス状の桝目に合わせて英数文字フォントを作成する場合を紹介する。このプログラムでは、あらかじめ7×11の桝目を画面上に表示しておき、桝目をマウスでクリックすることにより、フォントを作成する。
  このようにして作成したフォントは別の処理で使用するので、これをデータとして保存し、再び取り出せるようにする。
 プログラム自体は平凡なものであるが、マウスクリックによる座標の取得や、ファイル入出力などが用いられているので、参考になると思われる。

メニューの作成
 すでに説明した方法に従って下記のようにメニューを設定する。

メニューのキャプション 書き換えた名称 イベントハンドラ名 ハンドラの内容
ファイル menuFile menuFile_Click() 何もしない。
開く menuOpen menuOpen_Click() OpenFileDialogを起動。指定されたファイル名のファイルを開き、dataに読み込む。
上書き保存 menuSave menuSave_Click() 読み込み時に使ったファイル名のファイルを開き、dataを書き込む。
名前を付けて保存 menuSaveAs menuSaveAs_Click() SaveFileDialogを起動。指定されたファイル名のファイルを開き、dataを書き込む。
全クリヤ menuClear menuClear_Click() Dataをすべて0にリセットする。

ファイルへの出力
◎上書き保存の場合
 すでに取得しているファイル名fnameを使用して、
     StreamWriter^ swriter=gcnew StreamWriter(fname);
でStreamWriterのオブジェクトを生成する。あとは、swriter->WriteLine(string);で保存し、最後は、swriter->Close();でファイルを閉じる。
◎名前を付けて保存の場合
 保存用のダイアログボックスを、
     SaveFileDialog^ sfdlg=gcnew SaveFileDialog();
で生成し、if(sfdlg->ShowDialog()==::DialogResult::OK) で「OK」を確認し、ダイアログから、sfdlg->FileName; で得たファイル名fnameでStreamWriterを生成する。以後は、上書き保存の場合と同じである。

ファイルからの読込み
 ファイルを開くダイアログボックスを、
    OpenFileDialog^ ofdlg=gcnew OpenFileDialog();
で生成し、 if(ofdlg->ShowDialog()==::DialogResult::OK) で「OK」を確認し、ofdlg->FileName; で得たファイル名fnameを用いて、
    StreamReader^ sreader=gcnew StreamReader(fname);
でStreamReaderのオブジェクトを生成する。あとは、sreader->ReadLine(); で読込み、sreader->Close(); で閉じる。

マウスによる座標の取得
 マウスのボタンを押したことによるイベントハンドラForm1_MouseDown()で、
    x=e->X;
    y=e->Y;
により、座標を取得する。
 左ボタンか右ボタンかの区別は、
    if(e->Button==System::Windows::Forms::MouseButtons::Left)

    if(e->Button==System::Windows::Forms::MouseButtons::Right)
で行なう。

プログラムの概要
1) StreamReaderとStreamWriterを使用するために、名前空間System::IOを記述しておく。
2) 二次元配列dataは、グローバル変数として宣言の後、Form1_Load()で、具体的にサイズを設定する。
  Form1_Load()を記述するには、下記の手続きを行う。
   ・「Form1[デザイン]」画面で、フォームの内部を右クリックし、「プロパティ」ウインドウを開く。
   ・「イベント」ボタン(稲妻の絵が描いてある)をクリックし、「動作」欄の「Load」をダブルクリックする。
   ・「Load」の右に、「Form1_Load」と表示され、同時に、エディタ画面が現れる。
   ・エディタ画面にスケルトンのForm1_Load()ができているので、そこに必要なコードを記述する。
3) ファイル入出力関係のメニューのために、menuOpen_Click()、menuSave_Click()、menuSaveAs_Click()を記述し、マウスクリックして得た入力データdataを一斉に消去するためのmenuClear_Click()を記述する。
4) マウスクリックを検出して、座標を取得するために、Form1_MouseDown()を記述する。左クリックと右クリックを区別するために、
    if(e->Button==System::Windows::Forms::MouseButtons::Left)
などを使用する。左クリックではdataが1にセットされ、右クリックではdataが0にリセットされる。
5) 得られた二次元配列dataを表示するために、Form1_Paint()を記述する。ここでは、7 x 11の枠を描き、dataが1であれば、赤で塗りつぶし、右側に、dataを表示する。

プログラム
 自動設定以外の、実際にコード入力した部分のみを示す。

using namespace System::IO;

static int X0=20,X1=170,Y0=40;
String^ fname;
array<int,2>^ data;

//起動時に呼び出される
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {

   data=gcnew array<int,2>(7,11);

}

//メニュー「ファイル」
private: System::Void menuFile_Click(System::Object^ sender, System::EventArgs^ e) {
}

//メニュー「開く」
private: System::Void menuOpen_Click(System::Object^ sender, System::EventArgs^ e) {

   OpenFileDialog^ ofdlg=gcnew OpenFileDialog();
   ofdlg->Filter="Dataファイル(*.dat)|*.dat";
   if(ofdlg->ShowDialog()!=System::Windows::Forms::DialogResult::OK) return;
   fname=ofdlg->FileName;
   StreamReader^ sreader=gcnew StreamReader(fname);
   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++)
         data[i,j]=int::Parse(sreader->ReadLine());
   sreader->Close();
   Invalidate();

}

//メニュー「上書き保存」
private: System::Void menuSave_Click(System::Object^ sender, System::EventArgs^ e) {

   StreamWriter^ swriter=gcnew StreamWriter(fname);
   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++)
         swriter->WriteLine(data[i,j].ToString());
   swriter->Close();

}

//メニュー「名前を付けて保存」
private: System::Void menuSaveAs_Click(System::Object^ sender, System::EventArgs^ e) {

   SaveFileDialog^ sfdlg=gcnew SaveFileDialog();
   sfdlg->Filter="Dataファイル(*.data)|*.data";
   if(sfdlg->ShowDialog()!=System::Windows::Forms::DialogResult::OK) return;
   fname=sfdlg->FileName;
   StreamWriter^ swriter=gcnew StreamWriter(fname);
   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++)
         swriter->WriteLine(data[i,j].ToString());
   swriter->Close();

}

//メニュー「全クリヤ」
private: System::Void menuClear_Click(System::Object^ sender, System::EventArgs^ e) {

   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++)
         data[i,j]=0;
   Invalidate();

}

//マウスクリック
private: System::Void Form1_MouseDown(System::Object^ sender,
                 System::Windows::Forms::MouseEventArgs^ e) {

   int x=e->X;
   int y=e->Y;
   if(x>X0 && x<X0+128 && y>Y0 && y<Y0+182){
      if(e->Button==System::Windows::Forms::MouseButtons::Left)
         data[(x-X0)/16,(y-Y0)/16]=1;
      if(e->Button==System::Windows::Forms::MouseButtons::Right)
         data[(x-X0)/16,(y-Y0)/16]=0;
   }
   Invalidate();

}

//画面描画
private: System::Void Form1_Paint(System::Object^ sender,
                 System::Windows::Forms::PaintEventArgs^ e) {

   Graphics^ gr=e->Graphics;

   //枠を描く
   for(int j=0;j<=11;j++)
      gr->DrawLine(Pens::Black,X0,Y0+j*16,X0+112,Y0+j*16);
   for(int i=0;i<=7;i++)
      gr->DrawLine(Pens::Black,X0+i*16,Y0,X0+i*16,Y0+176);

   //dataにより赤で塗りつぶす
   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++){
         if(data[i,j]==1){
            gr->FillRectangle(Brushes::Red,X0+i*16+1,Y0+j*16+1,15,15);
         }
      }

   //dataを表示する
   System::Drawing::Font^ font1=gcnew System::Drawing::Font("MS ゴシック",11);
   for(int j=0;j<11;j++)
      for(int i=0;i<7;i++)
         gr->DrawString(data[i,j].ToString(),font1,Brushes::Black,X1+i*16,Y0+j*16);

}

得られた画面
 図1は、このプログラムによるForm1を起動したところで、ファイル関係のメニューができている。まだマウスによる
入力をしていないので、データはすべて0になっている。


図1 未入力で、ファイル関係のメニューを開いたところ


 図2は、マウスクリックによって数字「6」を入力したところで、右側に、対応するデータが表示されている。


図2 マウスで「6」を入力したところ。右にdataが表示されている。