|
UserFormにTextBoxが3個、CommandButtonが1個有るとします
TextBox1:日付入力
TextBox2:車体番号入力
TextBox3:燃料量入力
車体番号、日付共に昇順整列が必須とします
合計は各日付の上に代入されます
尚、燃料の量と合計は、CommandButton1を押した事にに拠り、出力、計算がされます
Option Explicit
'日付の先頭位置の前の列(「車体番号」を基準として「日付」の列Offset値)
Const clngTop As Long = 0
'出力シートの基準位置
Private rngResult As Range
'日付範囲
Private rngDate As Range
'車体番号範囲
Private rngScope As Range
Private Sub CommandButton1_Click()
Dim i As Long
Dim lngColumn As Long
Dim lngRow As Long
Dim vntData As Variant
Dim vntSum As Variant
lngColumn = CLng(TextBox1.Tag)
'日付が選択されていない場合
If TextBox1.Tag = 0 Then
Exit Sub
End If
lngRow = CLng(TextBox2.Tag)
'車体番号が選択されていない場合
If lngRow = 0 Then
Exit Sub
End If
'日付、車体番号の交差するセルに値を書き込み
With rngResult.Offset(, clngTop)
.Offset(lngRow, lngColumn).NumberFormatLocal = "G/標準"
.Offset(lngRow, lngColumn).Value = Val(TextBox3.Text)
End With
With rngResult.Offset(, clngTop)
'選択した日付の列の値を配列に取得
vntData = .Offset(1, lngColumn).Resize(rngScope.Count).Value
For i = 1 To UBound(vntData, 1)
vntSum = vntSum + Val(vntData(i, 1))
Next i
'合計を出力
.Offset(-1, lngColumn).Value = vntSum
End With
TextBox2.Text = ""
TextBox3.Text = ""
TextBox1.SetFocus
End Sub
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
' 日付列の探索と作成
Dim lngDate As Long
Dim lngFound As Long
With TextBox1
If .Value <> "" Then
If IsDate(.Value) Then
lngDate = DateValue(.Value)
'日付を探索
.Tag = GetDateColumn(lngDate, rngDate, _
rngResult.Offset(, clngTop))
Else
Beep
Cancel = True
End If
End If
End With
End Sub
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
' 車体番号行の探索、作成
Dim lngFound As Long
With TextBox2
If .Value <> "" Then
'車体番号を探索
.Tag = GetIDNoRow(.Text, rngScope, rngResult)
End If
End With
End Sub
Private Sub TextBox3_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
With TextBox3
If .Value <> "" Then
'数値のチェック
If Not IsNumeric(.Text) Then
Beep
Cancel = True
End If
End If
End With
End Sub
Private Sub UserForm_Initialize()
'シート最終行
Const clngLastRow As Long = 65536
Dim lngColumn As Long
Dim lngRow As Long
'Sheet2出力表のA1セルを基準とする(列見出し「商品ID」のセル位置)
' Set rngResult = Worksheets("Sheet1").Cells(2, "A")
Set rngResult = Worksheets("Sheet3").Cells(2, "A")
With rngResult
'日付の書かれている列数を取得
lngColumn = .Offset(, 256 - .Column).End(xlToLeft).Column _
- .Offset(, clngTop).Column
'日付列の範囲を取得
If lngColumn > 0 Then
Set rngDate = .Offset(, clngTop + 1).Resize(, lngColumn)
End If
'IDが有る行数を取得
lngRow = .Offset(clngLastRow - .Row).End(xlUp).Row - .Row
'IDが有る範囲を取得
If lngRow > 0 Then
Set rngScope = .Offset(1).Resize(lngRow)
End If
End With
TextBox1.Tag = 0
TextBox2.Tag = 0
End Sub
Private Sub UserForm_Terminate()
Set rngResult = Nothing
Set rngScope = Nothing
Set rngDate = Nothing
End Sub
Private Function GetDateColumn(vntDate As Variant, _
rngScope As Range, _
rngDateTop As Range) As Long
Dim lngFound As Long
Dim lngOver As Long
Dim lngCount As Long
'日付範囲に日付が無いなら
If rngScope Is Nothing Then
lngFound = 0
lngCount = 0
lngOver = 1
Else
'日付の探索
'セル値が数値として入力されている場合
lngFound = DataSearch(CLng(vntDate), rngScope, lngOver)
'セル値が文字列として入力されている場合
' lngFound = DataSearch(vntDate, rngScope, lngOver)
lngCount = rngScope.Columns.Count
End If
'日付が見つかった場合
If lngFound > 0 Then
'位置を返す
GetDateColumn = lngFound
Else
If MsgBox("指定された日付が有りません、" & Format(vntDate, "yyyy/m/d") _
& "の列を作ります", vbInformation + vbOKCancel, "日付不一致") = vbOK Then
With rngDateTop
'日付が最終列の以内の場合
If lngOver <= lngCount Then
'指定位置に列を挿入
.Offset(, lngOver).EntireColumn.Insert
End If
'日付を書き込み
With .Offset(, lngOver)
.NumberFormatLocal = "yyyy/m/d"
.Value = vntDate
End With
'挿入位置を返す
GetDateColumn = lngOver
'日付列の範囲を更新
Set rngScope _
= .Offset(, 1).Resize(, lngCount + 1)
End With
End If
End If
End Function
Private Function GetIDNoRow(vntID As Variant, _
rngScope As Range, _
rngListTop As Range) As Long
Dim lngFound As Long
Dim lngOver As Long
Dim lngCount As Long
'車体番号範囲に車体番号が無いなら
If rngScope Is Nothing Then
lngFound = 0
lngCount = 0
lngOver = 1
Else
'車体番号を探索
lngFound = DataSearch(vntID, rngScope, lngOver)
lngCount = rngScope.Rows.Count
End If
'探索成功(車体番号が有るなら)
If lngFound > 0 Then
'位置を返す
GetIDNoRow = lngFound
Else
If MsgBox("車体番号が有りません、" & vntID & "の行を作ります", _
vbInformation + vbOKCancel, "番号不一致") = vbOK Then
With rngListTop
'挿入位置が行末で無いなら
If lngOver <= lngCount Then
'行を挿入
.Offset(lngOver).EntireRow.Insert
End If
'セルの書式を文字列に設定
.Offset(lngOver).NumberFormatLocal = "@"
'車体番号を書き込み
.Offset(lngOver).Value = vntID
'挿入位置を返す
GetIDNoRow = lngOver
'探索範囲の更新
Set rngScope _
= .Offset(1).Resize(lngCount + 1)
End With
End If
End If
End Function
Private Function DataSearch(vntKey As Variant, _
rngScope As Range, _
Optional lngOver As Long, _
Optional lngMode As Long = 1) As Long
Dim vntFind As Variant
'Matchによる二分探索
vntFind = Application.Match(vntKey, rngScope, lngMode)
lngOver = 1
'もし、エラーで無いなら
If Not IsError(vntFind) Then
'もし、Key値と探索位置の値が等しいなら
If vntKey = rngScope(vntFind).Value Then
'戻り値として、行位置を代入
DataSearch = vntFind
End If
'Key値を超える最小値のある行
lngOver = vntFind + 1
End If
End Function
|
|