Top Page
 C#
を使う



エクセルが持つ計算機能では何ともならない場合や、周辺機器との通信が必要な場合は、二昔前ならN88-BASIC、一昔前ならVBを使ってプログラムを組むことが一般的でしたが、残念ながらBVも6.0までが限界で、その後は複雑さが便利さを追い越してしまったようです。

そんな訳で、私自身も暫くあちこち手を出してみましたがどうもいけません。SmallBasicは変数の型もなければ、余計なものが何もなくて魅力的なツールなので何とか使いたかったのですが、あまりにも簡素化が進み過ぎた結果、内容が複雑になってくると手に負えなくなって挫折。そこで半ば仕方なく、C#(シー・シャープ)ということになるのですが、同じCの冠が付いているとは言え、C言語とC#は似て非なる言語。

C言語がCPUやメモリ、周辺IOを効率的に制御することを主な目的として開発された言語であり、その先にC++があるのに対して、C#はコード表記上は確かにC的ではあるのですが、それは表向きだけで、中身は根本的に違っている言語のようです。

起動時間とか、反応速度とか見たら、Visual StudioのC#は限度を超えて耐え難く、その文法上の表現方法も、C#独自な部分にはどうも引っ掛かるところもありますが、とにかくやってみないことには始まりません。

そんな訳で、、


C#のインストール

ダウンロード

ここから Visual Studio 2022 の「コミュニティ」の「無料ダウンロード」をクリックしてインストーラーをダウンロードします。インストーラーを続行するとダウンロードする Visual Studioの中身が尋ねられるので「.NET デスクトップ開発」にチェックを入れます。なお、インストールするドライブを指定しない場合はCドライブにインストールされますが、例えばDドライブに余裕がある場合は「インストールの場所」で変更しておいた方がいいでしょう(下図参照)。




実行
インストールを完了し、プログラムを開始すると下のような画面が表示されるので「新しいプロジェクトの作成」を選択し、続行します。



次の画面で、具体的な開発環境を選択します。Visual Studioは、C#だけでなくVisual Basicを始め、各種環境下におけるプログラムの開発が可能なのですが、ここでは「C#コンソールアプリ」か「C#フォームアプリケーション(.NET Framework)」を選択してから「次へ」を指示します。

コンソールアプリはコマンドプロンプト(俗に言う黒画面/DOS画面)を使う開発環境です。グラフィック画面ではないため取っ付きにくく感じられますが、部分的にC#の機能を確認する場合などは手っ取り早くテストできるため重要な環境です。

我々が主に使うのは「C# Windowsフォームアプリケーション(.NET Framework)」です。この開発環境は、普通のWindowd画面で、お馴染みのテキストボックスや、ラベルといった標準的なグラフィックツールを使うことができます。



コンソールアプリ

先ずは入り口のコンソールアプリから。
画面の「コンソールアプリ」をクリックしてから画面右下の「次へ」をクリックすると下図の画面が表示されます。



プロジェクト名に、そのプログラムの題名(テストなら testxx 等)を入れ、場所にフォルダーを指定します。デフォルトのフォルダーにするとWindowsが得意とする奥の引き出しにしまい込まれてしまうため、お薦めではありません。自分専用のフォルダーを指定することをお勧めします。テスト段階なら私はTEMPという一時フォルダーを使って、試しプログラムを作ったり消したりしても残骸が残りにくいようにしています。ただし行けそうだったら、TEMPではなくC#アプリ専用のフォルダーで進めるべきでしょう。フォルダーの移転も不可能ではないようですが、厄介です。

「作成」を指示すると、どうなってしまったのかと心配になるくらい時間が経過し、やがて下のような画面が現れます。(最新のPC環境ではもう少し早いのかも知れませんが、)




これが Visual Studioの画面です。プログラムのコードは@の画面に記述します。なお、プログラムを作成したり動作を確認する作業は「デバッグ」と呼ばれ、その間 Aは Debug の表示にしておきます。
プログラムが完成して第三者にこのファイルを送る時は、 Debug の部分をクリックして Release に変えてからビルド→(プロジェクト名)リビルドをするとbin\Releaseの下のフォルダにexeファイル生成されますから、これを送付します。

ともあれ、開発段階ではAには常にDebugを表示させておき、実行はBのデバッグ→デバッグなしで開始 を使ってプログラムを走らせて動作確認をします。



思ったように動かない場合にのみ、「デバッグの開始」を使います。より詳細なデバッグ情報が表示され、エラーが発生した行が示されます。



C#の文法T

コメント文
 // 以降〜改行 までの文字はプログラムに関係しないコメント、
 /*  と */  に挟まれた全行はコメントとみなされます。


変数の型
変数名はa〜zまたはA〜Zで始まり、数字と _ の組み合わせ。大文字と小文字は区別されます。
 var    暗黙型(コンパイル時に決まる)
 byte    符号なし整数 8ビット  0 〜 255
 sbyte   符号付き整数 8ビット -128 〜 127
 int     符号付き整数 32ビット -2,147,483,648 〜 2,147,483,647
 uint    符号なし整数 32ビット 0 〜 4294967295
 short   符号付き整数 16ビット -32,768 〜 32,767
 ushort   符号なし整数 16ビット 0 〜 65535
 long    符号付き整数 64ビット -922337203685477508 〜 922337203685477507
 ulong    符号なし整数 64ビット 0 〜 18446744073709551615
 float    単精度浮動小数点型 32ビット -3.402823e38 〜 3.402823e38
 double   倍精度浮動小数点型 64ビット -1.79769313486232e3〜 1.797693134862
 char    単一 Unicode 文字 16ビット テキストで使用される Unicode 記号
 bool    論理ブール型 True または False
 string   文字列型
 decimal  有効桁数29で10進数を表現

一般的に、整数値ならint、数値計算にはdoubleが多く用いられます。


変数の宣言と代入の例
 int a;       // int型変数 a の使用を宣言
 double dz,ft;  // double型変数 dzとft の使用を宣言
 int a = 6;    // int型変数 a の宣言と値の初期化
 int a,b = 2;   // int型 a の宣言と、宣言と同時に初期化したint型の b

 for(int i = 0 ; i < 10 ; i++)  のように、実行文の中で宣言と初期化をすることもできます。


変数の有効範囲

 using System;

 public static void M()   //外側のブロックの開始
 {             
  int x = 10;         //外側のブロック内で有効な変数 x を宣言

    {                  //内側のブロックの開始
      int x = 20;           // 同名の x を再宣言するとここでエラー
      Console.WriteLine(x); 
    }                  //内側のブロックの終了

  Console.WriteLine(x);
 }              //外側のブロックの終了

上層の { } のブロックで宣言した変数は下層のブロックで再宣言するとエラーになります。
上下関係にないブロック間では同名の変数を使うことはできますが保存はされません。
つまり、ブロック内で宣言した変数は、そのブロックから出たらメモリが解放されます。一時的にしか使わない変数はそのブロックで宣言した方が効率的ということになります。


アクセスできる範囲
 public: 同じプログラム内の他のコードや、そのプログラムを参照する別の
    プログラム内の任意のコードからアクセス可能

 private: 同じ class 内または同じ構造体内のコードからのみアクセス可能

 static: そのブロックから外に出ても消えることのない静的なメモリが当てられる

なお、C言語には関数の外で宣言することで広域で使えるグローバル変数がありましたがC#にはこれがありません。替わりに static を使います。


定数
変更することのない定数は、const で定義します。

 public const double sq3 = 1.73205;
 public const string my_name = "YAMADA";



コンソールアプリの使い方

コマンドプロンプトを使うコンソールアプリは、コンソール画面のキャラクタ文字を使い、C#の基本的な機能を確認するためには便利な機能です。 新しいプロジェクトの作成→コンソールアプリ C# で開始することができます。


コンソールへの出力
プログラミングの例として必ず使われる"Hello,World"は

 Console.WriteLine("Hello, World!");

のように 標準入出力を扱うコンソール・クラスで定義された、WriteLineメソッドによって、画面に文字が出力されます。


次の例はWiteLineの応用です。



””に隣接する + は文字の連結を表していますが、(x+y) の部分は算術が適用されています。

なお、Write メソッドも.WriteLineと似た働きをしますが、改行をしないメソッドです。


コンソールからの入力



コンソールのキー入力は ConsoleクラスのReadLineメソッドで改行コードまでの文字列が入力できます。上はキーボードから文字列を2回入力し、それを連結して出力した例です。

文字列ではなく、単独のキー入力は

 Console.ReadKey()


以上二つのメソッド、WriteLine と ReadLine を利用することで、C#は最低限の入出力手段を持ったことになります。最初から後述のフォームアプリを使って本格的なプログラムを作るのではなく、C#の部分的あるいは基本的な機能を確かめるには、このコンソールアプリの方が適しているので活用してみてください。




メソッド
C#における「メソッド(method)」は、C言語の関数に当たり、目的の処理をするために、一連のコードで書かれたブロックを言います。
メソッドは、名前を持ち、引数を受け取ることができ、戻り値を返すこともできます。



上の例の cal というメソッドはint型の引数xと、int型の引数yを元に int 型の戻り値を作り出す働きをします。

開始ポイントでもある Main のメソッドは a と b に初期値をセットしてから cal を呼び出し、戻って来た値をWriteLineでコンソールに表示するという働きをしています。

なお、C言語では Main や cal には static を付けなくてもよかったのですが、C#では要求されます。static はどうやら、{ ブロック } から出入りする際に接続のためのメモリを確保するようです


クラス
メソッドは、実行するためのブロックですが、直接実行するのでは無いブロックがあります。参照型と呼ばれるこのブロックは

 public class 名前
 {
    // 働き
 }

のように書かれ 「クラス(class)」 と呼ばれています。外からも見えるように public を頭に付けています。クラスは実際に実行するブロックではありませんが、規則を作るという重要な働きを持っています。
C言語の構造体は変数の型とその並び方を定義するだけですが、C#における「クラス(class)」は、フィールド、プロパティ、メソッドなどの機能を定義する働きを持っています。以下はその例です。

public class MyClass  // このクラスの名前
{
  // フィールド(外部からはアクセスできない保護された変数)
  private int Myd;  // 変数Mydを宣言

  // プロパティ(クラス外の変数の受け渡しの定義)
  public int MyProperty 
  {
    get { return Myd; }   //getを使って外部にMydの値を返す
    set { Myd = value; }  //setを使って外部の値をMydに受け取り
  }

  // メソッド(クラスで実行される処理)
  public void MyMethod() 
  {
    //
  }
}

「クラス」は、言わば型紙(テンプレート)の働きを持っています。
何を作るための型紙かと言うと、洋服という目的物(オブジェクト)を作るための型紙です。
型紙に合わせて切り取られ、裁縫されるメモリのブロックが「オブジェクト」ということになります。



オブジェクト
クラスという型紙を元に作られるメモリのブロックは「オブジェクト(object)」と呼ばれます。
できた目的のメモリブロックはオブジェクトではなくインスタンス(実際例)と呼ばれる場合もありますが、その使い分けは混乱しているようです。


以下のようなクラスA1があったとします

public class A1 
{
  public string Name { get; set; }  //Nameプロパティ
  public int Age { get; set; }     //Ageプロパティ
}
 注)上の「クラスのプロパティ」で説明したgetとsetの記述法に対し、この簡易的な方法は「自動実装」と呼ばれます。

このクラスA1というテンプレート(型紙)からnew演算子を使って、新しいオブジェクトを生成することができます。

public class Test
{
 static void Main()
 {
  A1 p0 = new A1(); //テンプレートA1()を使って、A1型オブジェクトp0を生成
  p0.Name = "山田"; //p0のNameプロパティに値を代入
  p0.Age = 30;     //p0のAgeプロパティに値を代入
、、、

同じ型のオブジェクトは複数生成することができ、例えば

  A1 p1 = new A1();
  p1.Name = "鈴木";
  p1.Age = 34;

それを以下のようにアクセスすることができます。

 Console.WriteLine(p0.Age);
 Console.WriteLine(p0.Name);
 Console.WriteLine(p1.Age);
 Console.WriteLine(p1.Name);

その実行結果は、






C#の文法U

フォームアプリに行く前の準備です。以下の規則の多くはC言語と共通性があります。

配列
複数のデータの集合を配列と呼びます。1列に並んだ配列が一次元配列、縦と横に並んだ二次元配列、のように呼びます。

 int[] arr = new int[5];    //int型一次元配列 5個 arr[0] 〜 arr[4] の宣言。

new はヒープ領域から新たなメモリ領域を確保する演算子。
ヒープ領域はスタックと異なり出し入れ順に制限のないメモリ領域です。

 int[] arr = new int[] { 1,8,7,0,6 }; //配列変数の宣言と初期化
 string[] weekDays = new string[] { "Sun","Mon","Tue","Wed","Thu","Fri","Sat"};

取り出しは
 Console.WriteLine(weekDays[2]);
のようにすることで
 Tue
が得られます。

同じように二次元配列は

 int[,] array = new int[4, 2];

宣言と同時に初期化する場合は

 int[,] array = new int[,] { {1,2},{3,4},{5,6},{7,8}};


文字の連結
文字列は + で連結させるこができます。

 Console.WriteLine("Hello" + "World");

 文字列の変数も + で連結

代入
代入は 左辺←右辺 へ実行されます。
 a = 1; a = b;

演算
 x + y  //加算
 x - y  //減算
 x * y  //乗算
 x / y  //除算
 x % y;  //剰余

複合代入
 a += b;   // a = a + b; に同
 b -= a;   // 以下同様に
 c *= a;   
 d /= a;
 a %= b;

インクリメント、デクリメント
 i++;     // i=i+1; に同
 ++i;     // i=i+1; に同
 i--;     // i=i-1; に同
 --i;     // i=i-1; に同

シフト
 x << i;   // x をi ビット左シフト(右には0が入る)
 x >> i;   // x をi ビット右シフト(左には0が入る)

論理(ビット演算)

 x & y    // xとyのビットand
 x ^ y    // xとyのビットxor
 x | y     // xとyのビットor
 ~x      // xの補数
 !x      // xのビット反転

論理条件式(if文などの条件判断)
 x && y   // かつ
 x || y    // または
 x == y   // 等しい
 x != y    // 等しくない
 x < y    // 左辺<不変
 x > y    // 左辺>右辺
 x <= y   // 左辺は右辺より小か等しい
 x >= y   // 左辺は右辺より大は等しい
 x == y   // 左辺は右辺に等しい

範囲
 i..j     // a[i..j] で「i番目からj番目の範囲」を参照
       // a[^i] で「後ろからi番目の要素」を参照

数学 Mathクラス:
 Math.Sin(d)   サイン
 Math.Cos(d)   コサイン
 Math.Tan(d)   タンジェント
 Math.Asin(d)  アークサイン
 Math.Acos(d)  アークコサイン
 Math.Atan(d)  アークタンジェント
 Math.Sign(d)   符号
 Math.Abs(d)   絶対値
 Math.Floor(d)  少数点以下切り捨て
 Math.Ceiling(d) 少数点以下切り上げ
 Math.Sqrt(d)   平方根
 Math.Truncate(d) 整数部の値
 Math.PI      π


キャスト: 変数の型を変更する
 int i; double d;
 d = (double)i;  //int型の変数をdouble型の変数へ代入

条件判断 if 文
 if (条件式)   // もし、こうなら
 {
  処理        //こう処理する
 }
 else if (条件)  // そうではなく、もし、こうなら
 {
  処理        //こう処理する
 }
 else       // そうでなかったら
 {
  処理       //こう処理する
 }

ただし、
 if 文だけでも
 複数回の else if 文が使われても
 else 文がなくてもよい。


分岐判断 swich 文:
 swich(変数)   //変数の値が
 {
  case 1:     //1なら
    処理
    break;
  case 2:    //2なら
    処理
    break;
  default:    // どれでもなかったら
    処理
    break;
 }
case数には制限なし


繰り返し for、while、do while文:
 for(初期化 ; 繰り返し条件 ; 処理)  // 例 for (int r = 1; r <= 10; r++) 
 {
   処理
 }

 while(i <= 5 )     // の間
 {
    処理
 }

 do          // 実行する
 {
    処理
 }
 while( I <= 5 )    // の間

while文はループに入った時に条件判断、
do while文は処理後に判断

break   ループをひとつ脱出する。

return  実行中のメソッドから抜け、呼び出し先に指定した値を返す。


C#のName space
Windowsは全てのファイルを階層構造のディレクトリで管理していますが、C#も同様にName space、その下にclassというように分類して管理しています。
Windowsは階層の区切りに\(逆スラッシュ)を使いますが、C#は . (ドット)を使います。先頭に出てくるusing はpathに相当します。




フォームアプリ

さていよいよフォームアプリです。黒画面ではなく、Form画面と呼ばれる画面を使って、画面の中に各種のクラスのツールを配置して、そのツールに必用な機能を持たせることでプログラムを作っていきます。

新しいプロジェクトの作成 → C# Windows フォームアプリ →次へ でプロジェクト名と場所を入れ、作成をクリック で土台となるフォーム画面が出来上がります。

フォームの上に各種ツールを配置するには、表示→ツールボックス を指示します。
「コモンコントロール」を押すと、いろいろなコントロールが出てきます。次回からは下図の赤矢印部分を押すことでツ箱ボックスを広げることができます。





Buttonは押しボタン、CheckBoxはレチェックでTrue/Falseを選択、ComboBoxはダウンリストからの選択、Labelはラベルの表示、TextBoxは文字列の入出力するためのコントロールです。




この中から、目的のコントロールを押したまま、フォーム画面までドラッグして、適当な位置に置きます。
例えば、Button と Label を配置してみます。



押しボタン(button1) をクリックしたら、ラベル(label1) に「こんには!」と表示される簡単なプログラムを作ってみることにします。

Button1をダブルクリックします。すると下のような画面が現れます。これがコード画面です。それまで表示されていた画面はデザイン画面と呼ばれています。

(なお、コード画面は、表示→コード で、デザイン画面は、表示→デザイナー で自由に切り替えることができます。)



Button1をダブルクリックすることで生成されたのが 
 Private void button1_Click(object sender, EventArgs e)
 {

 }

です。Button1をダブルリックしたことで、プログラムのコードが自動的に生成されたということになります。

ちなみに、上からずらっと並んだ using,,,や、namespace,,public,, などのコードもC#が自動的に生成してくれたものです。我々は主に { と } の中を埋めるプログラムを書くことになります。

確認のために、もういちどデザインに切り替えてみると、画面右下にはButton1のプロパティ(属性)が表示されています。(プロパティウィンドウが表示されていない時は、表示→プロパティウィンドウ で表示させます)
ここで、プロパティウィンドウのアクション(下図矢印の電光マーク)をクリックしてみます。
アクションは、キーやマウスの操作、タイマー動作、通信などで発生するイベントを表示させることができます。

Button1のClick欄を見てみると、確かに button1_Click が有効になっています。



フォーム画面のButton1をクリックすることで ボタンをクリックした時のイベントコードが自動生成しましたが、プロパティウィンドウの”Click”欄をクリックすることでも、イベントのコードを自動生成させることができます。

なお、有効にしたイベントを取り消す時は、イベントの項を右クリックしてリセットしてからコードを削除します。

ところでイベントではなく、そのツールが持つ属性を設定することもできます。例えば、デザイン画面でLabel1をシングルクリックし、工具のマーク(下図参照)をクリックすると、ラベルが持つ属性の設定画面が表示されます。

Name では label1 を任意の名称に変更できます。Fontを変更したり、AutoSizeをFalseにしてSizeの変更ができます。また、label1というName自体を変更することも可能です。



プロパティ画面による設定ではなく、コード画面から
 label1.ForeColor = Color.Red;
のように設定することもできます。

話が、横道にそれてしまいましたが、button1_Clickの仕上げをしてみましょう。

 Private void button1_Click(object sender, EventArgs e)
 {
    button1.Text = "こんにちは!";
 }

こうすることで、ボタン1を押すと、「こんにちは!」 が表示されるようになります。
button1のTextに、"こんにちは"という文字列が代入されるプログラムです。




イベント

コードに書かれた順番通りにプログラム呼び出すのではなく、マウスボタンが押されたり、キーボードのキーが押された出来事(イベント)で、呼び出されるプログラムはイベントドリブン・プログラムと呼ばれます。これは、従来で言う割込み(インターラプト)プログラムです。
イベントはプロパティのマークを押して表示される画面で管理されます。以下にその代表的なイベントを見てみます。


キーの押し下げ
フォーム画面からkey入力をするためには、フォーム画面の空白部をクリックしてから、プロパティのイベントの KeyDown と表示されている個所をクリックすると、中身の無いKeyDownイベントコードが生成されます。 { } の中身を例えば次のように書き込みます。

  private void Form1_KeyDown(object sender, KeyEventArgs e)
 {
   Keys s = e.KeyCode;    //Keysイベントで発生するキーコードを変数sに代入
   label1.Text = s.ToString(); //sをストリングに変換してラベル1に表示
 }

イベントが発生するキーコード e.KeyCode をkeysという列挙型で変数 s に代入し、
sをストリング型に変換してlabel1に表示します。
こうすることで、キーインする度にlそのキーコードがlabel1に表示されます。


マウスのクリック位置
フォーム画面上のマウスをクリックした位置を得るには、
labelを配置しておき、プロパティの電光イベントのMouseClick の項をダブルクリックしてコードを生成させ、下記のように追記します。

 private void Form1_MouseClick(object sender, MouseEventArgs e)
 {
   int x = System.Windows.Forms.Cursor.Position.X;
   int y = System.Windows.Forms.Cursor.Position.Y;
   label1.Text = x.ToString() + " " + y.ToString();
 }

フォーム画面の任意の位置でクリックすると、その座標位置がラベルに表示されます。
Cursor.Position.X はカーソルのX位置を変数に取りこみます。


テキストボックスの変化
フォーム画面にツールボックスからTextBox を配置して、イベントマークの TextChanged項をクリックします。
生成されたコードに次の追記をします。

 private void textBox1_TextChanged(object sender, EventArgs e)
 {
  label1.Text = textBox1.Text; //テキストボックスのテキストをラベル1のテキストに代入
 }

TextBox1の文字列に変化が生じると、label1のテキストに同じ変化が反映されます。


タイマーの動作
フォーム画面にツールボックスから Timer を配置します。
Timerはフォーム画面の下側に配置されます(下図)



タイマーのプロパティはレンチマークで設定します(下図参照)。 Intervalは1ms単位の繰り返し時間です。




Timerをクリックするとコードが生成されます。

Timerを起動するのは

  timer1.Enabled = true;

ButtonとTextBoxを使って下のようなプログラムの動作を試してみてください。





●数字と数値変換

数字を数値に変換(1) Parse
 int n = int.Parse("126");        // 数字をintへ変換
 Console.WriteLine(n);

 double d = double.Parse("126.254");  //数字を doubleへ変換
 Console.WriteLine(d);

>> 126
>> 126.254

文字を値に変換(2)  Convert
 int x = Convert.ToInt32("123");      // int型に変換
 long y = Convert.ToInt64("123");      // long型に変換
 float z = Convert.ToSingle("123.456");   // float型に変換
 double d = Convert.ToDouble("123.456"); // double型に変換

値を文字に変換 ToString
 int nb = 20;
 string st;
 Console.WriteLine(nb + 100);    //数値を表示
 st = nb.ToString();           // 数値nbを文字列に変換
 Console.WriteLine(st + "ABC");  // 文字列を表示

>> 120
>> 20ABC


ラムダ式
C言語のマクロのように、ラムダ式は、複雑な記述を簡易な表現に差し替える働きを持っています。プログラムが実行される際、 左辺の記述は => 右辺の記述 に差し替えられて実行されます。



なお、戻り値がない場合は、Funcではなく Action< > を使います。


処理の委託デリゲート



最初の行の

  delegate void Dg(string t);

は、メソッドDg の宣言のようですが、先頭が static ではなく、delegate となっていますから、普通のメソッドではないことがわかります。delegate で宣言されるメソッドは「委託型メソッド」と呼ばれ、宣言された様式(戻り値や引数の作用)を他のメソッドに委託して、処理を実行してもらうことができます。なお、上例の仮引数 t に意味はなく、何でも構いません。

上の例では、メソッドDgの実際の定義は、Mainの中に書かれています。

 Dg Fn = (string Fn)  ストリング型メソッド Fn の定義は、Dg型メソッド Fn によって与えられ、
 それは、=>  「Fnの文字列 + " Yamada" を表示する。」

ということになります。そして、Dg型メソッドであればFnでなく、これを変更した他のメソッド

 Dg Gm = (string Gm => { 、、、 });

もで使うことができます。無論、戻り値や引数の条件さえ合致していれば、どんなメソッドでも構いません。

下は、データ列から平均点や標準偏差を求めるのにデリゲートとラムダ式を使った場合の例です。








代表的なコントロール

先に Button と Label の使用例を取り上げましたが、他の代表的なコモンコントロールの使い方を見てみます。



メッセージボックス
画面にメッセージボックスを表示してOKの確認を求めます。×で否定です。



 MessageBox.Show("メッセージ","タイトル");



チェックボックス
チェックボックスは、質問の確認項目などに使われるツールです。
label と checkBox を配置して checkBoxのプロパティのアクションをクリックして CheckStateChange の項をダブルクリックすることで checkBox1_CheckStateChanged のコードを生成します。



チェックボックスのイベントを検出するのではなく、buttonのクリックでチェックボックスの状態調べる場合は以下のようにします。




このように、コントロールを使って、これをプログラムに反映する方法を大きく区分すると、第一の方法は、そのコントロールで発生できるアクション(電光マーク)を有効にして、生成されるプログラムを利用する方法と、もう一つは、そのコントロールのプロパティ(工具マーク)を調べる if 文または swich 文によって判断する方法です。アクションもプロパティも多岐にわたりますので、それを使うかは迷いますが、実際に試して慣れることが近道かも知れません。


テキストボックス
文字列の読み書き機能を持っているのがtextBoxです

テキストボックスとラベルとボタンを配置して、button1のクリックイベントでテキストボックスの内容をラベルにコピーします。

 private void button1_Click(object sender, EventArgs e)
 {
    label1.Text = textBox1.Text;
 }



なお、label1に凹みを付けて、サイズを変更するには、プロパティのBorderStyle をFixed3Dにして、SutoSizeをFalseにして、横に伸ばしています。

下は、これをボタンではなく、テキストボックスのイベント TextChanged をダブルクリックで有効にして、同じような結果を出した例です。テキストボックス内の文字を変更する度にラベルの中の文字も変わります。



なおテキストボックスはプロパティのMultilineをFalseからTrueに変え、Sizeを大きくすることで多数行の文字を扱うこともできます。


コンボボックス
comboBoxはプルダウンで表示される登録項目から、項目を選択するツールです。
配置したコンボボックスのプロパティ欄の Items の .コレクション(下図矢印)を押すと文字列コレクションエディター画面が表示されるので、アイテムを登録します。



なお、アイテムの登録はプロパティからではなくコードの中で
 comboBox1.Items.Add("東京");
のようにすることもできます。プログラムを実行すると以下のようになります。



comboBox1で選択されたアイテムは

 label1.Text = comboBox1.SelectedItem.ToString(); // 登録順の番号
 label2.Text = comboBox1.Text;             // 登録された文字

のように取得することができます。




複数のコントロールのリスト

個々にコントロールを作るのではなく、複数のコントロールをまとめて作る場合は List<T>クラスを使います。下の例ではbutton を押すと、複数の連続したコントロールがコードで生成されます。




のような、チェックボックスとテキストボックスの列が出来上がります。
できた各コントロールは

 elist[6].Text = "ねずみ";   //elist:[6]に書き出し
 dlist[1].Checked = dlist[0].Checked; //dlist[0]のチェックをdlist[1]へコピー

のようにして操作することができます



プログラムをコピーする手順

C言語などと違い、C#のフォームアプリは、コードをコピーするだけでは正常に動作しません。手順としては

1)必用なツールをフォームに配置する(複数の同種のツールがある場合は配置順に注意します)

2)例えば
 private void button1_Click(object sender, EventArgs e)
 {
のようにイベントを発生させるツールの場合は、そのツール(上例ならbutton1)のデザイン図を選択した状態でプロパティの電光のイベントマークをクリックして、例の場合ならClickの欄をダブルクリックして目的のイベントを呼び出します(これで原型のコードが生成されます)

3)各イベントの中身のコード、および、イベント以外のコードをコピペします。




シリアル通信

PC-PC間だけでなく、 PC-マイクロコントローラー間のシリアル通信も重要です。例えば、機器側の各種センサーやモーターの制御は機器に組込んだ各マイクロコントローラーをC言語で制御し、システム全体はシリアル通信を介してホストのC#で制御するこによって、高いレベルの処理を高速に実行することが可能になります。

SerialPortをフォームに配置して、下のようなコントロールを配置します。

  button1: COM OPEN
  button2: 送信   
  button3:  CLR
  comboBox1:PORT     
  comboBox2:bps 
  textBox1:  送信データ
  textBoox2: 受信データ


button1〜3 はclick でイベント呼び出し、
serialPortはDataReceivedでイベント呼び出しを設定します。



namespace Test
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }

// シリアルポートオープン button1のイベント呼び出し button1_Click
  private void button1_Click(object sender, EventArgs e)
  {
   serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
   serialPort1.Parity = Parity.None;
   serialPort1.DataBits = 8;
   serialPort1.StopBits = StopBits.One;
   serialPort1.Handshake = Handshake.None;
   serialPort1.PortName = comboBox1.Text;
   serialPort1.Open();
  }
// 送信 bitton2のイベント呼び出し button2_Click
  private void button2_Click(object sender, EventArgs e)
  {
   if (serialPort1.IsOpen)
   {
    serialPort1.Write(textBox1.Text + "\n");
   }
  }
// 受信
  delegate void SetTextCallback(string text);
  private void Response(string text)
  {
   if (textBox2.InvokeRequired)
   {
    SetTextCallback d = new SetTextCallback(Response);
    Invoke(d, new object[] { text });
   }
   else
   {
    textBox2.AppendText(text + "\n");
   }
  }
//serialPortの受信イベント呼び出し DataReceived: serialPort1_DataReceived
  private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
  {
   string str = serialPort1.ReadLine();
   Response(str);
  }
//データクリヤ button3のイベント呼び出し button3_Click
  private void button3_Click(object sender, EventArgs e)
  {
   textBox1.Text = "";
   textBox2.Text = "";
  }
 }
}


なお ,PORTのitems には
COM1
COM2
COM3
 〜
COM9

bpsのitemsには
4800
9600
19200
38400
57600
115200
を書いておきます。

使い方
PORTにポート番号を指定し、bpsから速度を選択して、COM OPENを押します。
送信する場合は送信データを書き、送信ボタンを押します。
受信すると受信データが表示されます。
なお、USBコンバーターを使う場合は、コントロールパネル→デバイスマネジャーで、接続ポートを確認してください。

自己ループバック接続で実験する際は
 2 RXD─┐
 3 TXD─┘
 4 DTR─┐
 6 DSR─┘
 7 RTS─┐
 8 CTS─┘
を接続してテストします。




フォームアプリコンソールアプリの共存
見た目に、フォームアプリは黒画面のコンソール画面より上なのですが、大量の情報、あるいは刻々と変化する情報などはむしろ不得意とするところかも知れません。以下はフォームアプリとコンソールアプリを共存させる方法です。

namespace WindowsFormsApp1
{
 public partial class Form1 : Form
 {
  [System.Runtime.InteropServices.DllImport("kernel32.dll")]
  private static extern bool AllocConsole();

  public Form1()
  {
   InitializeComponent();
   AllocConsole();
  }

  private void button1_Click(object sender, EventArgs e) //コンソール表示ボタン
  {
   Console.WriteLine("表示データ"); //必用に応じて変更
  }

  private void button2_Click(object sender, EventArgs e) //コンソール消去ボタン
  {
   Console.Clear();
  }
 }
}



エラー
例えば、配置したbuttonにクリックイベントを設定した状態で、生成されたこのコード行を削除してしまうと、
デザイン画面に以下のようなエラーが表示されてしまいます。デザイン画面の中のイベント設定が残されたままコードの記述が消されてしまったためのエラーのようです。




ここで、画面下部のソリューションの欄に「確認してください」とあるので、これをクリックすると、
今まで表示されなかった下のようなDesigners.cs画面が現れます。




赤の波線で警告されている行(上図の矢印)を削除してみると無事回復することが分かります。Designers画面はこのようにエラーの原因のヒントを与えてくれます。




ファイル開くと保存
ファイルのダイアログボックスを使い、テキストファイルを開き、保存することができます。




準備:richTextBox と button を2個フォームに配置します。


namespace dir
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }
  string fn; //fileパス
//ファイルを開くダイアログ
  private void button1_Click(object sender, EventArgs e)
  {

   OpenFileDialog op = new OpenFileDialog();
   op.Title = "ファイルを開く";
   op.InitialDirectory = @"C:\";
   op.FileName = @"";
   op.Filter = "テキストファイル(*.txt;*.text)|*.txt;*.text|すべてのファイル(*.*)|*.*";
   op.FilterIndex = 1;
   DialogResult result = op.ShowDialog();

   if (result == DialogResult.OK)
   {
    //「開く」ボタン処理
    string fileName = op.FileName; //選択ファイルのパス取得
    fn = fileName; // ファイルのパスの保存
    StreamReader sr = new StreamReader(op.FileName); // テキストファイル読み込み宣言
    string str = sr.ReadToEnd();
    sr.Close();

    richTextBox1.Text = str;
   }
   else if (result == DialogResult.Cancel)
   {
    //×ボタンの処理
   }
  }
 //保存
  private void button2_Click(object sender, EventArgs e)
  {
    string str = richTextBox1.Text; //更新するテキスト
    File.WriteAllText(@fn,str); //ファイル書込み(ファイルパス、テキスト)
    this.Close();
  }
 }
}

新規ファイルを作る
前のプログラムは既存のテキストファイルを開き、この内容を変更して上書きすることはできましたが、新しいファイルを作ることができません。ここでは新しい名前のテキストファイルを作ってみます。

使うのはファイル名を指定する textBox1 と、ダイアログを呼び出す button3 です。
textBox1 にファイル名を入力して新規作成の button3 を押すと、下のようなダイアログが表示されます。




//新規ファイルの作成(ファイル名はTextBox1指示) 
private void button3_Click(object sender, EventArgs e)
{
 DialogResult result = this.folderBrowserDialog1.ShowDialog();
 if (result == DialogResult.OK)
 {

  Console.WriteLine("Folder = " + this.folderBrowserDialog1.SelectedPath);
  // file path + ファイル名
  string path = this.folderBrowserDialog1.SelectedPath + "\\" + textBox1.Text + ".txt";
  FileInfo fileInfo = new FileInfo(path); // FileInfoのインスタンス生成
  FileStream fileStream = fileInfo.Create(); // 空のファイルを作成
  this.Close(); //
 }

}

結果として、指定するフォルダにtextBox1 で指定する名前の空のテキストファイルが生成されます。ファイルの中身は前章の方法で編集することができます。



グラフィック

図形 Draw を使う
円、楕円、直線などの図形を描くことができます。
フォーム画面をクリックして、プロパティのイベント(電光マーク)のPaintをダブルクリックして Form1_Paint() のコードを生成し、下記のように作図コードを書きます。

namespace test
{
 public partial class Form1 : Form
 {
  public Form1()
  {
   InitializeComponent();
  }
  private void Form1_Paint(object sender, PaintEventArgs e)
  {
   //eオブジェクトからGraphicsオブジェクトを取得し、変数gに代入する。
   Graphics g = e.Graphics;  
   //gオブジェクトに含まれる処理法を使って描画する
   g.DrawLine(Pens.Red, 10, 20, 250, 400); // 線描画
   g.Dispose();          //ペン放棄
  }
 }
}

上例では、赤で座標 10,20 から 250,400 まで直線を描いてます。Disposeは開放。
同様に、

 楕円弧  g.DrawArc(Pens.Blue, 100, 200, 50, 50, 0, 360);
     //中心x,y,横径,縦径,始角、終角
 楕円    g.DrawEllipse(Pens.Black, 100, 200, 150, 50);
       // 中心x,y,横径、縦径
 矩形  g.DrawRectangle(Pens.Red, 20, 20, 200, 200);
      //x1,y1,x2,y2
 多角形
   Point[] ps = {new Point(10, 20),
    new Point(250, 150),
    new Point(180, 200),
    new Point(300, 450)};
    g.DrawPolygon(Pens.Black,ps);


ビットマップを使う
例えば、データに基づくグラフの作図が可能です。
前例と同じくForm1_Paint() のコードを生成し

namespace test2
{
 public partial class Form1 : Form
 {
  public Form1()
  {
    InitializeComponent();
    this.BackColor = Color.Black;   //背景色
  }
  private void Form1_Paint(object sender, PaintEventArgs e)
  {
    Graphics g = this.CreateGraphics(); //グラフィックメソッド使用
    Bitmap p = new Bitmap(1, 1); //Bitmap新規作成  @
    p.SetPixel(0, 0, Color.White);    //ピクセル色指定:白

    int scl = 100; // 縦拡大比
    int sft = 200; // 縦yシフト量
    int dv = 200; // 分割数
    for (int i = 0; i < 1000; i++)     //横ビット数
    {
      int xdata = i; //x位置
      double ydata = scl * Math.Cos(i * 2 * Math.PI / dv); //y位置
      g.DrawImageUnscaled(p, xdata,sft + (int)ydata); //点を描画
    }
  }
 }
}

@ Bitmap(Image)はImage使用、Bitmap(String)はファイル指定、Bitmap(1,1)は新規作成





チャート図を使う
一般的にチャート図は棒グラフや円グラフに使われますが、データ表示にも使うことができます。
表示→ツールボックス のデータの中の Chart を使い、適切なサイズにします。

namespace WindowsFormsApp1
{
 public partial class Form1 : Form
 {
   public Form1()
   {
     InitializeComponent();

     chart1.ChartAreas.Clear();
     chart1.Series.Clear();

     ChartArea chartA = new ChartArea();
     chart1.ChartAreas.Add(chartA);

     Series d = new Series();
     d.ChartType = SeriesChartType.Line; //折れ線グラフ

     int dv = 100; //分割数
     for (int i = 0; i < dv; i++)
     {
       int xdata = i;
       double ydata = Math.Sin(i * 2 * Math.PI / dv);  //サイン波
       d.Points.AddXY(xdata, ydata); //データのX,Y値追加
     }
     chart1.Series.Add(d); //描画
  }
 }
}



上はi を振って、折れ線でSin波を描いています。折れ線グラフ以外にも多数のグラフがあります。



C#のライブラリ
以下はC#で使われる一般的なライブラリです。各ライブラリの詳細はネット検索で調べることができます。

System.Cosole
コマンドプロンプトにデータを入力するための関連処理がまとまっているライブラリ

System.Math
数学用のメソッドと定数がまとまっているライブラリ
平方根、立方根、対数関数、三角関数

System.IO.Directory
ディレクトリの操作や処理がまとまっているライブラリ
削除、コピー、移動、新規作成、一覧取得

System.IO.File
ファイルの操作や処理がまとまっているライブラリ
削除、コピー、移動、新規作成、一覧取得

System.IO.StreamReader
ファイルのデータを、文字コードを指定して読み込むための操作がまとまっているライブラリ
 ReadToEnd:すべての文字を読み込む
 ReadToEndAsync:非同期ですべての文字を読み込む
 ReadLine:1行分の文字列を読み込む
 ReadLineAsync:非同期で1行分の文字列を読み込む

System.IO.StreamWriter
ファイルなどに文字コードを指定して書き込むための操作がまとまっているライブラリ

System.Text.Encoding
文字コードを指定するための操作がまとまっているライブラリ

System.Windows.Forms.Form
Windowsのアプリケーションを作るときに使われる操作がまとまっているライブラリ

拡張ライブラリ

NLog
C#で開発されたアプリから、必要なログを出力できるライブラリ
「NuGet パッケージの管理」から検索してダウンロードできる。

Math.NET Numerics
.NETの環境で統計処理が可能なライブラリ

Accord.NET Framework
.NET環境で機械学習ができるライブラリ










アクセスカウンター



inserted by FC2 system