-
日付を取り扱う処理は多いもので、請求処理や月締処理などで対象月の月末の日付を計算する場合があります。 また、年度の替わりが年末である場合には年末の日付を計算する必要があります。
月末で問題なのは2月で、うるう年の月末は29日のため、そのことを考える必要があります。
月末の取得は、私がよく使っているのですが指定された年月での月の最初日から翌月の最初日を計算し、 その結果の1日前を計算しています。 また、DateTime の DaysInMonth メソッドを使って該当年月の日数を使うことでも可能です。
それでは、指定された年月日に対応する月末の日付を取得する方法と、年末の日付を取得する方法を以下に示します。月末、年末の日付取得
'月末の取得 Dim dateWK As DateTime dateWK = Now() Console.WriteLine("現在:" & dateWK.ToString("yyyy/MM/dd")) dateWK = New Date(dateWK.Year, dateWK.Month, 1) '指定年月での最初日 dateWK = dateWK.AddMonths(1).AddDays(-1) '次月の1日前を計算 Console.WriteLine("月末の取得1:" & dateWK.ToString("yyyy/MM/dd")) '[DateTime.DaysInMonth]メソッドによる方法 dateWK = Me.DateTimePicker1.Value dateWK = New Date(dateWK.Year, dateWK.Month, DateTime.DaysInMonth(dateWK.Year, dateWK.Month)) Console.WriteLine("月末の取得2:" & dateWK.ToString("yyyy/MM/dd")) '年末の取得(直接12月31日指定) dateWK = Me.DateTimePicker1.Value dateWK = New Date(dateWK.Year, 12, 31) '指定年での最終日(直接12月31日指定) Console.WriteLine("年末の取得の取得1:" & dateWK.ToString("yyyy/MM/dd")) '年末の取得(指定年の翌年の元旦の1日前の計算) dateWK = Me.DateTimePicker1.Value dateWK = New Date(dateWK.Year, 1, 1) '指定年での最初日(元旦) dateWK = dateWK.AddYears(1).AddDays(-1) '次年の1日前を計算 Console.WriteLine("年末の取得の取得1:" & dateWK.ToString("yyyy/MM/dd"))上記の処理を実行すると以下の様な表示が、「出力」ウインドウに表示されます。
現在:2019/02/01 月末の取得1:2019/02/28 月末の取得2:2019/02/28 年末の取得の取得1:2019/12/31 年末の取得の取得1:2019/12/31
ところで、年の加算を行った場合にうるう年を跨いだ場合にどうなるのかが少し気になりましたので、 以下の様なソースで実行してみました。1年後の計算(AddYearsメソッド)
'1年後の計算(AddYearsメソッド) dateWK = New Date(2019, 2, 28) '指定年月:2019/02/28 dateWK = dateWK.AddYears(1) Console.WriteLine("うるう年では無い年の1年後:" & dateWK.ToString("yyyy/MM/dd")) dateWK = New Date(2020, 2, 28) '指定年月:2020/02/28 dateWK = dateWK.AddYears(1) Console.WriteLine("うるう年の場合の年の1年後:" & dateWK.ToString("yyyy/MM/dd")) dateWK = New Date(2020, 2, 29) '指定年月:2020/02/29 dateWK = dateWK.AddYears(1) Console.WriteLine("うるう日からの1年後:" & dateWK.ToString("yyyy/MM/dd")) dateWK = New Date(2019, 3, 1) '指定年月:2019/03/01 dateWK = dateWK.AddYears(1) Console.WriteLine("うるう日を挟む場合の1年後:" & dateWK.ToString("yyyy/MM/dd"))上記の処理を実行すると以下の様な表示が、「出力」ウインドウに表示されます。
2019/02/28 を指定した場合、2019年はうるう年では無いので、1年後の計算は当然 2020/02/28 になります。
2020/02/28 を指定した場合、2020年はうるう年なので 2020/02/29 があるので1日ずれるかと思いきや、1年後の計算は当然 2021/02/28 になります。 これはうるう日を特別に計算しているのか、もしくはただ単に年の数値を1加算しているのかはわかりません。
2020/02/29 を指定した場合でも結果は 1年後の計算は当然 2021/02/28 になります。やはり、うるう日を加味されている様です。
このことは、ある指定日からの1年間を計算する場合に問題になるかもしれません。 1年は365日とするのかそれともうるう日を含めるのかはその時々の仕様によると思います。うるう年では無い年の1年後:2020/02/28 うるう年の場合の年の1年後:2021/02/28 うるう日からの1年後:2021/02/28 うるう日を挟む場合の1年後:2020/03/01
関連する記事
⇒日付型データの使い方 :[Date,DateTime]
⇒日付型データの比較について
⇒文字列から数値型への変換(parse - tryparse)
⇒オブジェクト型から数値型への変換(TryParse)
PR -
以前、以下の記事でテキストボックスの入力される文字を数字のみに限定するコントロールについて記述しましたが、 このコントロールは数値入力には適さないので、今回は少し使える様に入力の見た目は電卓の感じにしてみました。 (数字が1の位から左側へシフトしていきます。)
今回のコントロールの動きは以下の様になります。- 数値の表示は3桁毎にカンマ編集での表示とする。
- カーソル(キャレット)は常にコントロールの右端に存在し動かない。 (矢印キーは動作しない)
- マイナス値は「-」(マイナスキー)を押下することで数値をプラスとマイナスを反転する。
- 「BackSpace」キーで最終文字を削除する。
- クリップボードからのペーストは出来ない様にする。
前回のコントロールでは KeyPress イベントで入力されたキーの制御をしていましたが、 今回はほとんどの処理を KeyDown イベントで行い、 KeyPress イベントでの処理は全て行わない様にします。
今回の処理ではテキストボックスの Text プロパティへの再表示を自分で強制的に行っているため、 KeyPress イベントでの処理をスキップしないと表示がおかしくなるためです。 (文字がダブって表示されたりします)
今回の処理で肝となる KeyDown イベントでは以下のキー処理を行います。- [Enter]:[Ctrl]キーが押下されていない場合、自分の親のコントロールの次のフォーカスへ移動
- [↑][↓][←][→]:矢印キーは処理無し(キーを捨てる)
- [0]~[9]:入力文字列が数値桁数を超えない場合にカンマ編集表示
- [-]:数値のプラス、マイナスの反転処理
- [BackSpace]:最終文字を削除
- その他のキー:処理無し(キーを捨てる)
尚、クリップボードからのペースト処理をしない様に WndProc をオーバーライドしペーストのメッセージを処理しない様にしています。
テキストボックスの電卓の様な入力コントロールクラス
Public Class ClsNumTextBox3 Inherits TextBox '数値桁数("-",","を含まない数値の桁数) Private _NumericUnits As Integer = 9 '数値マイナスフラグ Private _fMinus As Boolean = False 'クリップボード貼付メッセージ Const WM_PASTE As Integer = &H302 '''''' コンストラクタ ''' Public Sub New() MyBase.New() 'IMEを無効にする MyBase.ImeMode = ImeMode.Disable 'MaxLengthは取り敢えず16を設定 Me.MaxLength = 16 'テキストは右寄せ Me.TextAlign = HorizontalAlignment.Right End Sub '''''' WndProc メソッド(クリップボード処理の為) ''' ''' <param name="m">メッセージ</param> Protected Overrides Sub WndProc(ByRef m As Message) Select Case m.Msg Case WM_PASTE 'クリップボードからのコピーは処理しない Return End Select 'メッセージのデフォルト処理を呼出す MyBase.WndProc(m) End Sub '''''' 数値桁数プロパティ ''' Public WriteOnly Property NumericUnits As Integer Set(value As Integer) Me._NumericUnits = value '退避値に設定 End Set End Property '''''' 数値での取得設定プロパティ ''' '''設定値 '''取得値 Public Property Value As Decimal Set(value As Decimal) Dim strNum As String = Math.Abs(value).ToString If strNum.Length > Me._NumericUnits Then MsgBox("ERR:数値桁数 " & Me._NumericUnits & " より大きい値が設定された") Else Me._fMinus = (value < 0) 'マイナスフラグ設定 Me.Text = strNum '取敢えず数値文字列設定 Call Me.RepairNumString("", Me._fMinus) End If End Set Get '文字列からカンマ除去 Dim strNum As String = Me.Text.Replace(",", "") 'Decimal変換値を返す Return ToDec(strNum) End Get End Property '''''' KeyDownイベントの処理 ''' Protected Overrides Sub OnKeyDown(e As KeyEventArgs) MyBase.OnKeyDown(e) Dim strAdd As String = "" Dim fEdit As Boolean = False 'キーコードによる処理 Select Case e.KeyCode Case Keys.Enter If e.Control = False Then '[Ctrl]キーが押下されていない場合、自分の親のコントロールの次のフォーカスへ移動 Me.Parent.SelectNextControl(Me, Not e.Shift, True, True, True) End If Case Keys.Up, Keys.Down, Keys.Left, Keys.Right e.Handled = True Case Keys.D0 To Keys.D9, Keys.NumPad0 To Keys.NumPad9 'キーが [0]~[9] '入力文字列が数値桁数を超えないかチェック Dim strNum As String = Me.Text.Replace("-", "").Replace(",", "") If strNum.Length >= Me._NumericUnits Then e.Handled = True Else Select Case e.KeyCode Case Keys.D0 To Keys.D9 strAdd = "0123456789".Substring(e.KeyCode - Keys.D0, 1) Case Keys.NumPad0 To Keys.NumPad9 strAdd = "0123456789".Substring(e.KeyCode - Keys.NumPad0, 1) End Select fEdit = True '編集表示フラグON e.Handled = True End If Case Keys.Subtract 'キーが [-] Me._fMinus = Not Me._fMinus 'マイナスフラグ反転 fEdit = True '編集表示フラグON Case Keys.Back '最後尾1文字削除 RepairNumString("", Me._fMinus, True) Me.SelectionStart = Me.Text.Length If Me.Text.Length = 0 Then '文字列が空になった場合はマイナスフラグOFF Me._fMinus = False End If e.Handled = True Case Else e.Handled = True End Select If fEdit = True Then '編集表示フラグONの場合、編集表示 Call Me.RepairNumString(strAdd, Me._fMinus) Me.SelectionStart = Me.Text.Length End If End Sub '''''' KeyPressイベントの処理 ''' Protected Overrides Sub OnKeyPress(e As KeyPressEventArgs) MyBase.OnKeyPress(e) '全ての文字をイベントをキャンセル e.Handled = True End Sub '''''' MouseDownイベント処理 ''' Protected Overrides Sub OnMouseDown(e As MouseEventArgs) MyBase.OnMouseDown(e) If Not (Me.SelectionStart = Me.Text.Length) Then 'カーソル位置を最後尾に強制移動 Me.SelectionStart = Me.Text.Length End If End Sub '''''' 文字列の編集表示 ''' ''' <param name="strAdd">最後尾付加文字</param> ''' <param name="fMinus">数値マイナスフラグ</param> ''' <param name="fBackSpace">BACKSPACEフラグ</param> '''文字列を3桁ごとにカンマ編集する Private Sub RepairNumString(ByVal strAdd As String, ByVal fMinus As Boolean, Optional fBackSpace As Boolean = False) '文字を最後に追加する Dim strNum As String = Me.Text.Replace("-", "").Replace(",", "") & strAdd If fBackSpace = True Then 'BackSpaceの指定の場合、最後の文字を削除 If strNum <> "" Then strNum = strNum.Substring(0, strNum.Length - 1) End If End If '3桁ごとのカンマ表示 Dim str As String = Me.ToDec(strNum).ToString("#,###") 'マイナスの場合は"-"付加 If fMinus = True Then If str <> "" Then str = "-" & str End If End If Me.Text = str 'マイナスの場合は赤色設定 If fMinus = True Then If Not Me.ForeColor = Color.Red Then Me.ForeColor = Color.Red End If Else If Not Me.ForeColor = Color.Black Then Me.ForeColor = Color.Black End If End If End Sub '''''' 文字列をDecimal数値変換 ''' ''' <param name="str">文字列</param> '''変換後の数値 Private Function ToDec(ByVal str As String) As Decimal Dim dec As Decimal = 0 Try If str <> "" Then dec = CDec(str) End If Catch ex As Exception End Try Return dec End Function End Class今回のコントロールを2個とボタンをフォームに張り付け、 そのボタンで1個目の数値を2個目の数値コントロールにコピーを行う例を以下に示します。
電卓風数値入力コントロールの例
Public Class frmTextBox3 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Try Dim dec As Decimal = Me.NumTextBox1.Value Me.NumTextBox2.Value = dec Catch ex As Exception End Try End Sub End Class
ボタンを押下することで、上のコントロールの Value プロパティから値を取得し、 その値を下のコントロールの Value プロパティに設定します。 その結果、値がコピーされたことが分かります。 (上の画像は先にマイナス値をコピーした後で、上のコントロールで「-」キーを押下した様子です)関連する記事
⇒テキストボックスの入力を数字のみにする方法
⇒テキストボックス拡張クラスにプロパティを追加する方法
⇒テキストボックスの Leave イベントでのエラー処理でフォーカス強制移動する方法について
-
通常、長い処理を行うプログラムの場合、処理を行っている間にマウスカーソルを待機状態にして、現在処理中であることをユーザに示します。 これを行うにはフォームの Cursor プロパティを Cursors.WaitCursor に設定します。
また、元に戻す時は Cursor プロパティを Cursors.Default に設定します。フォームのマウスカーソルを待機状態する方法
Public Class frmCursor Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'フォームのカーソルを待機状態にする Me.Cursor = Cursors.WaitCursor '10秒待つ(長い処理の代わりにSleep関数を用いる) System.Threading.Thread.Sleep(10000) 'フォームのカーソルを元に戻す Me.Cursor = Cursors.Default End Sub End Class上のプログラムで「長い処理の代わり」と書きましたが、実際にはデータベース処理など時間の掛かる処理を書くわけですが、 その中でエラーの対応の為に Try ... Catch ... End でエラー処理を記述すると思います。
このエラー処理の中で適切にカーソルを元に戻してやらないと、カーソルが待機状態のままになってしまいます。
(これは明らかなバグで、フォーム上の処理はできるが、カーソルが矢印に戻ってないので変な感じになります)
これを回避するためにも、カーソル設定処理は Try ... Catch ... End の外側で行うか、 もしくは以下のソースの様に Try の Finnaly の中で行うと良いと思います。
カーソル処理を Finally ブロックで行う方法
Public Class frmCursor Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Try 'フォームのカーソルを待機状態にする Me.Cursor = Cursors.WaitCursor '10秒待つ(ここでは通常の処理においてエラーが発生するかもしれない) System.Threading.Thread.Sleep(10000) Catch ex As Exception 'ここに例外処理を記述する Finally 'フォームのカーソルを元に戻す Me.Cursor = Cursors.Default End Try End Sub End Class関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について
-
何かのデータをデータベースから読込み TextBox 等に表示し、それぞれ TextBox のいずれかに入力の変更が在ったかどうかを判断する方法を示します。
以下のソースではフォームロードイベント時に仮のデータを初期値として、フォーム上の5個の TextBox に設定しています。 さらに、TextBox の TextChanged イベントで入力が在ったことを処理するため、内部の変更フラグをONしていますが、 そのイベント処理ハンドラを AddHandler により各 TextBox に関連付けています。
仮に【登録】【終了】ボタンを設置し、【登録】ボタン処理では実際の登録はしないのですが、 登録したものとして、変更フラグをOFFとして再初期化しています。 また、【終了】ボタン処理ではフラグを確認して、確認メッセージを表示する様にしています。フォーム上の複数の TextBox の入力変化を確認する処理
Public Class frmInpCheck 'データに変更が在った証拠のフラグ Private fDirty As Boolean = False '【登録】ボタンクリックイベント処理 Private Sub btnWrite_Click(sender As Object, e As EventArgs) Handles btnWrite.Click MsgBox("登録します。") '登録処理を以下に記述... 'フラグをOFF Me.fDirty = False End Sub '【終了】ボタンクリックイベント処理 Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click If Me.fDirty = True Then If MsgBox("データが変更されています。終了してもよろしいですか?", _ MsgBoxStyle.Question + MsgBoxStyle.YesNo, "TEST") = MsgBoxResult.No Then 'いいえの場合は処理を取止め Exit Sub End If End If '自分を閉じる Me.Close() End Sub 'フォームロードイベント時処理 Private Sub frmInpCheck_Load(sender As Object, e As EventArgs) Handles Me.Load 'フォームロード時に画面のTextBoxを初期化する '(一般的にはデータベース等からデータを取得し表示する...) Me.TextBox1.Text = "A1234" Me.TextBox2.Text = "BBBB" Me.TextBox3.Text = "C120000" Me.TextBox4.Text = "DDDDDD" Me.TextBox5.Text = "EEE" 'フォームに属するコントロールがTextBoxの場合、TextChangedイベントの処理を関連付ける For Each ctrl As Control In Me.Controls If TypeOf ctrl Is TextBox Then AddHandler CType(ctrl, TextBox).TextChanged, AddressOf event_TextChanged End If Next End Sub 'TextBoxの内容変化イベント処理 Private Sub event_TextChanged(sender As Object, e As EventArgs) 'データの変更フラグON!! Me.fDirty = True End Sub End Classこれを実行すると以下の様な表示になります。
TextBox のデータ4を変更し、【終了】ボタンをクリックすると以下の表示になります。
尚、 AddHandler でイベントを関連付けているところを、 イベント処理の Subプロシージャ で Handlesキーワードの後ろに5個分の TextBox を以下の様に記述しても同じことができます。
TextChangedイベント処理について
'通常の方法でのTextBoxの内容変化イベント処理 '(Handles の後ろに必要なコントロールを全て記述することで AddHandler と同様になる) Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles _ TextBox1.TextChanged, TextBox2.TextChanged, TextBox3.TextChanged, _ TextBox4.TextChanged, TextBox5.TextChanged 'データの変更フラグON!! Me.fDirty = True End Sub
この方法は見た目にも余りかっこよくないですし、仮に TextBox が増えたりした場合には変更が面倒なのでお勧めしません。 ただ、こんな方法もあるということを示しました。
今回は TextBox のみを例にしましたが、実際は日付入力や CheckBox などもありますので それぞれのコントロールで値が変更されたイベントのタイミングでフラグをONしてやればよいと思います。
(CheckBox の場合は、 CheckedChangedイベント)関連する記事
⇒フォームクラス生成時に設定値を同時に渡す方法
⇒フォーム上の複数のコントロール(TextBox)の入力変化を確認する方法について
⇒フォームのマウスカーソルを待機状態する方法について
⇒フォームクラスの継承の方法について
-
プログラム上でKEYを持つリスト構造を使う場合に利用するのがコレクションクラスです。 良く使うコレクションクラスには以下の様に3種類のものがあります。
クラス名 KEY操作 Index操作 備考 ArrayList × ○ Indexでの操作しかできないコレクション基本クラス
取り扱うデータ型は Object 型Hashtable ○ × 連想配列的なKEYを持つコレクションクラス
KEY及び、取り扱うデータ型は Object 型SortedList ○ ○ ArrayList と Hashtable の性質を併せ持ったコレクションクラス
Indexは指定されたKEY順にソートされた結果が割り振られます
単なる Object 型の配列として使う場合は ArrayList でもいいのですが、 データ処理をする場合には何がしかのキーがあって、それに紐づくデータがあるものです。 そのためキーが扱える Hashtable SortedList を利用します。
これらのコレクションクラスはデータとして扱えるのは、 Object 型なので結果 データ型としてOKなものは何でもになります。 いろんなサイトで、データとして文字列が扱われているものはあるのですが、今回は少しだけ複雑にするため、 ユーザクラスをデータにもつものを示したいと思います。
以下のソースを見て下さい。ユーザクラスとしてTest を宣言しています。
このクラスを SortedList のデータとして追加等を行います。
このプログラムはモジュールファイルに Sub Main を作成しその中に処理を記述しています。 これをコンパイルする場合はプロジェクト・プロパティでスタートアップオブジェクトとして MdlMainSortList を指定して下さい。
クラスデータをリストする SortedList を宣言した後、 テストクラスのデータを4件生成しながら SortedList に追加を行います。 キーとしては4件とも同一の書式で文字列として処理しています。
その後確認の為に SortedList.Values から順次データを取得して、内容を表示しています。 (この時取得されるのはクラス型なので、いわゆる参照型です。)
さて、内部のデータの変更を行う為にキーを指定しデータを取得します。 ここでクラスのパブリック変数に直接値を入れることで内部データの変更が行われます。 (クラスの参照を SortedList はデータとして持っているだけで、その参照により実体データにアクセスします)
再度 SortedList の中身を全て確認するのですが、今回はIndexを使ってデータを取得しています。SortedListでのクラスデータの使い方
Module MdlMainSortList 'テストクラス Private Class Test Public Key As String 'KEYとなる文字列 Public Name As String '名称の文字列 Public Data As Integer 'あるデータとしてのInteger型データ Public Flag As Boolean 'フラグ 'コンストラクタ Sub New(ByVal aKey As String, ByVal aName As String, ByVal aData As String) Me.Key = aKey Me.Name = aName Me.Data = aData Me.Flag = False End Sub End Class <STAThread()> _ Sub Main() 'クラスデータをリストするSortedList Dim SortTest As New SortedList Dim clsTest As Test '敢えてKEYの順番通りでは無い様に SortedList に追加 clsTest = New Test("KEY004", "NAME004", 444) SortTest.Add("KEY004", clsTest) clsTest = New Test("KEY001", "NAME001", 100) SortTest.Add("KEY001", clsTest) clsTest = New Test("KEY003", "NAME003", 333) SortTest.Add("KEY003", clsTest) clsTest = New Test("KEY002", "NAME002", 222) SortTest.Add("KEY002", clsTest) Debug.Print("**************************") 'SortedList のKEY順番に取り出す For Each clsTest In SortTest.Values '内容を確認 Debug.Print(clsTest.Key & " : " & clsTest.Name & " : " & clsTest.Data.ToString) Next '1個のデータをKEYで内容を取り出し、そのクラスの中身を変更する clsTest = SortTest.Item("KEY002") '取り出した clsTest はクラスデータの参照なので、以下の処理でクラスの中身を変更 clsTest.Name = "NAMEaaa" clsTest.Data = 555 clsTest.Flag = True Debug.Print("**************************") 'KEY順番に指標で取り出す For i As Integer = 0 To SortTest.Count - 1 'クラスの参照を取り出す clsTest = CType(SortTest.GetByIndex(i), Test) '内容を確認 Debug.Print(clsTest.Key & " : " & clsTest.Name & " : " & clsTest.Data.ToString & " : " & clsTest.Flag.ToString) Next End Sub End Module結果の出力を開発環境の「出力」ウインドウに表示していますが、以下の様になります。
("KEY002"のデータが変更されていることが分かります。)
次に、 SortedList を Hashtable に変えてみた例を示します。 特に SortedList の場合と変わりはありませんが、 Indexを使ってのデータへのアクセスは出来ないので、キーを使うことになります。
ここでキーについての注意ですが、私はキーとしては文字列で設定する様にしています。 例えば扱うデータのキーとして「得意先コード(数値で5桁)」「商品コード(数値で8桁)」の2個があった場合は、 それぞれのコードを先頭ゼロ付きで桁数固定で文字列変換し連結したものをキーとしています。
もし「商品コード」等が文字列(漢字を含まないとする)の場合でしたら、 先頭に空白を補って桁数を揃えて連結します。そうしないと比較がうまくいかないからです。Hashtableでのクラスデータの使い方
Module MdlMainHashList 'テストクラス Private Class Test Public Key As String 'KEYとなる文字列 Public Name As String '名称の文字列 Public Data As Integer 'あるデータとしてのInteger型データ Public Flag As Boolean 'フラグ 'コンストラクタ Sub New(ByVal aKey As String, ByVal aName As String, ByVal aData As String) Me.Key = aKey Me.Name = aName Me.Data = aData Me.Flag = False End Sub End Class <STAThread()> _ Sub Main() 'クラスデータをリストするHashtable Dim HashTest As New Hashtable Dim clsTest As Test '敢えてKEYの順番通りでは無い様に SortedList に追加 clsTest = New Test("KEY004", "NAME004", 444) HashTest.Add("KEY004", clsTest) clsTest = New Test("KEY001", "NAME001", 100) HashTest.Add("KEY001", clsTest) clsTest = New Test("KEY003", "NAME003", 333) HashTest.Add("KEY003", clsTest) clsTest = New Test("KEY002", "NAME002", 222) HashTest.Add("KEY002", clsTest) 'KEY順番に指標で取り出す Debug.Print("**************************") For Each clsTest In HashTest.Values '内容を確認 Debug.Print(clsTest.Key & " : " & clsTest.Name & " : " & clsTest.Data.ToString) Next '1このデータをKEYで内容を取り出し、そのクラスの中身を変更する clsTest = HashTest.Item("KEY002") '取り出した clsTest はクラスデータの参照なので、以下の処理でクラスの中身を変更 clsTest.Name = "NAMEaaa" clsTest.Data = 555 clsTest.Flag = True 'KEY順番に指標で取り出す Debug.Print("**************************") For Each clsTest In HashTest.Values '内容を確認 Debug.Print(clsTest.Key & " : " & clsTest.Name & " : " & clsTest.Data.ToString) Next End Sub End Module