3流プログラマのメモ書き

元開発職→現社内SEの三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(VB.Net)ハッシュテーブル(連想配列)の使い方

フォーム上のコントロールが移動やサイズ変更が可能な状態で、フォーム上の全コントロールのサイズや位置を配列に記憶させておき、リセット処理のときに、初期値(配列に記憶させておいた値)に戻すという処理を書いていました。

最初はWindowsフォーム上のすべてのコントロールを列挙するには?の記事にある方法で、フォーム上の全コントロールを List オブジェクトで順番に代入し、リセット時にまた順番に戻すという処理にしてました。

しかし、サードパーティ製のコントロールが何かのタイミングでどうやら独自にコントロールを増減させているらしく、リセット時のフォーム上の全コントロールの列挙が最初に記憶させた配列と異なってしまうのです。

対応策として、コントロールのハンドルは一意なので、これをキーにして連想配列にできないということで、ハッシュテーブルを使うことにしました。

こんな感じです。ResetControl()を呼べば全コントロールが初期値に戻ります。

''' フォームと全コントロールのSizeハッシュテーブル

Private m_AllCtlSize As New Hashtable(500)

'''

フォームと全コントロールのLocationハッシュテーブル

Private m_AllCtlLocation As New Hashtable(500)

 

 

Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'現在フォームと全コントロールの画面サイズ、ロケーションをメンバ変数にバックアップ

m_AllCtlSize.Clear()

m_AllCtlLocation.Clear()

m_AllCtlSize.Add(Me.Handle, Me.Size)

m_AllCtlLocation.Add(Me.Handle, Me.Location)

Dim all As Control() = GetAllControls(Me)

For Each c As Control In all

'ハッシュテーブルにコントロールのハンドルをキーとして、値を登録

m_AllCtlSize.Add(c.Handle, c.Size)

m_AllCtlLocation.Add(c.Handle, c.Location)

Next

End Sub

Private Sub ResetControl()

'バックアップしておいたサイズ、位置情報メンバ変数から値を復元

Me.Size = CType(m_AllCtlSize(Me.Handle), Size)

Me.Location = CType(m_AllCtlLocation(Me.Handle), Point)

Dim all As Control() = GetAllControls(Me)

For Each c As Control In all

'フォントをリセットする。

c.ResetFont()

Dim objSize As Object = m_AllCtlSize(c.Handle)

If objSize IsNot Nothing Then c.Size = CType(objSize, Size)

Dim objLoc As Object = m_AllCtlLocation(c.Handle)

If objLoc IsNot Nothing Then c.Location = CType(objLoc, Point)

Next

Me.Refresh()

End Sub

 

 

'''

''' 指定されたコントロール上にコントロールをすべて列挙する。

'''

''' 列挙したいコントロール

''' 列挙したいコントロール上のすべてのコントロール

'''

Public Function GetAllControls(ByVal top As Control) As Control()

Dim buf As ArrayList = New ArrayList

For Each c As Control In top.Controls

buf.Add(c)

buf.AddRange(GetAllControls(c))

Next

Return CType(buf.ToArray(GetType(Control)), Control())

End Function

ちなみに、ハッシュテーブルの値を取得するときはインデクサにキーを指定することでOKみたいです。

注意しないといけないのはハッシュテーブルは Object型のため、取り出すときにキャストしてやらないといけません。

詳しくは@IT ハッシュテーブル(連想配列)を使うには?を参考のこと。

追記(2009/1/13):

どうやら .Net2.0 からDictionaryジェネリック・クラスが追加され、より効率的かつ安全にハッシュテーブルが使えるようになったみたいです。

Dictionaryクラスを使うと、インスタンス生成時に型を指定できるので値取得時にいちいちキャストする必要がありません。

ということで、同じ型の値をもたす場合は.Net2.0以降の場合はDictionaryクラスを使うのが賢明ですね。

Dictionaryクラスの詳細は@IT ハッシュテーブル(連想配列)を使うには?(Dictionaryクラス編)[2.0のみ、C#、VB]に載せられています。

ちょうどArrayListが.Net2.0でListに置き換わったようなものみたいですね。