インデクサの活用
テキストボックスを例にインデクサの使い方を説明したが、今ひとつインデクサの便利さに関してピンと来ない人が
いるかも知れません。
そこで今度はビット処理をインデクサで書いてみます。
例えばAPIの中には16ビットの数値のビットをフラグにして値を受け渡す物が有ります。
これらのAPIを使うときは特定のビットを調べてたり、特定のビットのON/OFFを行なったりする
必要が有ります。
上のイメージは番号を指定して左側の「Set」ボタンを押すと、指定したビットが反転します。
各ビット表示はピクチャーボックスが明るいか暗いかで表示します。
又ビットが反転されると全体の数値がテキストボックスに表示されます。
更にテキストボックスに数値を入れて右側の「Set」ボタンを押すと、其のビット表示がされます。
サンプルコード
C#コード
//インデクサを持つクラス
public indexbit Bit = new indexbit();
//ビットの表示用のピクチャーボックスを作成
PictureBox[] pb = new PictureBox[16];
public Form1()
{
InitializeComponent();
textBoxBit.Text = "0";
Bit.value = 0;
//ピクチャーボックスの番号から配列番号を取得し
//そのピクチャーボックスをピクチャーボックスの
//配列に入れている
foreach (Control cl in groupBox1.Controls )
{
//コントロールの名前にpictureBoxが付いていたら
if (cl.Name.StartsWith("pictureBox"))
{
//プログラムを読みやすくするだけ pictureBoxの長さ
int subLength = "pictureBox".Length;
//名前から番号を取得
int no = int.Parse(cl.Name.Substring(subLength, cl.Name.Length
- subLength)) - 1;
//ピクチャーボックスを配列に入れる
if(no<17)
pb[no] = (PictureBox)cl;
}
}
}
VB.NET コード
'インデクサを持つクラス
Public Bit As indexbit = New indexbit()
'ビットの表示用のピクチャーボックスを作成
Public pb(15) As PictureBox
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
textBoxBit.Text = "0"
Bit.value = 0
'ピクチャーボックスの番号から配列番号を取得し
'そのピクチャーボックスをピクチャーボックスの
'配列に入れている
For Each cl As Control In groupBox1.Controls
'コントロールの名前にpictureBoxが付いていたら
If cl.Name.StartsWith("pictureBox") Then
'プログラムを読みやすくするだけpictureBoxの長さ
Dim subLength As Integer = "pictureBox".Length
'名前から番号を取得
Dim no As Integer = Int32.Parse(cl.Name.Substring(subLength, _
cl.Name.Length - subLength)) - 1
'ピクチャーボックスを配列に入れる
If (no < 17) Then
pb(no) = DirectCast(cl, PictureBox)
End If
End If
Next
先ず16ビット幅のUInt16のデータフィールドとインデクサを持つindexbitクラスを宣言します。
次に16個のPictureBoxの配列を宣言します。
各ビットを表示するピクチャーボックスはpictureBox1、pioctureBox2・・・pictureBox15という風にあらかじめ
置いています。
foreach(For Each)の中はFormに貼り付けたpictureBoxを配列に入れるコードです。
この部分はインデクサとは関係ないのですが、実は簡単に見せる為に苦労しています。
コントロールの配列の中から名前の先頭が「pictureBox」となるものを選んで、其の続きの数字を取り出し
配列の添字としているのです。
ビット反転のコード
C#コード
//ビット反転ボタン押下
private void butSet_Click(object sender, EventArgs e)
{
try
{
//ビット番号を取得
int index = int.Parse(textBoxBit.Text);
//ビットの状態を反転させる
Bit[index] = !Bit[index];
//反転結果を数値にして表示
textBoxInt.Text = Bit.value.ToString();
//ピクチャーボックスにビットを表示
setPicBoxColor();
}
catch
{
MessageBox.Show("数値が設定されていません。");
}
}
VB.NET コード
'ビット反転ボタン押下
Private Sub butBitSet_Click( ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles butBitSet.Click
Try
'ビット番号を取得
Dim index As Integer = Int32.Parse(textBoxBit.Text)
'ビットの状態を反転させる
Bit(index) = Not Bit(index)
'反転結果を数値にして表示
textBoxInt.Text = Bit.value.ToString()
'ピクチャーボックスにビットを表示
setPicBoxColor()
Catch
MessageBox.Show("数値が設定されていません。")
End Try
End Sub
ビット反転のコードは簡単です。
Bit[index] = !Bit[index];
Bit(index) = Not Bit(index)
Bitはクラスで有るにもかかわらずまるで配列の様に使われています。
Bit[index](Bit(index))はtrue(True)又はfalse(False)を返すインデクサです。
ピクチャーボックス表示のコード
C#コード
//ピクチャーボックスの表示を変える
private void setPicBoxColor()
{
for (int i = 0; i < 16; i++)
//インデクサが使用されている
if (Bit[i])
pb[i].BackColor = Color.LightGreen;
else
pb[i].BackColor = Color.DarkGreen;
}
VB.NET コード
'ピクチャーボックスの表示を変える
Private Sub setPicBoxColor()
For i As Integer = 0 To 15
'インデクサが使用されている
If Bit(i) Then
pb(i).BackColor = Color.LightGreen
Else
pb(i).BackColor = Color.DarkGreen
End If
Next
End Sub
上のコードはピクチャーボックスの表示を更新しています。
if (Bit[i])
If Bit(i) Then
クラスを引数付きで呼び出しています、ビットが立っているとtrue(True)を立っていないと
false(False)を返します。
これがインデクサです。
数値を表示するコード
C#コード
//数値をセットする
private void butintSet_Click(object sender, EventArgs e)
{
//通常のプロパティにアクセス
Bit.value = UInt16.Parse(textBoxInt.Text);
//ピクチャーボックスの表示を変える
setPicBoxColor();
}
VB.NET コード
'数値をセットする
Private Sub butintSet_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles butintSet.Click
'通常のプロパティにアクセス
Bit.value = UInt16.Parse(textBoxInt.Text)
'ピクチャーボックスの表示を変える
setPicBoxColor()
End Sub
もちろん通常のプロパティも設定できます。
インデクサを持つクラス
C#コード
//インデクサを持つクラス
public class indexbit
{
//フィールドで16ビットの値を保持
private UInt16 ibit ;
//valueプロパティで数値の設定取得が出来る
public UInt16 value
{
get
{
return ibit;
}
set
{
ibit = value;
}
}
//インデクサの記述
public bool this[int index]
{
//bitの取得
get
{
//例外も投げることが出来る
//16ビット以上は例外を投げる
if (index > 15)
throw new System.Exception();
//検査するビットの計算
UInt16 i = (UInt16)Math.Pow(2, index);
//検査ビットが立っていたらtrueを返す
if ((ibit & i) > 0)
return true;
else
return false;
}
//bitの設定
set
{
if (index > 15)
throw new System.Exception();
//設定するビットの計算
UInt16 i = (UInt16)Math.Pow(2, index);
//セットならビットのorを
if (value == true)
ibit |= i;
//リセットはビットを反転させてandを取る
else
ibit &= (UInt16)(~i);
}
}
}
VB.NET コード
'インデクサの記述
Default Property bit(ByVal index As Integer) As Boolean
'bitの取得
Get
'例外も投げることが出来る
'16ビット以上は例外を投げる
If index > 15 Then
Throw New System.Exception()
End If
'検査するビットの計算
Dim i As UInt16 = Convert.ToUInt16(Math.Pow(2, index))
'検査ビットが立っていたらtrueを返す
If (ibit And i) > 0 Then
Return True
Else
Return False
End If
End Get
'bitの設定
Set(ByVal value As Boolean)
If (index > 15) Then
Throw New System.Exception()
End If
'設定するビットの計算
Dim i As UInt16 = Convert.ToUInt16(Math.Pow(2, index))
'セットならビットのorを
If value = True Then
ibit = ibit Or i
'リセットはビットを反転させてandを取る
Else
ibit = ibit And Convert.ToUInt16((Not i))
End If
End Set
End Property
End Class
上がインデクサを持つクラスです。
フィールドでUInt16幅のibitを持っています。
もちろんプロパティでこの値へのアクセスは可能です。
インデクサの部分は
public bool this[int index]
Default Property bit(ByVal index As Integer) As Boolean
はこの部分で、引数に数値をもらって配列の様な振る舞いを行ないます。
引数の最大値は15ですがそれより大きい数字が着たらエラーを投げます。
ビットを取り出すところはビットマスクを使用しています。
読み出すビットだけが立った数値と内部保持の数値をビット演算のANDを行い
0でなかったらビットが立っているものとして、true(True)を0ならfalse(False)を
返すようにしています。
ビットをセットする場合も同じで、セットする場合はセットするビットだけが立った
数値を計算して更にそれをビット反転しビット演算のAndを行なっています。
クラスがまるで配列の様に値を返したり、値をセット出来たりすることが出来るものが、
インデクサなのです。
|